diff options
author | Alexander Færøy <ahf@0x90.dk> | 2014-07-02 23:17:36 +0200 |
---|---|---|
committer | Alexander Færøy <ahf@0x90.dk> | 2014-07-02 23:17:36 +0200 |
commit | fd3676e40783e7a24ace7cb652dea72411737fdd (patch) | |
tree | 9b87475b59130900da5c15cc92040b7f94191b1a /src | |
parent | 0a221742649cf39db96da69dead0292fd38c7b66 (diff) | |
parent | 96a292d40e7f6fe505c4a0f686d35132ffac8208 (diff) | |
download | irssi-fd3676e40783e7a24ace7cb652dea72411737fdd.zip |
Merge pull request #48 from ailin-nemui/256-colour-history
256 colour support for Irssi
Diffstat (limited to 'src')
-rw-r--r-- | src/fe-common/core/fe-windows.c | 57 | ||||
-rw-r--r-- | src/fe-common/core/fe-windows.h | 2 | ||||
-rw-r--r-- | src/fe-common/core/formats.c | 346 | ||||
-rw-r--r-- | src/fe-common/core/formats.h | 13 | ||||
-rw-r--r-- | src/fe-common/core/printtext.c | 12 | ||||
-rw-r--r-- | src/fe-common/core/themes.c | 121 | ||||
-rw-r--r-- | src/fe-common/core/themes.h | 8 | ||||
-rw-r--r-- | src/fe-text/gui-printtext.c | 49 | ||||
-rw-r--r-- | src/fe-text/statusbar.c | 4 | ||||
-rw-r--r-- | src/fe-text/term-curses.c | 21 | ||||
-rw-r--r-- | src/fe-text/term-terminfo.c | 72 | ||||
-rw-r--r-- | src/fe-text/term.c | 34 | ||||
-rw-r--r-- | src/fe-text/term.h | 21 | ||||
-rw-r--r-- | src/fe-text/terminfo-core.c | 17 | ||||
-rw-r--r-- | src/fe-text/textbuffer-view.c | 82 | ||||
-rw-r--r-- | src/fe-text/textbuffer-view.h | 3 | ||||
-rw-r--r-- | src/fe-text/textbuffer.c | 96 | ||||
-rw-r--r-- | src/fe-text/textbuffer.h | 5 | ||||
-rw-r--r-- | src/perl/ui/Themes.xs | 7 |
19 files changed, 846 insertions, 124 deletions
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 f2a82030..770caaa1 100644 --- a/src/fe-common/core/formats.c +++ b/src/fe-common/core/formats.c @@ -101,10 +101,88 @@ 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; + char *p, fmt; + /* storage for numerical parsing code for %x/X formats. */ + int tmp; + unsigned int tmp2; + fmt = **format; switch (fmt) { case '{': @@ -162,6 +240,62 @@ int format_expand_styles(GString *out, const char **format, int *flags) /* code */ format_expand_code(format, out, flags); break; + case 'x': + case 'X': + 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); @@ -195,7 +329,7 @@ int format_expand_styles(GString *out, const char **format, int *flags) return FALSE; } - return TRUE; + return retval; } void format_read_arglist(va_list va, FORMAT_REC *format, @@ -303,6 +437,7 @@ int format_get_length(const char *str) GString *tmp; int len; gboolean utf8; + int adv = 0; g_return_val_if_fail(str != NULL, 0); @@ -313,9 +448,10 @@ int format_get_length(const char *str) while (*str != '\0') { if (*str == '%' && str[1] != '\0') { str++; - if (*str != '%' && - format_expand_styles(tmp, &str, NULL)) { - str++; + if (*str != '%') { + adv = format_expand_styles(tmp, &str, NULL); + str += adv; + if (adv) continue; } @@ -340,7 +476,7 @@ int format_real_length(const char *str, int len) const char *start; const char *oldstr; gboolean utf8; - + int adv = 0; g_return_val_if_fail(str != NULL, 0); g_return_val_if_fail(len >= 0, 0); @@ -351,9 +487,10 @@ int format_real_length(const char *str, int len) while (*str != '\0' && len > 0) { if (*str == '%' && str[1] != '\0') { str++; - if (*str != '%' && - format_expand_styles(tmp, &str, NULL)) { - str++; + if (*str != '%') { + adv = format_expand_styles(tmp, &str, NULL); + str += adv; + if (adv) continue; } @@ -378,6 +515,7 @@ char *format_string_expand(const char *text, int *flags) { GString *out; char code, *ret; + int adv; g_return_val_if_fail(text != NULL, NULL); @@ -388,10 +526,13 @@ char *format_string_expand(const char *text, int *flags) while (*text != '\0') { if (code == '%') { /* color code */ - if (!format_expand_styles(out, &text, flags)) { + 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; } code = 0; } else { @@ -415,6 +556,7 @@ static char *format_get_text_args(TEXT_DEST_REC *dest, GString *out; char code, *ret; int need_free; + int adv; out = g_string_new(NULL); @@ -422,10 +564,13 @@ static char *format_get_text_args(TEXT_DEST_REC *dest, while (*text != '\0') { if (code == '%') { /* color code */ - if (!format_expand_styles(out, &text, &dest->flags)) { + 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; } code = 0; } else if (code == '$') { @@ -716,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; @@ -749,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; } @@ -858,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); @@ -907,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; } @@ -1020,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 6c55a068..037aa424 100644 --- a/src/fe-common/core/formats.h +++ b/src/fe-common/core/formats.h @@ -13,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 @@ -121,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) @@ -132,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 d3653f90..a5eaa38f 100644 --- a/src/fe-common/core/printtext.c +++ b/src/fe-common/core/printtext.c @@ -206,6 +206,7 @@ static char *printtext_get_args(TEXT_DEST_REC *dest, const char *str, { GString *out; char *ret; + int adv; out = g_string_new(NULL); for (; *str != '\0'; str++) { @@ -255,9 +256,12 @@ static char *printtext_get_args(TEXT_DEST_REC *dest, const char *str, break; } default: - if (!format_expand_styles(out, &str, &dest->flags)) { + 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; } break; } @@ -272,6 +276,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++) { @@ -283,9 +288,12 @@ static char *printtext_expand_formats(const char *str, int *flags) if (*++str == '\0') break; - if (!format_expand_styles(out, &str, flags)) { + adv = format_expand_styles(out, &str, flags); + if (!adv) { g_string_append_c(out, '%'); g_string_append_c(out, *str); + } else { + 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 76b116d8..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,21 +152,39 @@ 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) { - /* 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]; - 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 > 15) + if (flags & GUI_PRINT_FLAG_COLOR_24_FG) + *attr |= ATTR_FGCOLOR24; + else if (*fg < 0 || *fg > 255) { *fg = -1; - if (*bg < 0 || *bg > 15) + *attr |= ATTR_RESETFG; + } + 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; if (flags & GUI_PRINT_FLAG_BOLD) *attr |= ATTR_BOLD; if (flags & GUI_PRINT_FLAG_UNDERLINE) *attr |= ATTR_UNDERLINE; @@ -192,9 +217,7 @@ static void sig_gui_print_text(WINDOW_REC *window, void *fgcolor, if (window == NULL) { g_return_if_fail(next_xpos != -1); - attr |= fg >= 0 ? fg : ATTR_RESETFG; - attr |= bg >= 0 ? (bg << 4) : ATTR_RESETBG; - 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))>>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 9dfc0db4..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 <signal.h> +#include <termios.h> +#include <stdio.h> /* 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,15 +297,44 @@ void term_window_scroll(TERM_WINDOW *window, int count) term_lines_empty[window->y+y] = FALSE; } +inline static int term_putchar(int c) +{ + 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); +} + +#define COLOR_RESET UINT_MAX + /* Change active color */ -void term_set_color(TERM_WINDOW *window, int col) +void term_set_color2(TERM_WINDOW *window, int col, unsigned int fgcol24, unsigned int bgcol24) { int set_normal; - int fg = col & 0x0f; - int bg = (col & 0xf0) >> 4; - set_normal = ((col & ATTR_RESETFG) && last_fg != -1) || - ((col & ATTR_RESETBG) && last_bg != -1); + unsigned int fg = (col & ATTR_FGCOLOR24) ? fgcol24 << 8 : (col & FG_MASK); + unsigned int bg = (col & ATTR_BGCOLOR24) ? bgcol24 << 8 : ((col & BG_MASK) >> BG_SHIFT); + + 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 @@ -310,12 +343,12 @@ void term_set_color(TERM_WINDOW *window, int col) } if (set_normal) { - last_fg = last_bg = -1; + last_fg = last_bg = COLOR_RESET; last_attrs = 0; terminfo_set_normal(); } - if (!term_use_colors && (col & 0xf0) != 0) + if (!term_use_colors && bg > 0) col |= ATTR_REVERSE; /* reversed text (use standout) */ @@ -330,12 +363,15 @@ void term_set_color(TERM_WINDOW *window, int col) (fg != 0 || (col & ATTR_RESETFG) == 0)) { if (term_use_colors) { last_fg = fg; - terminfo_set_fg(last_fg); + if (!(fg & 0xff)) + term_set_color_24bit(0, last_fg >> 8); + else + terminfo_set_fg(last_fg); } } /* set background color */ - if (col & 0x80 && window->term->TI_colors == 8) + if (window && (term_color256map[bg&0xff]&8) == window->term->TI_colors) col |= ATTR_BLINK; if (col & ATTR_BLINK) current_term->set_blink(current_term); @@ -344,12 +380,15 @@ void term_set_color(TERM_WINDOW *window, int col) (bg != 0 || (col & ATTR_RESETBG) == 0)) { if (term_use_colors) { last_bg = bg; - terminfo_set_bg(last_bg); + if (!(bg & 0xff)) + term_set_color_24bit(1, last_bg >> 8); + else + terminfo_set_bg(last_bg); } } /* bold */ - if (col & 0x08 && window->term->TI_colors == 8) + if (window && (term_color256map[fg&0xff]&8) == window->term->TI_colors) col |= ATTR_BOLD; if (col & ATTR_BOLD) terminfo_set_bold(); @@ -361,9 +400,16 @@ void term_set_color(TERM_WINDOW *window, int col) } else if (last_attrs & ATTR_UNDERLINE) terminfo_set_uline(FALSE); - last_attrs = col & ~0xff; + /* 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 27174c83..e5f66644 100644 --- a/src/fe-text/term.h +++ b/src/fe-text/term.h @@ -3,13 +3,19 @@ typedef struct _TERM_WINDOW TERM_WINDOW; +#define FG_MASK ( 0x00ff ) +#define BG_MASK ( 0xff00 ) +#define BG_SHIFT 8 + /* text attributes */ -#define ATTR_RESETFG 0x0100 -#define ATTR_RESETBG 0x0200 -#define ATTR_BOLD 0x0400 -#define ATTR_BLINK 0x0800 -#define ATTR_UNDERLINE 0x1000 -#define ATTR_REVERSE 0x2000 +#define ATTR_RESETFG ( 0x010000 ) +#define ATTR_RESETBG ( 0x020000 ) +#define ATTR_BOLD ( 0x040000 ) +#define ATTR_BLINK ( 0x080000 ) +#define ATTR_UNDERLINE ( 0x100000 ) +#define ATTR_REVERSE ( 0x200000 ) +#define ATTR_FGCOLOR24 ( 0x400000 ) +#define ATTR_BGCOLOR24 ( 0x800000 ) #define ATTR_RESET (ATTR_RESETFG|ATTR_RESETBG) @@ -25,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); @@ -63,6 +71,7 @@ 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_move(TERM_WINDOW *window, int x, int y); diff --git a/src/fe-text/terminfo-core.c b/src/fe-text/terminfo-core.c index bddc93e1..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 */ diff --git a/src/fe-text/textbuffer-view.c b/src/fe-text/textbuffer-view.c index c19b9af7..81deaf54 100644 --- a/src/fe-text/textbuffer-view.c +++ b/src/fe-text/textbuffer-view.c @@ -104,8 +104,8 @@ static void textbuffer_cache_unref(TEXT_BUFFER_CACHE_REC *cache) textbuffer_cache_destroy(cache); } -#define FGATTR (ATTR_NOCOLORS | ATTR_RESETFG | 0x0f) -#define BGATTR (ATTR_NOCOLORS | ATTR_RESETBG | 0xf0) +#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) { @@ -113,14 +113,16 @@ static void update_cmd_color(unsigned char cmd, int *color) if (cmd & LINE_COLOR_BG) { /* set background color */ *color &= FGATTR; + *color &= ~ATTR_FGCOLOR24; if ((cmd & LINE_COLOR_DEFAULT) == 0) - *color |= (cmd & 0x0f) << 4; + *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 { @@ -142,10 +144,38 @@ static void update_cmd_color(unsigned char cmd, int *color) break; case LINE_CMD_COLOR0: *color &= BGATTR; + *color &= ~ATTR_FGCOLOR24; break; } } +#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); @@ -171,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); @@ -204,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; } @@ -236,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) { @@ -249,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++; @@ -260,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; @@ -342,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; @@ -377,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; } @@ -397,7 +446,7 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, if (need_move || xpos > 0) term_move(view->window, xpos, ypos); - term_set_color(view->window, color); + term_set_color2(view->window, color, fg24, bg24); if (subline == cache->count-1) { text_newline = NULL; @@ -423,8 +472,17 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, text = tmp; continue; } else { - update_cmd_color(*text, &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; @@ -455,7 +513,7 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, /* low-ascii */ term_set_color(view->window, ATTR_RESET|ATTR_REVERSE); term_addch(view->window, (chr & 127)+'A'-1); - 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 69f5969c..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,26 +243,67 @@ 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]; + unsigned char data[22]; int pos; - /* get the fg & bg command chars */ - fg = fg < 0 ? LINE_COLOR_DEFAULT : fg & 0x0f; - bg = LINE_COLOR_BG | (bg < 0 ? LINE_COLOR_DEFAULT : bg & 0x0f); - pos = 0; - if (fg != buffer->last_fg) { + 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++] = fg == 0 ? LINE_CMD_COLOR0 : fg; +#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++] = bg; +#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)) { @@ -318,8 +364,8 @@ 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; } @@ -427,10 +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; } - if ((cmd & 0x80) == 0) { + if ((cmd & LINE_CMD_EOL) == 0) { /* set color */ set_color(str, cmd); } else switch (cmd) { @@ -456,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 e5d78487..6123ba7a 100644 --- a/src/fe-text/textbuffer.h +++ b/src/fe-text/textbuffer.h @@ -17,6 +17,11 @@ enum { 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_COLOR_EXT, /* extended color */ + LINE_COLOR_EXT_BG, /* extended bg */ +#ifdef TERM_TRUECOLOR + LINE_COLOR_24, /* 24bit color */ +#endif }; typedef struct { 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); |