From 96a292d40e7f6fe505c4a0f686d35132ffac8208 Mon Sep 17 00:00:00 2001 From: Ailin Nemui Date: Thu, 9 Jan 2014 15:20:29 +0100 Subject: Finish 256 colour support for Irssi 256 colour patch is cleaned up and the remaining cases are made work, this includes especially Theme support, which was not implemented before. Changes not related to colours were reverted again, making a review of the two patches against master easier to follow. As a byproduct of the Hex-colour code parser, the 24bit colours are also implemented. Actually using them in the terminal is guarded by a compile time switch (as well as a run time switch), as it breaks the existing colour protocol and requires additional storage. To make a seamless usage, down-conversion is provided for 8 and 16 colours. Diverging from Tom's approach, the colour protocol is reverted back to the original one. Unfortunately, the changes required in the Theme engine will break the API. For more details, please refer to the patch documentation at either http://irssi-docs.wikispaces.com/Notes-256-Colour or https://github.com/shabble/irssi-docs/wiki/Notes-256-Colour --- AUTHORS | 2 + configure.ac | 16 ++ docs/formats.txt | 2 + irssi.conf | 1 + src/common.h | 4 - src/core/session.c | 2 +- src/fe-common/core/fe-common-core.c | 52 +---- src/fe-common/core/fe-exec.c | 4 +- src/fe-common/core/fe-windows.c | 57 +++++ src/fe-common/core/fe-windows.h | 2 + src/fe-common/core/formats.c | 412 +++++++++++++++++++++++++++--------- src/fe-common/core/formats.h | 19 +- src/fe-common/core/printtext.c | 11 +- src/fe-common/core/themes.c | 121 ++++++++--- src/fe-common/core/themes.h | 8 +- src/fe-text/gui-printtext.c | 88 ++++---- src/fe-text/statusbar.c | 4 +- src/fe-text/term-curses.c | 21 +- src/fe-text/term-terminfo.c | 135 ++++++------ src/fe-text/term.c | 34 ++- src/fe-text/term.h | 26 +-- src/fe-text/terminfo-core.c | 31 ++- src/fe-text/terminfo-core.h | 2 - src/fe-text/textbuffer-view.c | 147 ++++++++----- src/fe-text/textbuffer-view.h | 3 + src/fe-text/textbuffer.c | 153 +++++++------ src/fe-text/textbuffer.h | 33 +-- src/perl/ui/Themes.xs | 7 +- 28 files changed, 904 insertions(+), 493 deletions(-) diff --git a/AUTHORS b/AUTHORS index 50f24ac4..aa4624c6 100644 --- a/AUTHORS +++ b/AUTHORS @@ -78,3 +78,5 @@ Other patches (grep for "patch" in ChangeLog) by: Ismael Luceno Thomas Karpiniec Svante Kvarnström + Ailin Nemui (Nei) + Tom Feist (shabble) diff --git a/configure.ac b/configure.ac index d409be36..04c50b4b 100644 --- a/configure.ac +++ b/configure.ac @@ -166,6 +166,15 @@ AC_ARG_ENABLE(dane, fi, want_dane=no) +AC_ARG_ENABLE(true-color, +[ --enable-true-color Build with true color support in terminal], + if test x$enableval = xno ; then + want_truecolor=no + else + want_truecolor=yes + fi, + want_truecolor=no) + dnl ** dnl ** SSL Library checks (OpenSSL) dnl ** @@ -643,6 +652,12 @@ if test "x$want_dane" = "xyes"; then fi fi +if test "x$want_truecolor" = "xyes" -a "x$want_termcap" != "xyes" -a "x$want_terminfo" = "xyes" ; then + AC_DEFINE([TERM_TRUECOLOR], [], [true color support in terminal]) +else + want_truecolor=no +fi + AC_CONFIG_FILES([ Makefile src/Makefile @@ -761,6 +776,7 @@ echo "Building with SSL support ........ : $have_openssl" echo "Building with 64bit DCC support .. : $offt_64bit" echo "Building with garbage collector .. : $have_gc" echo "Building with DANE support ....... : $have_dane" +echo "Building with true color support.. : $want_truecolor" echo echo "If there are any problems, read the INSTALL file." diff --git a/docs/formats.txt b/docs/formats.txt index 0ffef08f..2a507a04 100644 --- a/docs/formats.txt +++ b/docs/formats.txt @@ -27,6 +27,8 @@ %| Marks the indentation position %# Monospace font on/off (useful with lists and GUI) %% A single % + %XAB %xAB Color from extended plane (A=1-7, B=0-Z) + %ZAABBCC %zAABBCC HTML color (in hex notation) In .theme files %n works a bit differently. See default.theme for more information. diff --git a/irssi.conf b/irssi.conf index a92cdaff..c9817eae 100644 --- a/irssi.conf +++ b/irssi.conf @@ -130,6 +130,7 @@ aliases = { CHAT = "dcc chat"; RUN = "SCRIPT LOAD"; CALC = "exec - if command -v bc >/dev/null 2>&1\\; then printf '%s=' '$*'\\; echo '$*' | bc -l\\; else echo bc was not found\\; fi"; + CUBES = "/script exec Irssi::active_win->print(\"%_bases\", MSGLEVEL_CLIENTCRAP) \\; Irssi::active_win->print( do { join '', map { \"%x0\\${_}0\\$_\" } '0'..'9','A'..'F' }, MSGLEVEL_NEVER | MSGLEVEL_CLIENTCRAP) \\; Irssi::active_win->print(\"%_cubes\", MSGLEVEL_CLIENTCRAP) \\; Irssi::active_win->print( do { my \\$y = \\$_*6 \\; join '', map { my \\$x = \\$_ \\; map { \"%x\\$x\\$_\\$x\\$_\" } @{['0'..'9','A'..'Z']}[\\$y .. \\$y+5] } 1..6 }, MSGLEVEL_NEVER | MSGLEVEL_CLIENTCRAP) for 0..5 \\; Irssi::active_win->print(\"%_grays\", MSGLEVEL_CLIENTCRAP) \\; Irssi::active_win->print( do { join '', map { \"%x7\\${_}7\\$_\" } 'A'..'X' }, MSGLEVEL_NEVER | MSGLEVEL_CLIENTCRAP) \\; Irssi::active_win->print(\"%_mIRC extended colours\", MSGLEVEL_CLIENTCRAP) \\; my \\$x \\; \\$x .= sprintf \"\00399,%02d%02d\",\\$_,\\$_ for 0..15 \\; Irssi::active_win->print(\\$x, MSGLEVEL_NEVER | MSGLEVEL_CLIENTCRAP) \\; for my \\$z (0..6) { my \\$x \\; \\$x .= sprintf \"\00399,%02d%02d\",\\$_,\\$_ for 16+(\\$z*12)..16+(\\$z*12)+11 \\; Irssi::active_win->print(\\$x, MSGLEVEL_NEVER | MSGLEVEL_CLIENTCRAP) }"; SBAR = "STATUSBAR"; INVITELIST = "mode $C +I"; Q = "QUERY"; diff --git a/src/common.h b/src/common.h index 37fee02f..bb246962 100644 --- a/src/common.h +++ b/src/common.h @@ -39,10 +39,6 @@ #endif #include - -/* TODO: wrap this in some autoconf macro bullocks? */ -#include - #ifdef HAVE_GMODULE # include #endif diff --git a/src/core/session.c b/src/core/session.c index 6fdaa186..b3002632 100644 --- a/src/core/session.c +++ b/src/core/session.c @@ -51,7 +51,7 @@ void session_upgrade(void) return; execv(session_args[0], session_args); - g_message( "exec failed: %s: %s\n", + fprintf(stderr, "exec failed: %s: %s\n", session_args[0], g_strerror(errno)); } diff --git a/src/fe-common/core/fe-common-core.c b/src/fe-common/core/fe-common-core.c index 4c5fbb84..dce6890e 100644 --- a/src/fe-common/core/fe-common-core.c +++ b/src/fe-common/core/fe-common-core.c @@ -55,9 +55,6 @@ static int no_autoconnect; static char *cmdline_nick; static char *cmdline_hostname; -static char *irssi_logfile = NULL; -static FILE * logfile_FILE = NULL; - void fe_core_log_init(void); void fe_core_log_deinit(void); @@ -123,26 +120,13 @@ static void sig_channel_destroyed(CHANNEL_REC *channel) void fe_common_core_register_options(void) { - static GOptionEntry options[] - = { - { "connect", 'c', 0, G_OPTION_ARG_STRING, &autocon_server, - "Automatically connect to server/network", "SERVER" - }, - { "password", 'w', 0, G_OPTION_ARG_STRING, &autocon_password, - "Autoconnect password", "PASSWORD" - }, - { "port", 'p', 0, G_OPTION_ARG_INT, &autocon_port, - "Autoconnect port", "PORT" }, - { "noconnect", '!', 0, G_OPTION_ARG_NONE, &no_autoconnect, - "Disable autoconnecting", NULL }, + static GOptionEntry options[] = { + { "connect", 'c', 0, G_OPTION_ARG_STRING, &autocon_server, "Automatically connect to server/network", "SERVER" }, + { "password", 'w', 0, G_OPTION_ARG_STRING, &autocon_password, "Autoconnect password", "PASSWORD" }, + { "port", 'p', 0, G_OPTION_ARG_INT, &autocon_port, "Autoconnect port", "PORT" }, + { "noconnect", '!', 0, G_OPTION_ARG_NONE, &no_autoconnect, "Disable autoconnecting", NULL }, { "nick", 'n', 0, G_OPTION_ARG_STRING, &cmdline_nick, "Specify nick to use", NULL }, - { "hostname", 'h', 0, G_OPTION_ARG_STRING, &cmdline_hostname, - "Specify host name to use", NULL }, - { "logfile", 0, 0, G_OPTION_ARG_FILENAME, &irssi_logfile, - "Logfile to write debugging data which would otherwise be printed " \ - "to STDERR or as Irssi internal messages", "PATH" - }, - + { "hostname", 'h', 0, G_OPTION_ARG_STRING, &cmdline_hostname, "Specify host name to use", NULL }, { NULL } }; @@ -159,9 +143,6 @@ void fe_common_core_init(void) { const char *str; - logfile_FILE = g_fopen(irssi_logfile, "a"); - if (logfile_FILE == NULL) irssi_logfile = NULL; - settings_add_bool("lookandfeel", "timestamps", TRUE); settings_add_level("lookandfeel", "timestamp_level", "ALL"); settings_add_time("lookandfeel", "timestamp_timeout", "0"); @@ -262,10 +243,6 @@ void fe_common_core_deinit(void) signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected); signal_remove("channel created", (SIGNAL_FUNC) sig_channel_created); signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed); - - if (irssi_logfile && logfile_FILE) { - fclose(logfile_FILE); - } } void glog_func(const char *log_domain, GLogLevelFlags log_level, @@ -280,24 +257,17 @@ void glog_func(const char *log_domain, GLogLevelFlags log_level, case G_LOG_LEVEL_CRITICAL: reason = "critical"; break; - case G_LOG_LEVEL_MESSAGE: - reason = "msg"; - break; default: reason = "error"; break; } - if (irssi_logfile != NULL && logfile_FILE != NULL) { - fprintf(logfile_FILE, "GLib: %s: %s", reason, message); - fflush(logfile_FILE); - } else { // if (windows == NULL) - fprintf(stderr, "GLib %s: %s", reason, message); + if (windows == NULL) + fprintf(stderr, "GLib %s: %s\n", reason, message); + else { + printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, + TXT_GLIB_ERROR, reason, message); } - /* else { */ - /* printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, */ - /* TXT_GLIB_ERROR, reason, message); */ - /* } */ } #define MSGS_WINDOW_LEVELS (MSGLEVEL_MSGS|MSGLEVEL_ACTIONS|MSGLEVEL_DCCMSGS) diff --git a/src/fe-common/core/fe-exec.c b/src/fe-common/core/fe-exec.c index 98245a59..9249f432 100644 --- a/src/fe-common/core/fe-exec.c +++ b/src/fe-common/core/fe-exec.c @@ -348,12 +348,12 @@ static void process_exec(PROCESS_REC *rec, const char *cmd) if (rec->shell) { execvp(shell_args[0], (char **) shell_args); - g_message( "Exec: /bin/sh: %s\n", g_strerror(errno)); + fprintf(stderr, "Exec: /bin/sh: %s\n", g_strerror(errno)); } else { args = g_strsplit(cmd, " ", -1); execvp(args[0], args); - g_message( "Exec: %s: %s\n", args[0], g_strerror(errno)); + fprintf(stderr, "Exec: %s: %s\n", args[0], g_strerror(errno)); } _exit(-1); diff --git a/src/fe-common/core/fe-windows.c b/src/fe-common/core/fe-windows.c index aa5ea397..bf9d7154 100644 --- a/src/fe-common/core/fe-windows.c +++ b/src/fe-common/core/fe-windows.c @@ -588,6 +588,63 @@ static void window_print_daychange(WINDOW_REC *window, struct tm *tm) printtext_string_window(window, MSGLEVEL_NEVER, str); } +short color_24bit_256 (const unsigned char rgb[]) +{ + static const int cstep_size = 40; + static const int cstep_start = 0x5f; + + static const int gstep_size = 10; + static const int gstep_start = 0x08; + + int dist[3] = {0}; + int r[3], gr[3]; + + size_t i; + + for (i = 0; i < 3; ++i) { + const int n = rgb[i]; + gr[i] = -1; + if (n < cstep_start /2) { + r[i] = 0; + dist[i] = -cstep_size/2; + } + else { + r[i] = 1+((n-cstep_start + cstep_size /2)/cstep_size); + dist[i] = ((n-cstep_start + cstep_size /2)%cstep_size - cstep_size/2); + } + if (n < gstep_start /2) { + gr[i] = -1; + } + else { + gr[i] = ((n-gstep_start + gstep_size /2)/gstep_size); + } + } + if (r[0] == r[1] && r[1] == r[2] && + 4*abs(dist[0]) < gstep_size && 4*abs(dist[1]) < gstep_size && 4*abs(dist[2]) < gstep_size) { + /* skip gray detection */ + } + else { + const int j = r[1] == r[2] ? 0 : 1; + if ((r[0] == r[1] || r[j] == r[2]) && abs(r[j]-r[(j+1)%3]) <= 1) { + const int k = gr[1] == gr[2] ? 0 : 1; + if ((gr[0] == gr[1] || gr[k] == gr[2]) && abs(gr[k]-gr[(k+1)%3]) <= 2) { + if (gr[k] < 0) { + r[0] = r[1] = r[2] = 0; + } + else if (gr[k] > 23) { + r[0] = r[1] = r[2] = 5; + } + else { + r[0] = 6; + r[1] = (gr[k] / 6); + r[2] = gr[k]%6; + } + } + } + } + return 16 + r[0]*36 + r[1] * 6 + r[2]; +} + static void sig_print_text(void) { GSList *tmp; diff --git a/src/fe-common/core/fe-windows.h b/src/fe-common/core/fe-windows.h index 58c316ef..613f15f8 100644 --- a/src/fe-common/core/fe-windows.h +++ b/src/fe-common/core/fe-windows.h @@ -97,4 +97,6 @@ void window_bind_remove_unsticky(WINDOW_REC *window); void windows_init(void); void windows_deinit(void); +short color_24bit_256(const unsigned char rgb[]); + #endif diff --git a/src/fe-common/core/formats.c b/src/fe-common/core/formats.c index 2b331fa8..770caaa1 100644 --- a/src/fe-common/core/formats.c +++ b/src/fe-common/core/formats.c @@ -66,8 +66,6 @@ static void format_expand_code(const char **format, GString *out, int *flags) { int set; - g_message( "format_expand_codes()\n"); - if (flags == NULL) { /* flags are being ignored - skip the code */ while (**format != ']') @@ -103,22 +101,89 @@ static void format_expand_code(const char **format, GString *out, int *flags) } } +void format_ext_color(GString *out, int bg, int color) +{ + g_string_append_c(out, 4); + if (bg && color < 0x10) + g_string_append_c(out, FORMAT_COLOR_NOCHANGE); + if (color < 0x10) + g_string_append_c(out, color+'0'); + else { + if (color < 0x60) + g_string_append_c(out, bg ? FORMAT_COLOR_EXT1_BG + : FORMAT_COLOR_EXT1); + else if (color < 0xb0) + g_string_append_c(out, bg ? FORMAT_COLOR_EXT2_BG + : FORMAT_COLOR_EXT2); + else + g_string_append_c(out, bg ? FORMAT_COLOR_EXT3_BG + : FORMAT_COLOR_EXT3); + g_string_append_c(out, FORMAT_COLOR_NOCHANGE + ((color-0x10)%0x50)); + } + if (!bg && color < 0x10) + g_string_append_c(out, FORMAT_COLOR_NOCHANGE); +} + +#ifdef TERM_TRUECOLOR +void unformat_24bit_color(char **ptr, int off, int *fgcolor, int *bgcolor, int *flags) +{ + unsigned int color; + unsigned char rgbx[4]; + unsigned int i; + for (i = 0; i < 4; ++i) { + rgbx[i] = (*ptr)[i + off]; + } + rgbx[3] -= 0x20; + *ptr += 4; + for (i = 0; i < 3; ++i) { + if (rgbx[3] & (0x10 << i)) + rgbx[i] -= 0x20; + } + color = rgbx[0] << 16 | rgbx[1] << 8 | rgbx[2]; + if (rgbx[3] & 0x1) { + *bgcolor = color; + *flags |= GUI_PRINT_FLAG_COLOR_24_BG; + } + else { + *fgcolor = color; + *flags |= GUI_PRINT_FLAG_COLOR_24_FG; + } +} +#endif + +void format_24bit_color(GString *out, int bg, unsigned int color) +{ + unsigned char rgb[] = { color >> 16, color >> 8, color }; +#ifdef TERM_TRUECOLOR + unsigned char x = bg ? 0x1 : 0; + unsigned int i; + g_string_append_c(out, 4); + g_string_append_c(out, FORMAT_COLOR_24); + for (i = 0; i < 3; ++i) { + if (rgb[i] > 0x20) + g_string_append_c(out, rgb[i]); + else { + g_string_append_c(out, 0x20 + rgb[i]); + x |= 0x10 << i; + } + } + g_string_append_c(out, 0x20 + x); +#else /* !TERM_TRUECOLOR */ + format_ext_color(out, bg, color_24bit_256(rgb)); +#endif /* TERM_TRUECOLOR */ +} + int format_expand_styles(GString *out, const char **format, int *flags) { - int retval = 1; + int retval = 1; char *p, fmt; /* storage for numerical parsing code for %x/X formats. */ - unsigned char accum = 0; - int tmp, i; - - //memset(num_buf, 0, 4); + int tmp; + unsigned int tmp2; fmt = **format; - - g_message( "format_expand_styles: fmtchar: %c\n", fmt); - switch (fmt) { case '{': case '}': @@ -134,7 +199,6 @@ int format_expand_styles(GString *out, const char **format, int *flags) case '9': case '_': /* bold on/off */ - g_message( "setting bold flag: %04x\n", FORMAT_STYLE_BOLD); g_string_append_c(out, 4); g_string_append_c(out, FORMAT_STYLE_BOLD); break; @@ -177,45 +241,61 @@ int format_expand_styles(GString *out, const char **format, int *flags) format_expand_code(format, out, flags); break; case 'x': - tmp = 0; - accum = 0; - for (i = 1; i < 3; i++) { - char fmtchar = (*format)[i]; - g_message("Format X: code: %c\n", fmtchar); - tmp = g_ascii_xdigit_value(fmtchar); - if (tmp != -1) { - accum = accum * 16 + tmp; - } - } - retval += i - 1; - - g_string_append_c(out, 4); - g_string_append_c(out, FORMAT_COLOR_NOCHANGE); - g_string_append_c(out, accum); - - g_message("Format x: code: %d (0x%02x)\n", accum, accum); - - break; case 'X': - tmp = 0; - accum = 0; - for (i = 1; i < 3; i++) { - char fmtchar = (*format)[i]; - g_message("Format X: code: %c\n", fmtchar); - tmp = g_ascii_xdigit_value(fmtchar); - if (tmp != -1) { - accum = accum * 16 + tmp; - } - } - g_string_append_c(out, 4); - g_string_append_c(out, accum); - g_string_append_c(out, FORMAT_COLOR_NOCHANGE); - retval += i - 1; - - g_message("Format X: code: %d (0x%02x)\n", accum, accum); - - break; + if ((*format)[1] < '0' || (*format)[1] > '7') + break; + tmp = 16 + ((*format)[1]-'0'-1)*36; + if (tmp > 231) { + if (!isalpha((*format)[2])) + break; + + tmp += (*format)[2] >= 'a' ? (*format)[2] - 'a' : (*format)[2] - 'A'; + + if (tmp > 255) + break; + } + else if (tmp > 0) { + if (!isalnum((*format)[2])) + break; + + if ((*format)[2] >= 'a') + tmp += 10 + (*format)[2] - 'a'; + else if ((*format)[2] >= 'A') + tmp += 10 + (*format)[2] - 'A'; + else + tmp += (*format)[2] - '0'; + } + else { + if (!isxdigit((*format)[2])) + break; + + tmp = g_ascii_xdigit_value((*format)[2]); + } + + retval += 2; + + format_ext_color(out, fmt == 'x', tmp); + break; + case 'z': + case 'Z': + tmp2 = 0; + for (tmp = 1; tmp < 7; ++tmp) { + if (!isxdigit((*format)[tmp])) { + tmp2 = UINT_MAX; + break; + } + tmp2 <<= 4; + tmp2 |= g_ascii_xdigit_value((*format)[tmp]); + } + + if (tmp2 == UINT_MAX) + break; + + retval += 6; + + format_24bit_color(out, fmt == 'z', tmp2); + break; default: /* check if it's a background color */ p = strchr(format_backs, fmt); @@ -223,8 +303,6 @@ int format_expand_styles(GString *out, const char **format, int *flags) g_string_append_c(out, 4); g_string_append_c(out, FORMAT_COLOR_NOCHANGE); g_string_append_c(out, (char) ((int) (p-format_backs)+'0')); - g_message( "BG: Printing: %d '%s'\n", - ((int) (p-format_backs)+'0'), out->str); break; } @@ -232,7 +310,6 @@ int format_expand_styles(GString *out, const char **format, int *flags) if (fmt == 'p') fmt = 'm'; p = strchr(format_fores, fmt); if (p != NULL) { - /* color code indicator for format_send_to_gui */ g_string_append_c(out, 4); g_string_append_c(out, (char) ((int) (p-format_fores)+'0')); g_string_append_c(out, FORMAT_COLOR_NOCHANGE); @@ -244,13 +321,12 @@ int format_expand_styles(GString *out, const char **format, int *flags) p = strchr(format_boldfores, fmt); if (p != NULL) { g_string_append_c(out, 4); - /* +8 selects bold version */ g_string_append_c(out, (char) (8+(int) (p-format_boldfores)+'0')); g_string_append_c(out, FORMAT_COLOR_NOCHANGE); break; } - return 0; + return FALSE; } return retval; @@ -375,10 +451,9 @@ int format_get_length(const char *str) if (*str != '%') { adv = format_expand_styles(tmp, &str, NULL); str += adv; - if (adv > 1) { + if (adv) continue; } - } /* %% or unknown %code, written as-is */ if (*str != '%') @@ -415,10 +490,9 @@ int format_real_length(const char *str, int len) if (*str != '%') { adv = format_expand_styles(tmp, &str, NULL); str += adv; - if (adv > 1) { + if (adv) continue; } - } /* %% or unknown %code, written as-is */ if (*str != '%') { @@ -439,8 +513,6 @@ int format_real_length(const char *str, int len) char *format_string_expand(const char *text, int *flags) { - g_message( "format_string_expand: flags: %04x\n", *flags); - GString *out; char code, *ret; int adv; @@ -454,13 +526,13 @@ char *format_string_expand(const char *text, int *flags) while (*text != '\0') { if (code == '%') { /* color code */ - adv = format_expand_styles(out, &text, flags); - if (!adv) { + adv = format_expand_styles(out, &text, flags); + if (!adv) { g_string_append_c(out, '%'); g_string_append_c(out, '%'); g_string_append_c(out, *text); - } else { - text += adv -1; + } else { + text += adv - 1; } code = 0; } else { @@ -492,13 +564,13 @@ static char *format_get_text_args(TEXT_DEST_REC *dest, while (*text != '\0') { if (code == '%') { /* color code */ - adv = format_expand_styles(out, &text, &dest->flags); - if (!adv) { + adv = format_expand_styles(out, &text, &dest->flags); + if (!adv) { g_string_append_c(out, '%'); g_string_append_c(out, '%'); g_string_append_c(out, *text); - } else { - text += adv -1; + } else { + text += adv - 1; } code = 0; } else if (code == '$') { @@ -789,13 +861,22 @@ void format_newline(WINDOW_REC *window) "", NULL); } +#ifndef TERM_TRUECOLOR +inline static int color_24bit_256_int(unsigned int color) +{ + unsigned char rgb[] = { color >> 16, color >> 8, color }; + return color_24bit_256(rgb); +} +#endif /* !TERM_TRUECOLOR */ + /* parse ANSI color string */ static const char *get_ansi_color(THEME_REC *theme, const char *str, int *fg_ret, int *bg_ret, int *flags_ret) { static char ansitab[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; const char *start; - int fg, bg, flags, num; + int fg, bg, flags, num, i; + unsigned int num2; if (*str != '[') return str; @@ -822,28 +903,127 @@ static const char *get_ansi_color(THEME_REC *theme, const char *str, /* reset colors back to default */ fg = theme->default_color; bg = -1; - flags &= ~GUI_PRINT_FLAG_INDENT; + flags &= ~(GUI_PRINT_FLAG_COLOR_24_FG | GUI_PRINT_FLAG_COLOR_24_BG | GUI_PRINT_FLAG_INDENT); break; case 1: /* hilight */ flags |= GUI_PRINT_FLAG_BOLD; break; + case 22: + /* normal */ + flags &= ~GUI_PRINT_FLAG_BOLD; + break; + case 4: + /* underline */ + flags |= GUI_PRINT_FLAG_UNDERLINE; + break; + case 24: + /* not underline */ + flags &= ~GUI_PRINT_FLAG_UNDERLINE; + break; case 5: /* blink */ flags |= GUI_PRINT_FLAG_BLINK; break; + case 25: + /* steady */ + flags &= ~GUI_PRINT_FLAG_BLINK; + break; case 7: /* reverse */ flags |= GUI_PRINT_FLAG_REVERSE; break; + case 27: + /* positive */ + flags &= ~GUI_PRINT_FLAG_REVERSE; + break; + case 39: + /* reset fg */ + flags &= ~GUI_PRINT_FLAG_COLOR_24_FG; + fg = theme->default_color; + break; + case 49: + /* reset bg */ + bg = -1; + flags &= ~(GUI_PRINT_FLAG_COLOR_24_BG | GUI_PRINT_FLAG_INDENT); + break; + case 38: + case 48: + /* ANSI indexed color or RGB color */ + if (*str != ';') break; + str++; + for (num2 = 0; i_isdigit(*str); str++) + num2 = num2*10 + (*str-'0'); + + switch (num2) { + case 2: + /* RGB */ + num2 = 0; + + for (i = 0; i < 3; ++i) { + num2 <<= 8; + + if (*str != ';' && *str != ':') { + i = -1; + break; + } + str++; + for (; i_isdigit(*str); str++) + num2 = (num2&~0xff) | + (((num2&0xff) * 10 + (*str-'0'))&0xff); + } + + if (i == -1) break; +#ifdef TERM_TRUECOLOR + if (num == 38) { + flags |= GUI_PRINT_FLAG_COLOR_24_FG; + fg = num2; + } else if (num == 48) { + flags |= GUI_PRINT_FLAG_COLOR_24_BG; + bg = num2; + } +#else /* !TERM_TRUECOLOR */ + if (num == 38) { + flags &= ~GUI_PRINT_FLAG_COLOR_24_FG; + fg = color_24bit_256_int(num2); + } else if (num == 48) { + flags &= ~GUI_PRINT_FLAG_COLOR_24_BG; + bg = color_24bit_256_int(num2); + } +#endif + + break; + case 5: + /* indexed */ + if (*str != ';') break; + str++; + for (num2 = 0; i_isdigit(*str); str++) + num2 = num2*10 + (*str-'0'); + + if (num == 38) { + flags &= ~GUI_PRINT_FLAG_COLOR_24_FG; + fg = num2; + } else if (num == 48) { + flags &= ~GUI_PRINT_FLAG_COLOR_24_BG; + bg = num2; + } + + break; + } + break; default: if (num >= 30 && num <= 37) { - if (fg == -1) fg = 0; - fg = (fg & 0xf8) | ansitab[num-30]; - } - if (num >= 40 && num <= 47) { - if (bg == -1) bg = 0; - bg = (bg & 0xf8) | ansitab[num-40]; + flags &= ~GUI_PRINT_FLAG_COLOR_24_FG; + fg = ansitab[num-30]; + } else if (num >= 40 && num <= 47) { + flags &= ~GUI_PRINT_FLAG_COLOR_24_BG; + bg = ansitab[num-40]; + } else if (num >= 90 && num <= 97) { + flags &= ~GUI_PRINT_FLAG_COLOR_24_FG; + fg = 8 + ansitab[num-90]; + } else if (num >= 100 && num <= 107) { + flags &= ~GUI_PRINT_FLAG_COLOR_24_BG; + bg = 8 + ansitab[num-100]; } break; } @@ -903,14 +1083,10 @@ static void get_mirc_color(const char **str, int *fg_ret, int *bg_ret) if (bg_ret) *bg_ret = bg; } -/* TODO: What are these magic numbers!? - */ #define IS_COLOR_CODE(c) \ ((c) == 2 || (c) == 3 || (c) == 4 || (c) == 6 || (c) == 7 || \ (c) == 15 || (c) == 22 || (c) == 27 || (c) == 31) -//#define IS_COLOR_CODE(c) ((c) < 255) - /* Return how many characters in `str' must be skipped before `len' characters of text is skipped. */ int strip_real_length(const char *str, int len, @@ -935,6 +1111,20 @@ int strip_real_length(const char *str, int len, *last_color_len = (int) (str-mircstart); } else if (*str == 4 && str[1] != '\0') { +#ifdef TERM_TRUECOLOR + if (str[1] == FORMAT_COLOR_24 && str[2] != '\0') { + if (str[3] == '\0') str++; + else if (str[4] == '\0') str += 2; + else if (str[5] == '\0') str += 3; + else { + if (last_color_pos != NULL) + *last_color_pos = (int) (str-start); + if (last_color_len != NULL) + *last_color_len = 6; + str+=4; + } + } else +#endif if (str[1] < FORMAT_STYLE_SPECIAL && str[2] != '\0') { if (last_color_pos != NULL) *last_color_pos = (int) (str-start); @@ -984,6 +1174,14 @@ char *strip_codes(const char *input) /* irssi color */ if (p[2] != '\0') { +#ifdef TERM_TRUECOLOR + if (p[1] == FORMAT_COLOR_24) { + if (p[3] == '\0') p += 2; + else if (p[4] == '\0') p += 3; + else if (p[5] == '\0') p += 4; + else p += 5; + } else +#endif /* TERM_TRUECOLOR */ p += 2; continue; } @@ -1013,10 +1211,7 @@ void format_send_to_gui(TEXT_DEST_REC *dest, const char *text) dup = str = g_strdup(text); - flags = 0; - fgcolor = theme->default_color; - bgcolor = -1; - + flags = 0; fgcolor = theme->default_color; bgcolor = -1; while (*str != '\0') { type = '\0'; for (ptr = str; *ptr != '\0'; ptr++) { @@ -1038,17 +1233,12 @@ void format_send_to_gui(TEXT_DEST_REC *dest, const char *text) if (*str != '\0' || (flags & GUI_PRINT_FLAG_CLRTOEOL)) { /* send the text to gui handler */ - g_message("format_send_to_gui: sending: fg: 0x%04x, " \ - "bg: 0x%04x flags: 0x%04x\n", fgcolor, bgcolor, flags); - signal_emit_id(signal_gui_print_text, 6, dest->window, GINT_TO_POINTER(fgcolor), GINT_TO_POINTER(bgcolor), GINT_TO_POINTER(flags), str, dest); - flags &= ~(GUI_PRINT_FLAG_INDENT|GUI_PRINT_FLAG_CLRTOEOL); - /* fprintf("format_send_to_gui: resetting flags: 0x%04x\n", flags); */ } if (type == '\n') { @@ -1063,12 +1253,12 @@ void format_send_to_gui(TEXT_DEST_REC *dest, const char *text) switch (type) { - case MIRC_BOLD_MARKER: + case 2: /* bold */ if (!hide_text_style) flags ^= GUI_PRINT_FLAG_BOLD; break; - case MIRC_COLOR_MARKER: + case 3: /* MIRC color */ get_mirc_color((const char **) &ptr, hide_colors ? NULL : &fgcolor, @@ -1076,7 +1266,7 @@ void format_send_to_gui(TEXT_DEST_REC *dest, const char *text) if (!hide_colors) flags |= GUI_PRINT_FLAG_MIRC_COLOR; break; - case LINE_FORMAT_MARKER: + case 4: /* user specific colors */ flags &= ~GUI_PRINT_FLAG_MIRC_COLOR; switch (*ptr) { @@ -1088,12 +1278,7 @@ void format_send_to_gui(TEXT_DEST_REC *dest, const char *text) break; case FORMAT_STYLE_BOLD: flags ^= GUI_PRINT_FLAG_BOLD; - g_message( - "format bold spotted, flags now: 0x%04x\n", - flags); - break; - case FORMAT_STYLE_REVERSE: flags ^= GUI_PRINT_FLAG_REVERSE; break; @@ -1110,16 +1295,47 @@ void format_send_to_gui(TEXT_DEST_REC *dest, const char *text) break; case FORMAT_STYLE_CLRTOEOL: break; + case FORMAT_COLOR_EXT1: + fgcolor = 0x10 + *++ptr - FORMAT_COLOR_NOCHANGE; + flags &= ~GUI_PRINT_FLAG_COLOR_24_FG; + break; + case FORMAT_COLOR_EXT1_BG: + bgcolor = 0x10 + *++ptr - FORMAT_COLOR_NOCHANGE; + flags &= ~GUI_PRINT_FLAG_COLOR_24_BG; + break; + case FORMAT_COLOR_EXT2: + fgcolor = 0x60 + *++ptr - FORMAT_COLOR_NOCHANGE; + flags &= ~GUI_PRINT_FLAG_COLOR_24_FG; + break; + case FORMAT_COLOR_EXT2_BG: + bgcolor = 0x60 + *++ptr - FORMAT_COLOR_NOCHANGE; + flags &= ~GUI_PRINT_FLAG_COLOR_24_BG; + break; + case FORMAT_COLOR_EXT3: + fgcolor = 0xb0 + *++ptr - FORMAT_COLOR_NOCHANGE; + flags &= ~GUI_PRINT_FLAG_COLOR_24_FG; + break; + case FORMAT_COLOR_EXT3_BG: + bgcolor = 0xb0 + *++ptr - FORMAT_COLOR_NOCHANGE; + flags &= ~GUI_PRINT_FLAG_COLOR_24_BG; + break; +#ifdef TERM_TRUECOLOR + case FORMAT_COLOR_24: + unformat_24bit_color(&ptr, 1, &fgcolor, &bgcolor, &flags); + break; +#endif default: if (*ptr != FORMAT_COLOR_NOCHANGE) { - fgcolor = (unsigned char) *ptr-'0'; + flags &= ~GUI_PRINT_FLAG_COLOR_24_FG; + fgcolor = *ptr==(char)0xff ? -1 : (unsigned char) *ptr-'0'; } if (ptr[1] == '\0') break; ptr++; if (*ptr != FORMAT_COLOR_NOCHANGE) { - bgcolor = *ptr-'0'; + flags &= ~GUI_PRINT_FLAG_COLOR_24_BG; + bgcolor = *ptr==(char)0xff ? -1 : *ptr-'0'; } } ptr++; diff --git a/src/fe-common/core/formats.h b/src/fe-common/core/formats.h index 56412937..037aa424 100644 --- a/src/fe-common/core/formats.h +++ b/src/fe-common/core/formats.h @@ -4,12 +4,6 @@ #include "themes.h" #include "fe-windows.h" -/* various types of colour codings possible. */ -#define MIRC_BOLD_MARKER ('\002') -#define MIRC_COLOR_MARKER ('\003') -#define LINE_FORMAT_MARKER ('\004') - - #define GUI_PRINT_FLAG_BOLD 0x0001 #define GUI_PRINT_FLAG_REVERSE 0x0002 #define GUI_PRINT_FLAG_UNDERLINE 0x0004 @@ -19,6 +13,8 @@ #define GUI_PRINT_FLAG_NEWLINE 0x0080 #define GUI_PRINT_FLAG_CLRTOEOL 0x0100 #define GUI_PRINT_FLAG_MONOSPACE 0x0200 +#define GUI_PRINT_FLAG_COLOR_24_FG 0x0400 +#define GUI_PRINT_FLAG_COLOR_24_BG 0x0800 #define MAX_FORMAT_PARAMS 10 #define DEFAULT_FORMAT_ARGLIST_SIZE 200 @@ -127,6 +123,15 @@ char *strip_codes(const char *input); void format_send_to_gui(TEXT_DEST_REC *dest, const char *text); #define FORMAT_COLOR_NOCHANGE ('0'-1) /* don't change this, at least hilighting depends this value */ +#define FORMAT_COLOR_EXT1 ('0'-2) +#define FORMAT_COLOR_EXT2 ('0'-3) +#define FORMAT_COLOR_EXT3 ('0'-4) +#define FORMAT_COLOR_EXT1_BG ('0'-5) +#define FORMAT_COLOR_EXT2_BG ('0'-9) +#define FORMAT_COLOR_EXT3_BG ('0'-10) +#ifdef TERM_TRUECOLOR +#define FORMAT_COLOR_24 ('0'-13) +#endif #define FORMAT_STYLE_SPECIAL 0x60 #define FORMAT_STYLE_BLINK (0x01 + FORMAT_STYLE_SPECIAL) @@ -138,6 +143,8 @@ void format_send_to_gui(TEXT_DEST_REC *dest, const char *text); #define FORMAT_STYLE_CLRTOEOL (0x08 + FORMAT_STYLE_SPECIAL) #define FORMAT_STYLE_MONOSPACE (0x09 + FORMAT_STYLE_SPECIAL) int format_expand_styles(GString *out, const char **format, int *flags); +void format_ext_color(GString *out, int bg, int color); +void format_24bit_color(GString *out, int bg, unsigned int color); void formats_init(void); void formats_deinit(void); diff --git a/src/fe-common/core/printtext.c b/src/fe-common/core/printtext.c index 1ac4e4de..a5eaa38f 100644 --- a/src/fe-common/core/printtext.c +++ b/src/fe-common/core/printtext.c @@ -256,12 +256,12 @@ static char *printtext_get_args(TEXT_DEST_REC *dest, const char *str, break; } default: - adv = format_expand_styles(out, &str, &dest->flags); - if (!adv) { + adv = format_expand_styles(out, &str, &dest->flags); + if (!adv) { g_string_append_c(out, '%'); g_string_append_c(out, *str); - } else { - str += adv -1; + } else { + str += adv - 1; } break; } @@ -277,6 +277,7 @@ static char *printtext_expand_formats(const char *str, int *flags) GString *out; char *ret; int adv; + out = g_string_new(NULL); for (; *str != '\0'; str++) { if (*str != '%') { @@ -292,7 +293,7 @@ static char *printtext_expand_formats(const char *str, int *flags) g_string_append_c(out, '%'); g_string_append_c(out, *str); } else { - str += adv -1; + str += adv - 1; } } diff --git a/src/fe-common/core/themes.c b/src/fe-common/core/themes.c index 548836ac..d92d23fe 100644 --- a/src/fe-common/core/themes.c +++ b/src/fe-common/core/themes.c @@ -115,8 +115,8 @@ void theme_destroy(THEME_REC *rec) } static char *theme_replace_expand(THEME_REC *theme, int index, - char default_fg, char default_bg, - char *last_fg, char *last_bg, + theme_rm_col default_fg, theme_rm_col default_bg, + theme_rm_col *last_fg, theme_rm_col *last_bg, char chr, int flags) { GSList *rec; @@ -168,15 +168,44 @@ static void theme_format_append_variable(GString *str, const char **format) g_free(value); } +static inline int chr_is_valid_rgb(const char format[]) +{ + int tmp; + for (tmp = 1; tmp < 7; ++tmp) { + if (!isxdigit(format[tmp])) + return tmp; + } + return 0; +} + +static inline int chr_is_valid_ext(const char format[]) +{ + if (format[1] < '0' || format[1] > '7') + return 1; + + if (format[1] == '7') { + if (!isalpha(format[2]) || format[2] == 'y' || format[2] == 'Y' + || format[2] =='z' || format[2] == 'Z') + return 2; + } else if (format[1] == '0') { + if (!isxdigit(format[2])) + return 2; + } else if (!isalnum(format[2])) + return 2; + + return 0; +} + /* append next "item", either a character, $variable or %format */ static void theme_format_append_next(THEME_REC *theme, GString *str, const char **format, - char default_fg, char default_bg, - char *last_fg, char *last_bg, + theme_rm_col default_fg, theme_rm_col default_bg, + theme_rm_col *last_fg, theme_rm_col *last_bg, int flags) { int index; unsigned char chr; + char *t; chr = **format; if ((chr == '$' || chr == '%') && @@ -203,22 +232,50 @@ static void theme_format_append_next(THEME_REC *theme, GString *str, /* %n = change to default color */ g_string_append(str, "%n"); - if (default_bg != 'n') { + if (default_bg.m[0] != 'n') { g_string_append_c(str, '%'); - g_string_append_c(str, default_bg); + g_string_append(str, default_bg.m); } - if (default_fg != 'n') { + if (default_fg.m[0] != 'n') { g_string_append_c(str, '%'); - g_string_append_c(str, default_fg); + g_string_append(str, default_fg.m); } *last_fg = default_fg; *last_bg = default_bg; + } else if (chr == 'z' || chr == 'Z') { + if (chr_is_valid_rgb(*format) == 0) { + t = chr == 'z' ? (*last_bg).m : (*last_fg).m; + strncpy(t, *format, 7); + t[7] = '\0'; + g_string_append_c(str, '%'); + g_string_append(str, t); + (*format)+=6; + } else { + g_string_append(str, "%%"); + g_string_append_c(str, **format); + } + } else if (chr == 'x' || chr == 'X') { + if (chr_is_valid_ext(*format) == 0) { + t = chr == 'x' ? (*last_bg).m : (*last_fg).m; + strncpy(t, *format, 3); + t[3] = '\0'; + g_string_append_c(str, '%'); + g_string_append(str, t); + (*format)+=2; + } else { + g_string_append(str, "%%"); + g_string_append_c(str, **format); + } } else { - if (IS_FGCOLOR_FORMAT(chr)) - *last_fg = chr; - if (IS_BGCOLOR_FORMAT(chr)) - *last_bg = chr; + if (IS_FGCOLOR_FORMAT(chr)) { + (*last_fg).m[0] = chr; + (*last_fg).m[1] = '\0'; + } + if (IS_BGCOLOR_FORMAT(chr)) { + (*last_bg).m[0] = chr; + (*last_bg).m[1] = '\0'; + } g_string_append_c(str, '%'); g_string_append_c(str, chr); } @@ -306,7 +363,10 @@ static int data_is_empty(const char **data) char *theme_format_expand_get(THEME_REC *theme, const char **format) { GString *str; - char *ret, dummy; + char *ret; + theme_rm_col dummy, reset; + dummy.m[0] = '\0'; + strcpy(reset.m, "n"); int braces = 1; /* we start with one brace opened */ str = g_string_new(NULL); @@ -321,7 +381,7 @@ char *theme_format_expand_get(THEME_REC *theme, const char **format) continue; } else { theme_format_append_next(theme, str, format, - 'n', 'n', + reset, reset, &dummy, &dummy, 0); continue; } @@ -343,15 +403,19 @@ char *theme_format_expand_get(THEME_REC *theme, const char **format) /* expand a single {abstract ...data... } */ static char *theme_format_expand_abstract(THEME_REC *theme, const char **formatp, - char default_fg, char default_bg, + theme_rm_col *last_fg, + theme_rm_col *last_bg, int flags) { GString *str; const char *p, *format; char *abstract, *data, *ret; + theme_rm_col default_fg, default_bg; int len; format = *formatp; + default_fg = *last_fg; + default_bg = *last_bg; /* get abstract name first */ p = format; @@ -425,7 +489,7 @@ static char *theme_format_expand_abstract(THEME_REC *theme, /* abstract may itself contain abstracts or replaces */ p = abstract; ret = theme_format_expand_data(theme, &p, default_fg, default_bg, - &default_fg, &default_bg, + last_fg, last_bg, flags | EXPAND_FLAG_LASTCOLOR_ARG); g_free(abstract); return ret; @@ -433,13 +497,13 @@ static char *theme_format_expand_abstract(THEME_REC *theme, /* expand the data part in {abstract data} */ char *theme_format_expand_data(THEME_REC *theme, const char **format, - char default_fg, char default_bg, - char *save_last_fg, char *save_last_bg, + theme_rm_col default_fg, theme_rm_col default_bg, + theme_rm_col *save_last_fg, theme_rm_col *save_last_bg, int flags) { GString *str; char *ret, *abstract; - char last_fg, last_bg; + theme_rm_col last_fg, last_bg; int recurse_flags; last_fg = default_fg; @@ -482,7 +546,7 @@ char *theme_format_expand_data(THEME_REC *theme, const char **format, /* get a single {...} */ abstract = theme_format_expand_abstract(theme, format, - last_fg, last_bg, + &last_fg, &last_bg, recurse_flags); if (abstract != NULL) { g_string_append(str, abstract); @@ -490,13 +554,11 @@ char *theme_format_expand_data(THEME_REC *theme, const char **format, } } - if ((flags & EXPAND_FLAG_LASTCOLOR_ARG) == 0) { /* save the last color */ if (save_last_fg != NULL) *save_last_fg = last_fg; if (save_last_bg != NULL) *save_last_bg = last_bg; - } ret = str->str; g_string_free(str, FALSE); @@ -510,7 +572,8 @@ char *theme_format_expand_data(THEME_REC *theme, const char **format, static char *theme_format_compress_colors(THEME_REC *theme, const char *format) { GString *str; - char *ret, last_fg, last_bg; + char *ret; + char last_fg, last_bg; str = g_string_new(NULL); @@ -543,8 +606,12 @@ static char *theme_format_compress_colors(THEME_REC *theme, const char *format) if (IS_FGCOLOR_FORMAT(*format)) last_fg = *format; + else if (*format == 'Z' || *format == 'X') + last_fg = '\0'; if (IS_BGCOLOR_FORMAT(*format)) last_bg = *format; + else if (*format == 'z' || *format == 'x') + last_bg = '\0'; } format++; } @@ -558,11 +625,13 @@ static char *theme_format_compress_colors(THEME_REC *theme, const char *format) char *theme_format_expand(THEME_REC *theme, const char *format) { char *data, *ret; + theme_rm_col reset; + strcpy(reset.m, "n"); g_return_val_if_fail(theme != NULL, NULL); g_return_val_if_fail(format != NULL, NULL); - data = theme_format_expand_data(theme, &format, 'n', 'n', NULL, NULL, + data = theme_format_expand_data(theme, &format, reset, reset, NULL, NULL, EXPAND_FLAG_ROOT); ret = theme_format_compress_colors(theme, data); g_free(data); @@ -944,10 +1013,6 @@ static int theme_read(THEME_REC *theme, const char *path) config_get_int(config, NULL, "default_color", -1); theme->info_eol = config_get_bool(config, NULL, "info_eol", FALSE); - /* FIXME: remove after 0.7.99 */ - if (theme->default_color == 0 && - config_get_int(config, NULL, "default_real_color", -1) != -1) - theme->default_color = -1; theme_read_replaces(config, theme); if (path != NULL) diff --git a/src/fe-common/core/themes.h b/src/fe-common/core/themes.h index dcdea0fc..31cfe943 100644 --- a/src/fe-common/core/themes.h +++ b/src/fe-common/core/themes.h @@ -57,10 +57,14 @@ void theme_set_default_abstract(const char *key, const char *value); #define EXPAND_FLAG_ROOT 0x10 #define EXPAND_FLAG_LASTCOLOR_ARG 0x20 +typedef struct { + char m[8]; +} theme_rm_col; + char *theme_format_expand(THEME_REC *theme, const char *format); char *theme_format_expand_data(THEME_REC *theme, const char **format, - char default_fg, char default_bg, - char *save_last_fg, char *save_last_bg, + theme_rm_col default_fg, theme_rm_col default_bg, + theme_rm_col *save_last_fg, theme_rm_col *save_last_bg, int flags); void themes_reload(void); diff --git a/src/fe-text/gui-printtext.c b/src/fe-text/gui-printtext.c index 556fae1b..380ca114 100644 --- a/src/fe-text/gui-printtext.c +++ b/src/fe-text/gui-printtext.c @@ -29,7 +29,14 @@ #include "gui-printtext.h" #include "gui-windows.h" -int mirc_colors[] = { 15, 0, 1, 2, 12, 4, 5, 6, 14, 10, 3, 11, 9, 13, 8, 7 }; +int mirc_colors[] = { 15, 0, 1, 2, 12, 4, 5, 6, 14, 10, 3, 11, 9, 13, 8, 7, + /* 16-27 */ 52, 94, 100, 58, 22, 29, 23, 24, 17, 54, 53, 89, + /* 28-39 */ 88, 130, 142, 64, 28, 35, 30, 25, 18, 91, 90, 125, + /* 40-51 */ 124, 166, 184, 106, 34, 49, 37, 33, 19, 129, 127, 161, + /* 52-63 */ 196, 208, 226, 154, 46, 86, 51, 75, 21, 171, 201, 198, + /* 64-75 */ 203, 215, 227, 191, 83, 122, 87, 111, 63, 177, 207, 205, + /* 76-87 */ 217, 223, 229, 193, 157, 158, 159, 153, 147, 183, 219, 212, + /* 88-98 */ 16, 233, 235, 237, 239, 241, 244, 247, 250, 254, 231, -1 }; static int scrollback_lines, scrollback_time, scrollback_burst_remove; static int next_xpos, next_ypos; @@ -145,44 +152,43 @@ static void remove_old_lines(TEXT_BUFFER_VIEW_REC *view) static void get_colors(int flags, int *fg, int *bg, int *attr) { + *attr = 0; if (flags & GUI_PRINT_FLAG_MIRC_COLOR) { - g_message( "getcolor: handling mirc colors\n"); - - /* mirc colors - real range is 0..15, but after 16 - colors wrap to 0, 1, ... */ - if (*bg >= 0) *bg = mirc_colors[*bg % 16]; - if (*fg >= 0) *fg = mirc_colors[*fg % 16]; - /* TODO: What to do here? */ - if (settings_get_bool("mirc_blink_fix")) - *bg &= ~0x08; + /* mirc colors - extended colours proposal */ + if (*bg >= 0) { + *bg = mirc_colors[*bg % 100]; + flags &= ~GUI_PRINT_FLAG_COLOR_24_BG; + if (settings_get_bool("mirc_blink_fix")) + *bg = term_color256map[*bg&0xff] & ~0x08; + } + if (*fg >= 0) { + *fg = mirc_colors[*fg % 100]; + flags &= ~GUI_PRINT_FLAG_COLOR_24_FG; + } } - if (*fg < 0 || *fg > 255) { - g_message( "getcolor: fg %d outside range, setting to -1\n", *fg); + if (flags & GUI_PRINT_FLAG_COLOR_24_FG) + *attr |= ATTR_FGCOLOR24; + else if (*fg < 0 || *fg > 255) { *fg = -1; + *attr |= ATTR_RESETFG; } - if (*bg < 0 || *bg > 255) { - g_message( "getcolor: bf %d outside range, setting to -1\n", *bg); + else + *attr |= *fg; + + if (flags & GUI_PRINT_FLAG_COLOR_24_BG) + *attr |= ATTR_BGCOLOR24; + else if (*bg < 0 || *bg > 255) { *bg = -1; + *attr |= ATTR_RESETBG; } + else + *attr |= (*bg << BG_SHIFT); - *attr = 0; - if (flags & GUI_PRINT_FLAG_REVERSE) { - *attr |= ATTR_REVERSE; - g_message( "getcolor: setting flag_reverse\n"); - } - if (flags & GUI_PRINT_FLAG_BOLD) { - *attr |= ATTR_BOLD; - g_message( "getcolor: setting flag_bold\n"); - } - if (flags & GUI_PRINT_FLAG_UNDERLINE) { - *attr |= ATTR_UNDERLINE; - g_message( "getcolor: setting flag_underline\n"); - } - if (flags & GUI_PRINT_FLAG_BLINK) { - *attr |= ATTR_BLINK; - g_message( "getcolor: setting flag_blink\n"); - } + if (flags & GUI_PRINT_FLAG_REVERSE) *attr |= ATTR_REVERSE; + if (flags & GUI_PRINT_FLAG_BOLD) *attr |= ATTR_BOLD; + if (flags & GUI_PRINT_FLAG_UNDERLINE) *attr |= ATTR_UNDERLINE; + if (flags & GUI_PRINT_FLAG_BLINK) *attr |= ATTR_BLINK; } static void view_add_eol(TEXT_BUFFER_VIEW_REC *view, LINE_REC **line) @@ -203,33 +209,15 @@ static void sig_gui_print_text(WINDOW_REC *window, void *fgcolor, LINE_INFO_REC lineinfo; int fg, bg, flags, attr; - attr = 0; - flags = GPOINTER_TO_INT(pflags); fg = GPOINTER_TO_INT(fgcolor); bg = GPOINTER_TO_INT(bgcolor); - - g_message( "SGPT str: '%s'\n", str); - - - g_message( "SGPT start: fg: %d (%02x), bg: %d (%02x) attr: %d (%04x), flags: %d (0x%04x)\n", - fg, fg, bg, bg, attr, attr, flags, flags); - get_colors(flags, &fg, &bg, &attr); - g_message( "SGPT getcol: fg: %d (%02x), bg: %d (%02x) attr: %d (%04x)\n", - fg, fg, (bg << 8), (bg << 8), attr, attr); - if (window == NULL) { g_return_if_fail(next_xpos != -1); - attr |= fg >= 0 ? fg : ATTR_RESETFG; - attr |= bg >= 0 ? (bg << 8) : ATTR_RESETBG; - g_message( - "SGPT nowin: fg: %d (%02x), bg: %d (%02x) attr: %d (%04x)\n", - fg, fg, (bg << 8), (bg << 8), attr, attr); - - term_set_color(root_window, attr); + term_set_color2(root_window, attr, fg, bg); term_move(root_window, next_xpos, next_ypos); if (flags & GUI_PRINT_FLAG_CLRTOEOL) diff --git a/src/fe-text/statusbar.c b/src/fe-text/statusbar.c index 68724293..5453c2d5 100644 --- a/src/fe-text/statusbar.c +++ b/src/fe-text/statusbar.c @@ -670,6 +670,8 @@ void statusbar_item_default_handler(SBAR_ITEM_REC *item, int get_size_only, SERVER_REC *server; WI_ITEM_REC *wiitem; char *tmpstr, *tmpstr2; + theme_rm_col reset; + strcpy(reset.m, "n"); int len; if (str == NULL) @@ -690,7 +692,7 @@ void statusbar_item_default_handler(SBAR_ITEM_REC *item, int get_size_only, /* expand templates */ tmpstr = theme_format_expand_data(current_theme, &str, - 'n', 'n', + reset, reset, NULL, NULL, EXPAND_FLAG_ROOT | EXPAND_FLAG_IGNORE_REPLACES | diff --git a/src/fe-text/term-curses.c b/src/fe-text/term-curses.c index fc674fd3..f1ee3131 100644 --- a/src/fe-text/term-curses.c +++ b/src/fe-text/term-curses.c @@ -275,21 +275,25 @@ static int get_attr(int color) { int attr; + if ((color & FG_MASK) >> 4) + color = (color & ~FG_MASK) | term_color256map[color & FG_MASK]; + if ((color & BG_MASK) >> (BG_SHIFT + 4)) + color = (color & ~BG_MASK) | (term_color256map[(color & BG_MASK) >> BG_SHIFT] << BG_SHIFT); if (!term_use_colors) - attr = (color & 0x70) ? A_REVERSE : 0; - else if ((color & 0xff) == 8 || (color & (0xff | ATTR_RESETFG)) == 0) + attr = (color & (0x7 << BG_SHIFT)) ? A_REVERSE : 0; + else if ((color & ((0xf << BG_SHIFT) | 0xf)) == 8 || (color & (FG_MASK | BG_MASK | ATTR_RESETFG)) == 0) attr = COLOR_PAIR(63); - else if ((color & 0x77) == 0) + else if ((color & ((0x7 << BG_SHIFT) | 0x7)) == 0) attr = A_NORMAL; else { if (color & ATTR_RESETFG) { - color &= ~0x0f; + color &= ~FG_MASK; color |= settings_get_int("default_color"); } - attr = COLOR_PAIR((color&7) | ((color&0x70)>>1)); + attr = COLOR_PAIR((color&0x7) | ((color&(0x7<>BG_SHIFT<<3)); } - if ((color & 0x08) || (color & ATTR_BOLD)) attr |= A_BOLD; + if ((color & 0x8) || (color & ATTR_BOLD)) attr |= A_BOLD; if (color & ATTR_BLINK) attr |= A_BLINK; if (color & ATTR_UNDERLINE) attr |= A_UNDERLINE; @@ -298,6 +302,11 @@ static int get_attr(int color) } /* Change active color */ +void term_set_color2(TERM_WINDOW *window, int col, unsigned int fg_ignore, unsigned int bg_ignore) +{ + term_set_color(window, col); +} + void term_set_color(TERM_WINDOW *window, int col) { wattrset(window->win, get_attr(col)); diff --git a/src/fe-text/term-terminfo.c b/src/fe-text/term-terminfo.c index 0b27f452..2ca2f347 100644 --- a/src/fe-text/term-terminfo.c +++ b/src/fe-text/term-terminfo.c @@ -22,9 +22,12 @@ #include "signals.h" #include "term.h" #include "terminfo-core.h" +#include "fe-windows.h" #include "utf8.h" #include +#include +#include /* returns number of characters in the beginning of the buffer being a a single character, or -1 if more input is needed. The character will be @@ -48,7 +51,8 @@ static int vcmove, vcx, vcy, curs_visible; static int crealx, crealy, cforcemove; static int curs_x, curs_y; -static int last_fg, last_bg, last_attrs; +static unsigned int last_fg, last_bg; +static int last_attrs; static GSource *sigcont_source; static volatile sig_atomic_t got_sigcont; @@ -293,118 +297,119 @@ void term_window_scroll(TERM_WINDOW *window, int count) term_lines_empty[window->y+y] = FALSE; } -void term_set_color(TERM_WINDOW *window, int col) +inline static int term_putchar(int c) { - int set_normal; + return fputc(c, current_term->out); +} + +/* copied from terminfo-core.c */ +int tputs(); + +static int term_set_color_24bit(int bg, unsigned int lc) +{ + static char buf[20]; + const unsigned char color[] = { lc >> 16, lc >> 8, lc }; + + if (!term_use_colors24) { + if (bg) + terminfo_set_bg(color_24bit_256(color)); + else + terminfo_set_fg(color_24bit_256(color)); + return -1; + } + + /* \e[x8;2;...;...;...m */ + sprintf(buf, "\033[%d8;2;%d;%d;%dm", bg ? 4 : 3, color[0], color[1], color[2]); + return tputs(buf, 0, term_putchar); +} - int fg = (col & FG_MASK); - int bg = (col & BG_MASK) >> 8; -// int attrs = (col & 0xff0000) >> 16; +#define COLOR_RESET UINT_MAX - if (col != ATTR_RESET) { - g_message( "T-TI: set color called with col: %d (%08x)\n", col, col); - g_message( "T-TI: fg: %d (0x%02x), bg: %d (0x%02x)\n", fg, fg, bg, bg); - } else { - //g_message( "T-TI: set color called with col: %d (%08x)\n", col, col); - } +/* Change active color */ +void term_set_color2(TERM_WINDOW *window, int col, unsigned int fgcol24, unsigned int bgcol24) +{ + int set_normal; - set_normal = ((col & ATTR_RESETFG) && last_fg != ATTR_COLOR_UNDEFINED) || - ((col & ATTR_RESETBG) && last_bg != ATTR_COLOR_UNDEFINED); + unsigned int fg = (col & ATTR_FGCOLOR24) ? fgcol24 << 8 : (col & FG_MASK); + unsigned int bg = (col & ATTR_BGCOLOR24) ? bgcol24 << 8 : ((col & BG_MASK) >> BG_SHIFT); - if (((last_attrs & ATTR_BOLD) && !(col & ATTR_BOLD)) || - ((last_attrs & ATTR_BLINK) && !(col & ATTR_BLINK))) { + set_normal = ((col & ATTR_RESETFG) && last_fg != COLOR_RESET) || + ((col & ATTR_RESETBG) && last_bg != COLOR_RESET); + if (((last_attrs & ATTR_BOLD) && (col & ATTR_BOLD) == 0) || + ((last_attrs & ATTR_BLINK) && (col & ATTR_BLINK) == 0)) { /* we'll need to get rid of bold/blink - this can only be done with setting the default color */ set_normal = TRUE; } if (set_normal) { - last_fg = last_bg = ATTR_COLOR_UNDEFINED; + last_fg = last_bg = COLOR_RESET; last_attrs = 0; - g_message( "setnormal: setting last_* to 0%04x\n", last_fg); terminfo_set_normal(); - /* terminfo_set_bg(123); */ - //terminfo_set_fg(47); } - /* if colors are disabled, any background color setting enables - * reverse video mode - */ - - if (!term_use_colors && bg > 0) { + if (!term_use_colors && bg > 0) col |= ATTR_REVERSE; - } /* reversed text (use standout) */ if (col & ATTR_REVERSE) { - if ((last_attrs & ATTR_REVERSE) == 0) { - g_message( "setreverse: on\n"); + if ((last_attrs & ATTR_REVERSE) == 0) terminfo_set_standout(TRUE); - } - } else if (last_attrs & ATTR_REVERSE) { - g_message( "setreverse: off\n"); + } else if (last_attrs & ATTR_REVERSE) terminfo_set_standout(FALSE); - } /* set foreground color */ - if (fg != last_fg && (fg != 0 || (col & ATTR_RESETFG) == 0)) { + if (fg != last_fg && + (fg != 0 || (col & ATTR_RESETFG) == 0)) { if (term_use_colors) { last_fg = fg; - terminfo_set_fg(last_fg); - g_message( "setfg: setting fg to %d (0x%04x)\n", fg, fg); + if (!(fg & 0xff)) + term_set_color_24bit(0, last_fg >> 8); + else + terminfo_set_fg(last_fg); } } /* set background color */ - /* TODO: What magic numbers? - originally 0xf0 - 11110000 - * - */ - if (col & 0x8000 && window->term->TI_colors == 8) { - g_message( "0x080 match: setting attr_bold\n"); + if (window && (term_color256map[bg&0xff]&8) == window->term->TI_colors) col |= ATTR_BLINK; - } - - if (col & ATTR_BLINK) { - g_message( "setblink\n"); + if (col & ATTR_BLINK) current_term->set_blink(current_term); - } - if (bg != last_bg && (bg != 0 || (col & ATTR_RESETBG) == 0)) { + if (bg != last_bg && + (bg != 0 || (col & ATTR_RESETBG) == 0)) { if (term_use_colors) { last_bg = bg; - terminfo_set_bg(last_bg); - g_message( "setbg: setting bg to %d (0x%04x)\n", bg, bg); + if (!(bg & 0xff)) + term_set_color_24bit(1, last_bg >> 8); + else + terminfo_set_bg(last_bg); } } /* bold */ - - /* TODO: maybe make this fg > 7, since that implies a bright - * color,which bold can emulate. - */ - if (fg > 0 && window->term->TI_colors == 8) { - g_message( "0x080 match: setting attr_bold\n"); + if (window && (term_color256map[fg&0xff]&8) == window->term->TI_colors) col |= ATTR_BOLD; - } - - if (col & ATTR_BOLD) { - g_message("setbold\n"); + if (col & ATTR_BOLD) terminfo_set_bold(); - } /* underline */ if (col & ATTR_UNDERLINE) { - if ((last_attrs & ATTR_UNDERLINE) == 0) { + if ((last_attrs & ATTR_UNDERLINE) == 0) terminfo_set_uline(TRUE); - } - } else if (last_attrs & ATTR_UNDERLINE) { + } else if (last_attrs & ATTR_UNDERLINE) terminfo_set_uline(FALSE); - } - /* update the new attribute settings whilst ignoring color values. */ - last_attrs = col & ~( BG_MASK | FG_MASK ); + /* update the new attribute settings whilst ignoring color values. */ + last_attrs = col & ~( BG_MASK | FG_MASK ); } +void term_set_color(TERM_WINDOW *window, int col) +{ + term_set_color2(window, col &~(ATTR_FGCOLOR24|ATTR_BGCOLOR24), UINT_MAX, UINT_MAX); +} + + void term_move(TERM_WINDOW *window, int x, int y) { if (x >= 0 && y >= 0) { diff --git a/src/fe-text/term.c b/src/fe-text/term.c index 38239016..4600f02e 100644 --- a/src/fe-text/term.c +++ b/src/fe-text/term.c @@ -37,6 +37,7 @@ int term_width, term_height; int term_use_colors; +int term_use_colors24; int term_type; static int force_colors; @@ -106,10 +107,28 @@ static void cmd_redraw(void) irssi_redraw(); } +int term_color256map[] = { + 0, 4, 2, 6, 1, 5, 3, 7, 8,12,10,14, 9,13,11,15, + 0, 0, 1, 1, 1, 1, 0, 0, 3, 1, 1, 9, 2, 2, 3, 3, 3, 3, + 2, 2, 3, 3, 3, 3, 2, 2, 3, 3, 3,11,10,10, 3, 3,11,11, + 0, 0, 5, 1, 1, 9, 0, 8, 8, 8, 9, 9, 2, 8, 8, 8, 9, 9, + 2, 8, 8, 8, 9, 9, 2, 8, 8, 3, 3,11,10,10, 3, 3,11,11, + 4, 4, 5, 5, 5, 5, 4, 8, 8, 8, 9, 9, 6, 8, 8, 8, 9, 9, + 6, 8, 8, 8, 8, 9, 6, 8, 8, 8, 7, 7, 6, 6, 8, 7, 7, 7, + 4, 4, 5, 5, 5, 5, 4, 8, 8, 8, 9, 9, 6, 8, 8, 8, 8, 9, + 6, 8, 8, 8, 7, 7, 6, 6, 8, 7, 7, 7, 6, 6, 7, 7, 7, 7, + 4, 4, 5, 5, 5,13, 4, 8, 8, 5, 5,13, 6, 8, 8, 8, 7, 7, + 6, 6, 8, 7, 7, 7, 6, 6, 7, 7, 7, 7,14,14, 7, 7, 7, 7, + 12,12, 5, 5,13,13,12,12, 5, 5,13,13, 6, 6, 8, 7, 7, 7, + 6, 6, 7, 7, 7, 7,14,14, 7, 7, 7, 7,14,14, 7, 7, 7,15, + 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 0 }; + static void read_settings(void) { const char *str; int old_colors = term_use_colors; + int old_colors24 = term_use_colors24; int old_type = term_type; /* set terminal type */ @@ -133,7 +152,14 @@ static void read_settings(void) term_use_colors = settings_get_bool("colors") && (force_colors || term_has_colors()); - if (term_use_colors != old_colors) +#ifdef TERM_TRUECOLOR + term_use_colors24 = settings_get_bool("colors_ansi_24bit") && + (force_colors || term_has_colors()); +#else + term_use_colors24 = FALSE; +#endif + + if (term_use_colors != old_colors || term_use_colors24 != old_colors24) irssi_redraw(); } @@ -149,6 +175,12 @@ void term_common_init(void) force_colors = FALSE; term_use_colors = term_has_colors() && settings_get_bool("colors"); +#ifdef TERM_TRUECOLOR + settings_add_bool("lookandfeel", "colors_ansi_24bit", FALSE); + term_use_colors24 = term_has_colors() && settings_get_bool("colors_ansi_24bit"); +#else + term_use_colors24 = FALSE; +#endif read_settings(); if (g_get_charset(&dummy)) { diff --git a/src/fe-text/term.h b/src/fe-text/term.h index 5a40d4b2..e5f66644 100644 --- a/src/fe-text/term.h +++ b/src/fe-text/term.h @@ -3,30 +3,19 @@ typedef struct _TERM_WINDOW TERM_WINDOW; -/* text attributes */ - - #define FG_MASK ( 0x00ff ) #define BG_MASK ( 0xff00 ) +#define BG_SHIFT 8 +/* text attributes */ #define ATTR_RESETFG ( 0x010000 ) #define ATTR_RESETBG ( 0x020000 ) #define ATTR_BOLD ( 0x040000 ) -#define ATTR_BLINK ( 0x080000 ) +#define ATTR_BLINK ( 0x080000 ) #define ATTR_UNDERLINE ( 0x100000 ) #define ATTR_REVERSE ( 0x200000 ) - -/* can also mean default color, probably. */ -#define ATTR_COLOR_UNDEFINED ( -1 ) - -#define EXT_COLOR_BLACK ( 0 ) -#define EXT_COLOR_RED ( 1 ) -#define EXT_COLOR_GREEN ( 2 ) -#define EXT_COLOR_YELLOW ( 3 ) -#define EXT_COLOR_BLUE ( 4 ) -#define EXT_COLOR_MAGENTA ( 5 ) -#define EXT_COLOR_CYAN ( 6 ) -#define EXT_COLOR_WHITE ( 7 ) +#define ATTR_FGCOLOR24 ( 0x400000 ) +#define ATTR_BGCOLOR24 ( 0x800000 ) #define ATTR_RESET (ATTR_RESETFG|ATTR_RESETBG) @@ -42,6 +31,8 @@ typedef guint32 unichar; extern TERM_WINDOW *root_window; extern int term_width, term_height; extern int term_use_colors, term_type; +extern int term_use_colors24; +extern int term_color256map[]; /* Initialize / deinitialize terminal */ int term_init(void); @@ -80,10 +71,9 @@ void term_window_clear(TERM_WINDOW *window); /* Scroll window up/down */ void term_window_scroll(TERM_WINDOW *window, int count); +void term_set_color2(TERM_WINDOW *window, int col, unsigned int fgcol24, unsigned int bgcol24); void term_set_color(TERM_WINDOW *window, int col); -void term_set_extended_color(TERM_WINDOW *window, int fg, int bg); - void term_move(TERM_WINDOW *window, int x, int y); void term_addch(TERM_WINDOW *window, char chr); void term_add_unichar(TERM_WINDOW *window, unichar chr); diff --git a/src/fe-text/terminfo-core.c b/src/fe-text/terminfo-core.c index 753cf928..ba9256b4 100644 --- a/src/fe-text/terminfo-core.c +++ b/src/fe-text/terminfo-core.c @@ -331,16 +331,29 @@ static void _set_standout(TERM_REC *term, int set) tput(tparm(set ? term->TI_smso : term->TI_rmso)); } +inline static int color256(const TERM_REC *term, const int color) { + if (color < term->TI_colors) + return color; + + if (color < 16) + return color % term->TI_colors; + + if (color < 256) + return term_color256map[color] % term->TI_colors; + + return color % term->TI_colors; +} + /* Change foreground color */ static void _set_fg(TERM_REC *term, int color) { - tput(tparm(term->TI_fg[color % term->TI_colors])); + tput(tparm(term->TI_fg[color256(term, color)])); } /* Change background color */ static void _set_bg(TERM_REC *term, int color) { - tput(tparm(term->TI_bg[color % term->TI_colors])); + tput(tparm(term->TI_bg[color256(term, color)])); } /* Beep */ @@ -519,19 +532,19 @@ static int term_setup(TERM_REC *term) term_env = getenv("TERM"); if (term_env == NULL) { - g_message( "TERM environment not set\n"); + fprintf(stderr, "TERM environment not set\n"); return 0; } #ifdef HAVE_TERMINFO if (setupterm(term_env, 1, &err) != 0) { - g_message( "setupterm() failed for TERM=%s: %d\n", term_env, err); + fprintf(stderr, "setupterm() failed for TERM=%s: %d\n", term_env, err); return 0; } #else if (tgetent(term->buffer1, term_env) < 1) { - g_message( "Termcap not found for TERM=%s\n", term_env); + fprintf(stderr, "Termcap not found for TERM=%s\n", term_env); return 0; } #endif @@ -544,7 +557,7 @@ static int term_setup(TERM_REC *term) else if (term->TI_hpa && term->TI_vpa) term->move = _move_pa; else { - g_message( "Terminal doesn't support cursor movement\n"); + fprintf(stderr, "Terminal doesn't support cursor movement\n"); return 0; } term->move_relative = _move_relative; @@ -561,7 +574,7 @@ static int term_setup(TERM_REC *term) else if (term->scroll == NULL && (term->TI_il1 && term->TI_dl1)) term->scroll = _scroll_line_1; else if (term->scroll == NULL) { - g_message( "Terminal doesn't support scrolling\n"); + fprintf(stderr, "Terminal doesn't support scrolling\n"); return 0; } @@ -578,7 +591,7 @@ static int term_setup(TERM_REC *term) /* we could do this by line inserts as well, but don't bother - if some terminal has insert line it most probably has delete line as well, if not a regular clear screen */ - g_message( "Terminal doesn't support clearing screen\n"); + fprintf(stderr, "Terminal doesn't support clearing screen\n"); return 0; } @@ -586,7 +599,7 @@ static int term_setup(TERM_REC *term) if (term->TI_el) term->clrtoeol = _clrtoeol; else { - g_message( "Terminal doesn't support clearing to end of line\n"); + fprintf(stderr, "Terminal doesn't support clearing to end of line\n"); return 0; } diff --git a/src/fe-text/terminfo-core.h b/src/fe-text/terminfo-core.h index cd851198..9e2b76d5 100644 --- a/src/fe-text/terminfo-core.h +++ b/src/fe-text/terminfo-core.h @@ -16,8 +16,6 @@ #define terminfo_set_bold() current_term->set_bold(current_term) #define terminfo_set_uline(set) current_term->set_uline(current_term, set) #define terminfo_set_standout(set) current_term->set_standout(current_term, set) -// new -#define terminfo_set_blink() current_term->set_blink(current_term) #define terminfo_is_colors_set(term) (term->TI_fg != NULL) #define terminfo_beep(term) current_term->beep(current_term) diff --git a/src/fe-text/textbuffer-view.c b/src/fe-text/textbuffer-view.c index 78509151..81deaf54 100644 --- a/src/fe-text/textbuffer-view.c +++ b/src/fe-text/textbuffer-view.c @@ -104,65 +104,78 @@ static void textbuffer_cache_unref(TEXT_BUFFER_CACHE_REC *cache) textbuffer_cache_destroy(cache); } -#define FGATTR (ATTR_NOCOLORS | ATTR_RESETFG | 0xff) -#define BGATTR (ATTR_NOCOLORS | ATTR_RESETBG | 0xff00) +#define FGATTR (ATTR_NOCOLORS | ATTR_RESETFG | FG_MASK | ATTR_FGCOLOR24) +#define BGATTR (ATTR_NOCOLORS | ATTR_RESETBG | BG_MASK | ATTR_BGCOLOR24) static void update_cmd_color(unsigned char cmd, int *color) { - static int next_color_bg = 0; - g_message( "update_cmd_color() color: 0x%08x, cmd: 0x%08x\n", *color, cmd); - - if (cmd & 0x80) { /* cmd message */ - switch (cmd) { - + if ((cmd & 0x80) == 0) { + if (cmd & LINE_COLOR_BG) { + /* set background color */ + *color &= FGATTR; + *color &= ~ATTR_FGCOLOR24; + if ((cmd & LINE_COLOR_DEFAULT) == 0) + *color |= (cmd & 0x0f) << BG_SHIFT; + else { + *color = (*color & FGATTR) | ATTR_RESETBG; + } + } else { + /* set foreground color */ + *color &= BGATTR; + *color &= ~ATTR_BGCOLOR24; + if ((cmd & LINE_COLOR_DEFAULT) == 0) + *color |= cmd & 0x0f; + else { + *color = (*color & BGATTR) | ATTR_RESETFG; + } + } + } else switch (cmd) { case LINE_CMD_UNDERLINE: *color ^= ATTR_UNDERLINE; - g_message( "update_cmd_color() toggle underline 0x%08d\n", *color); - break; case LINE_CMD_REVERSE: - *color ^= ATTR_REVERSE; - g_message( "update_cmd_color() toggle reverse 0x%08d\n", *color); - break; case LINE_CMD_BLINK: - *color ^= ATTR_BLINK; - g_message( "update_cmd_color() toggle blink 0x%08d\n", *color); - break; case LINE_CMD_BOLD: - *color ^= ATTR_BOLD; - g_message( "update_cmd_color() toggle bold 0x%08d\n", *color); - break; case LINE_CMD_COLOR0: *color &= BGATTR; - g_message( "update_cmd_color() set BGATTR RESET 0x%08d\n", *color); - - break; - case LINE_CMD_SELECT_FG: - next_color_bg = 0; - g_message( "update_cmd_color() Next color will be FG\n"); - - break; - - case LINE_CMD_SELECT_BG: - next_color_bg = 1; - g_message( "update_cmd_color() Next color will be BG\n"); + *color &= ~ATTR_FGCOLOR24; break; } - } else { - if (next_color_bg == 1) { - *color = cmd << 8; - } else { - *color = cmd; - } - } } +#ifdef TERM_TRUECOLOR +static void unformat_24bit_line_color(const unsigned char **ptr, int off, int *flags, int *fg, int *bg) +{ + unsigned int color; + unsigned char rgbx[4]; + unsigned int i; + for (i = 0; i < 4; ++i) { + rgbx[i] = (*ptr)[i + off]; + } + rgbx[3] -= 0x20; + *ptr += 4; + for (i = 0; i < 3; ++i) { + if (rgbx[3] & (0x10 << i)) + rgbx[i] -= 0x20; + } + color = rgbx[0] << 16 | rgbx[1] << 8 | rgbx[2]; + if (rgbx[3] & 0x1) { + *flags = (*flags & FGATTR) | ATTR_BGCOLOR24; + *bg = color; + } + else { + *flags = (*flags & BGATTR) | ATTR_FGCOLOR24; + *fg = color; + } +} +#endif + static inline unichar read_unichar(const unsigned char *data, const unsigned char **next, int *width) { unichar chr = g_utf8_get_char_validated(data, -1); @@ -188,6 +201,7 @@ view_update_line_cache(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line) unsigned char cmd; const unsigned char *ptr, *next_ptr, *last_space_ptr; int xpos, pos, indent_pos, last_space, last_color, color, linecount; + int last_bg24, last_fg24, bg24, fg24; int char_width; g_return_val_if_fail(line->text != NULL, NULL); @@ -221,7 +235,18 @@ view_update_line_cache(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line) /* set indentation position here - don't do it if we're too close to right border */ if (xpos < view->width-5) indent_pos = xpos; - } else + } else if (cmd == LINE_COLOR_EXT) { + color &= ~ATTR_FGCOLOR24; + color = (color & BGATTR) | *ptr++; + } else if (cmd == LINE_COLOR_EXT_BG) { + color &= ~ATTR_BGCOLOR24; + color = (color & FGATTR) | (*ptr++ << BG_SHIFT); + } +#ifdef TERM_TRUECOLOR + else if (cmd == LINE_COLOR_24) + unformat_24bit_line_color(&ptr, 0, &color, &fg24, &bg24); +#endif + else update_cmd_color(cmd, &color); continue; } @@ -253,7 +278,7 @@ view_update_line_cache(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line) sub = g_new0(LINE_CACHE_SUB_REC, 1); if (last_space > indent_pos && last_space > 10) { /* go back to last space */ - color = last_color; + color = last_color; fg24 = last_fg24; bg24 = last_bg24; ptr = last_space_ptr; while (*ptr == ' ') ptr++; } else if (view->longword_noindent) { @@ -266,6 +291,9 @@ view_update_line_cache(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line) sub->indent = xpos; sub->indent_func = indent_func; sub->color = color; +#ifdef TERM_TRUECOLOR + sub->fg24 = fg24; sub->bg24 = bg24; +#endif lines = g_slist_append(lines, sub); linecount++; @@ -277,11 +305,11 @@ view_update_line_cache(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line) if (!view->utf8 && char_width > 1) { last_space = xpos; last_space_ptr = next_ptr; - last_color = color; + last_color = color; last_fg24 = fg24; last_bg24 = bg24; } else if (*ptr == ' ') { last_space = xpos; last_space_ptr = ptr; - last_color = color; + last_color = color; last_fg24 = fg24; last_bg24 = bg24; } xpos += char_width; @@ -359,7 +387,7 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, const unsigned char *text, *end, *text_newline; unsigned char *tmp; unichar chr; - int xpos, color, drawcount, first, need_move, need_clrtoeol, char_width; + int xpos, color, fg24, bg24, drawcount, first, need_move, need_clrtoeol, char_width; if (view->dirty) /* don't bother drawing anything - redraw is coming */ return 0; @@ -373,7 +401,6 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, xpos = drawcount = 0; first = TRUE; text_newline = text = subline == 0 ? line->text : cache->lines[subline-1].start; - g_message( "view_line_draw()\n"); for (;;) { if (text == text_newline) { if (need_clrtoeol && xpos < term_width) { @@ -395,6 +422,10 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, if (indent_func == NULL) xpos = cache->lines[subline-1].indent; color = cache->lines[subline-1].color; +#ifdef TERM_TRUECOLOR + fg24 = cache->lines[subline-1].fg24; + bg24 = cache->lines[subline-1].bg24; +#endif } else { indent_func = NULL; } @@ -412,12 +443,10 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, xpos = indent_func(view, line, ypos); } - if (need_move || xpos > 0) { + if (need_move || xpos > 0) term_move(view->window, xpos, ypos); - } - g_message( "view_line_draw(): color: 0x%08x\n", color); - term_set_color(view->window, color); + term_set_color2(view->window, color, fg24, bg24); if (subline == cache->count-1) { text_newline = NULL; @@ -443,11 +472,17 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, text = tmp; continue; } else { - update_cmd_color(*text, &color); - g_message( "post update_cmd_color: 0x%08x\n", - color); - - term_set_color(view->window, color); + if (*text == LINE_COLOR_EXT) + color = (color & BGATTR & ~ATTR_FGCOLOR24) | *++text; + else if (*text == LINE_COLOR_EXT_BG) + color = (color & FGATTR & ~ATTR_BGCOLOR24) | (*++text << BG_SHIFT); +#ifdef TERM_TRUECOLOR + else if (*text == LINE_COLOR_24) + unformat_24bit_line_color(&text, 1, &color, &fg24, &bg24); +#endif + else + update_cmd_color(*text, &color); + term_set_color2(view->window, color, fg24, bg24); } text++; continue; @@ -476,13 +511,9 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, term_addch(view->window, *text); } else { /* low-ascii */ - g_message( "printing inverse char %c\n", - (chr & 127)+'A'-1); term_set_color(view->window, ATTR_RESET|ATTR_REVERSE); term_addch(view->window, (chr & 127)+'A'-1); - g_message( "setting color back to: 0x%08x\n", - color); - term_set_color(view->window, color); + term_set_color2(view->window, color, fg24, bg24); } } text = end; diff --git a/src/fe-text/textbuffer-view.h b/src/fe-text/textbuffer-view.h index 46da808e..48cba093 100644 --- a/src/fe-text/textbuffer-view.h +++ b/src/fe-text/textbuffer-view.h @@ -15,6 +15,9 @@ typedef struct { int indent; INDENT_FUNC indent_func; int color; +#ifdef TERM_TRUECOLOR + int fg24, bg24; +#endif /* first word in line belong to the end of the last word in previous line */ diff --git a/src/fe-text/textbuffer.c b/src/fe-text/textbuffer.c index 35f52a16..ad1b06f6 100644 --- a/src/fe-text/textbuffer.c +++ b/src/fe-text/textbuffer.c @@ -39,8 +39,8 @@ TEXT_BUFFER_REC *textbuffer_create(void) buffer = g_slice_new0(TEXT_BUFFER_REC); buffer->last_eol = TRUE; - buffer->last_fg = LINE_COLOR_DEFAULT; - buffer->last_bg = LINE_COLOR_DEFAULT | LINE_COLOR_BG; + buffer->last_fg = -1; + buffer->last_bg = -1; return buffer; } @@ -148,6 +148,7 @@ static void text_chunk_append(TEXT_BUFFER_REC *buffer, { TEXT_CHUNK_REC *chunk; int left; + int i; if (len == 0) return; @@ -166,8 +167,12 @@ static void text_chunk_append(TEXT_BUFFER_REC *buffer, } } - if (left > 0 && data[left-1] == 0) - left--; /* don't split the commands */ + for (i = 5; i > 0; --i) { + if (left >= i && data[left-i] == 0) { + left -= i; /* don't split the commands */ + break; + } + } memcpy(chunk->buffer + chunk->pos, data, left); chunk->pos += left; @@ -238,84 +243,92 @@ int textbuffer_line_exists_after(LINE_REC *line, LINE_REC *search) return FALSE; } +#ifdef TERM_TRUECOLOR +static void format_24bit_line_color(unsigned char *out, int *pos, int bg, unsigned int color) +{ + unsigned char rgb[] = { color >> 16, color >> 8, color }; + unsigned char x = bg ? 0x1 : 0; + unsigned int i; + out[(*pos)++] = LINE_COLOR_24; + for (i = 0; i < 3; ++i) { + if (rgb[i] > 0x20) + out[(*pos)++] = rgb[i]; + else { + out[(*pos)++] = 0x20 + rgb[i]; + x |= 0x10 << i; + } + } + out[(*pos)++] = 0x20 + x; +} +#endif + void textbuffer_line_add_colors(TEXT_BUFFER_REC *buffer, LINE_REC **line, int fg, int bg, int flags) { - unsigned char data[20]; - memset(data, 0, 20); - - int pos = 0; - int i = 0; - /* get the fg & bg command chars */ - /* TODO: These things are adding additional data to colours. */ - g_message( "TBLAC1: fg: 0x%08x, bg: 0x%08x, flags: 0x%08x, last_flags: 0x%08x\n", - fg, bg, flags, buffer->last_flags); + unsigned char data[22]; + int pos; - /* fg = fg < 0 ? LINE_COLOR_DEFAULT : fg & 0xff; */ - /* bg = LINE_COLOR_BG | (bg < 0 ? LINE_COLOR_DEFAULT : bg & 0xff); */ - g_message( "TBLAC2: fg: 0x%02x, bg: 0x%02x\n", fg, bg); - - if (fg != buffer->last_fg) { + pos = 0; + if (fg != buffer->last_fg + || (flags & GUI_PRINT_FLAG_COLOR_24_FG) != (buffer->last_flags & GUI_PRINT_FLAG_COLOR_24_FG)) { buffer->last_fg = fg; data[pos++] = 0; - data[pos++] = LINE_CMD_SELECT_FG; - data[pos++] = 0; - data[pos++] = fg == 0 ? LINE_CMD_COLOR0 : fg; - g_message( "TBLAC2: fg: data[%d}=%d(0x%02x)\n", pos-1,data[pos-1],data[pos-1]); - +#ifdef TERM_TRUECOLOR + if (flags & GUI_PRINT_FLAG_COLOR_24_FG) + format_24bit_line_color(data, &pos, 0, fg); + else +#endif + if (fg < 0) + data[pos++] = LINE_COLOR_DEFAULT; + else if (fg < 16) + data[pos++] = fg == 0 ? LINE_CMD_COLOR0 : fg; + else if (fg < 256) { + data[pos++] = LINE_COLOR_EXT; + data[pos++] = fg; + } } - if (bg != buffer->last_bg) { + if (bg != buffer->last_bg + || (flags & GUI_PRINT_FLAG_COLOR_24_BG) != (buffer->last_flags & GUI_PRINT_FLAG_COLOR_24_BG)) { buffer->last_bg = bg; data[pos++] = 0; - data[pos++] = LINE_CMD_SELECT_BG; - data[pos++] = 0; - data[pos++] = bg; - g_message( "TBLAC2: bg: data[%d}=%d(0x%02x)\n", pos-1,data[pos-1],data[pos-1]); - +#ifdef TERM_TRUECOLOR + if (flags & GUI_PRINT_FLAG_COLOR_24_BG) + format_24bit_line_color(data, &pos, 1, bg); + else +#endif + if (bg < 0) + data[pos++] = LINE_COLOR_BG | LINE_COLOR_DEFAULT; + else if (bg < 16) + data[pos++] = LINE_COLOR_BG | bg; + else if (bg < 256) { + data[pos++] = LINE_COLOR_EXT_BG; + data[pos++] = bg; + } } if ((flags & GUI_PRINT_FLAG_UNDERLINE) != (buffer->last_flags & GUI_PRINT_FLAG_UNDERLINE)) { data[pos++] = 0; data[pos++] = LINE_CMD_UNDERLINE; - g_message( "TBLAC2: underline: data[%d}=%d(0x%02x)\n", pos-1,data[pos-1],data[pos-1]); - } if ((flags & GUI_PRINT_FLAG_REVERSE) != (buffer->last_flags & GUI_PRINT_FLAG_REVERSE)) { data[pos++] = 0; data[pos++] = LINE_CMD_REVERSE; - g_message( "TBLAC2: reverse: data[%d}=%d(0x%02x)\n", pos-1,data[pos-1],data[pos-1]); - } if ((flags & GUI_PRINT_FLAG_BLINK) != (buffer->last_flags & GUI_PRINT_FLAG_BLINK)) { data[pos++] = 0; data[pos++] = LINE_CMD_BLINK; - g_message( "TBLAC2: blink: data[%d}=%d(0x%02x)\n", pos-1,data[pos-1],data[pos-1]); - } if ((flags & GUI_PRINT_FLAG_BOLD) != (buffer->last_flags & GUI_PRINT_FLAG_BOLD)) { data[pos++] = 0; data[pos++] = LINE_CMD_BOLD; - g_message( "TBLAC2: bold: data[%d}=%d(0x%02x)\n", pos,data[pos-1],data[pos-1]); - } if (flags & GUI_PRINT_FLAG_INDENT) { data[pos++] = 0; data[pos++] = LINE_CMD_INDENT; - g_message( "TBLAC2: indent: data[%d}=%d(0x%02x)\n", pos-1,data[pos-1],data[pos-1]); - } - g_message( "TBLAC data:\n"); - - for (i=0; i < 20; i++) { - g_message( "%02x\n", data[i]); - } - g_message( "\n"); - - if (pos > 0) { - g_message( "calling textbuffer_insert()\n"); + if (pos > 0) *line = textbuffer_insert(buffer, *line, data, pos, NULL); - } buffer->last_flags = flags; } @@ -351,14 +364,11 @@ LINE_REC *textbuffer_insert(TEXT_BUFFER_REC *buffer, LINE_REC *insert_after, data[len-2] == 0 && data[len-1] == LINE_CMD_EOL; if (buffer->last_eol) { - buffer->last_fg = LINE_COLOR_DEFAULT; - buffer->last_bg = LINE_COLOR_DEFAULT | LINE_COLOR_BG; + buffer->last_fg = -1; + buffer->last_bg = -1; buffer->last_flags = 0; } - g_message( "line created: '%s' %d\n", line->text, line->info.time); - g_message( "Buffer %p\n", buffer); - return line; } @@ -413,22 +423,18 @@ void textbuffer_remove_all_lines(TEXT_BUFFER_REC *buffer) static void set_color(GString *str, int cmd) { - int color = ATTR_COLOR_UNDEFINED; + int color = -1; if (!(cmd & LINE_COLOR_DEFAULT)) - color = (cmd & 0xff) + '0'; - - g_message( "textbuffer.c:set_color color: %d (%02x)\n", color, color); + color = (cmd & 0x0f)+'0'; if ((cmd & LINE_COLOR_BG) == 0) { /* change foreground color */ - g_string_append_printf(str, "%c%c%c", - LINE_FORMAT_MARKER, + g_string_append_printf(str, "\004%c%c", color, FORMAT_COLOR_NOCHANGE); } else { /* change background color */ - g_string_append_printf(str, "%c%c%c", - LINE_FORMAT_MARKER, + g_string_append_printf(str, "\004%c%c", FORMAT_COLOR_NOCHANGE, color); } } @@ -467,13 +473,17 @@ void textbuffer_line2text(LINE_REC *line, int coloring, GString *str) if (!coloring) { /* no colors, skip coloring commands */ + if (cmd == LINE_COLOR_EXT || cmd == LINE_COLOR_EXT_BG) + ptr++; +#ifdef TERM_TRUECOLOR + else if (cmd == LINE_COLOR_24) + ptr+=4; +#endif + continue; } - /* these magic numbers correspond with some of IS_COLOR_CODE in - * formats.c:843 (31 and 22) */ - - if ((cmd & 0x80) == 0) { + if ((cmd & LINE_CMD_EOL) == 0) { /* set color */ set_color(str, cmd); } else switch (cmd) { @@ -499,6 +509,17 @@ void textbuffer_line2text(LINE_REC *line, int coloring, GString *str) g_string_append_printf(str, "\004%c", FORMAT_STYLE_INDENT); break; + case LINE_COLOR_EXT: + format_ext_color(str, 0, *ptr++); + break; + case LINE_COLOR_EXT_BG: + format_ext_color(str, 1, *ptr++); + break; +#ifdef TERM_TRUECOLOR + case LINE_COLOR_24: + g_string_append_printf(str, "\004%c", FORMAT_COLOR_24); + break; +#endif } } } diff --git a/src/fe-text/textbuffer.h b/src/fe-text/textbuffer.h index a94a06af..6123ba7a 100644 --- a/src/fe-text/textbuffer.h +++ b/src/fe-text/textbuffer.h @@ -8,20 +8,20 @@ #define LINE_COLOR_BG 0x20 #define LINE_COLOR_DEFAULT 0x10 -/* command values (see _LINE_REC protocol) */ enum { LINE_CMD_EOL=0x80, /* line ends here */ LINE_CMD_CONTINUE, /* line continues in next block */ - /* TODO: no longer needed */ LINE_CMD_COLOR0, /* change to black, would be same as \0\0 but it breaks things.. */ LINE_CMD_UNDERLINE, /* enable/disable underlining */ LINE_CMD_REVERSE, /* enable/disable reversed text */ LINE_CMD_INDENT, /* if line is split, indent it at this position */ LINE_CMD_BLINK, /* enable/disable blink */ LINE_CMD_BOLD, /* enable/disable bold */ - LINE_CMD_SELECT_FG, - LINE_CMD_SELECT_BG - + LINE_COLOR_EXT, /* extended color */ + LINE_COLOR_EXT_BG, /* extended bg */ +#ifdef TERM_TRUECOLOR + LINE_COLOR_24, /* 24bit color */ +#endif }; typedef struct { @@ -29,7 +29,6 @@ typedef struct { time_t time; } LINE_INFO_REC; -/* TODO: fixme. */ typedef struct _LINE_REC { /* Text in the line. \0 means that the next char will be a color or command. @@ -44,28 +43,6 @@ typedef struct _LINE_REC { DO NOT ADD BLACK WITH \0\0 - this will break things. Use LINE_CMD_COLOR0 instead. */ - - - /* NEW COLOUR PROTOCOL: - - 0x00 - indicates command or colour. - 0x01 - command follows (1 byte) - -- following may be omitted if LINE_CMD_USE_DEFAULT_[FB}G is set. - 0x02 - BG colour follows (1 byte) - 0x04 - FG colour follows (1 byte) - - - Things that will need to be fixed: - - * textbuffer-view.c:update_cmd_color() - * textbuffer-view.c:view_line_draw() - * textbuffer-view.c:view_update_line_cache() - - * textbuffer.c:textbuffer_line2text() - * textbuffer.c:mark_temp_eol macro - - * gui-printtext.c ? - */ struct _LINE_REC *prev, *next; unsigned char *text; diff --git a/src/perl/ui/Themes.xs b/src/perl/ui/Themes.xs index dc5f6272..ab7c1909 100644 --- a/src/perl/ui/Themes.xs +++ b/src/perl/ui/Themes.xs @@ -241,8 +241,11 @@ PPCODE: if (flags == 0) { ret = theme_format_expand(theme, format); } else { - ret = theme_format_expand_data(theme, (const char **) &format, 'n', 'n', - NULL, NULL, EXPAND_FLAG_ROOT | flags); + theme_rm_col reset; + strcpy(reset.m, "n"); + ret = theme_format_expand_data(theme, (const char **) &format, + reset, reset, NULL, NULL, + EXPAND_FLAG_ROOT | flags); } XPUSHs(sv_2mortal(new_pv(ret))); g_free_not_null(ret); -- cgit v1.2.3