From 4f78b0dda13c98be3be711d84c17ce12de269780 Mon Sep 17 00:00:00 2001 From: Witold Filipczyk Date: Sat, 19 Aug 2006 23:39:40 +0200 Subject: [PATCH] True color mode. See new konsole. TODO: dump --- Makefile.config.in | 1 + configure.in | 2 + features.conf | 8 +++ src/config/options.inc | 49 +++++++++++++-- src/dialogs/options.c | 26 ++++++-- src/terminal/color.c | 14 +++++ src/terminal/color.h | 4 +- src/terminal/draw.c | 5 +- src/terminal/draw.h | 6 +- src/terminal/screen.c | 138 ++++++++++++++++++++++++++++++++++++++++- 10 files changed, 235 insertions(+), 18 deletions(-) diff --git a/Makefile.config.in b/Makefile.config.in index e7f17b29..f14fa04d 100644 --- a/Makefile.config.in +++ b/Makefile.config.in @@ -155,6 +155,7 @@ CONFIG_SMB = @CONFIG_SMB@ CONFIG_SPIDERMONKEY = @CONFIG_SPIDERMONKEY@ CONFIG_SSL = @CONFIG_SSL@ CONFIG_SYSMOUSE = @CONFIG_SYSMOUSE@ +CONFIG_TRUE_COLOR = @CONFIG_TRUE_COLOR@ CONFIG_URI_REWRITE = @CONFIG_URI_REWRITE@ CONFIG_UTF_8 = @CONFIG_UTF_8@ CONFIG_XBEL_BOOKMARKS = @CONFIG_XBEL_BOOKMARKS@ diff --git a/configure.in b/configure.in index a15a01d5..884f1e49 100644 --- a/configure.in +++ b/configure.in @@ -1239,6 +1239,8 @@ EL_ARG_ENABLE(CONFIG_88_COLORS, 88-colors, [88 colors], EL_ARG_ENABLE(CONFIG_256_COLORS, 256-colors, [256 colors], [ --enable-256-colors enable 256 color support]) +EL_ARG_ENABLE(CONFIG_TRUE_COLOR, true-color, [true color], + [ --enable-true-color enable true color support]) EL_ARG_ENABLE(CONFIG_EXMODE, exmode, [Exmode interface], [ --enable-exmode enable exmode (CLI) interface]) diff --git a/features.conf b/features.conf index 5ee749e4..5b0d9d51 100644 --- a/features.conf +++ b/features.conf @@ -497,6 +497,14 @@ CONFIG_88_COLORS=no CONFIG_256_COLORS=no +### True color +# +# Define to add support for True color. Note that only terminal capable to show +# it is konsole from kdebase-3.5.4. This mode eats a lot of memory. +# +# Default: disabled + +CONFIG_TRUE_COLOR=no ### Ex-mode Interface # diff --git a/src/config/options.inc b/src/config/options.inc index 97b1c9b6..15e80b44 100644 --- a/src/config/options.inc +++ b/src/config/options.inc @@ -636,7 +636,8 @@ static struct option_info config_options_info[] = { * the INIT_OPT_INT macro; that wouldn't be standard C. * And they especially cannot be inside the argument list of N_; * xgettext (GNU gettext-tools) 0.14.3 wouldn't support that. */ -#if defined(CONFIG_88_COLORS) && defined(CONFIG_256_COLORS) + /* FIXME: It's totally brainless --witekfl */ +#if defined(CONFIG_88_COLORS) && defined(CONFIG_256_COLORS) && !defined(CONFIG_TRUE_COLOR) INIT_OPT_INT("document.dump", N_("Color mode"), "color_mode", 0, -1, 3, -1, N_("Color mode for dumps:\n" @@ -645,7 +646,7 @@ static struct option_info config_options_info[] = { "1 is 16 color mode\n" "2 is 88 color mode\n" "3 is 256 color mode")), -#elif defined(CONFIG_88_COLORS) /* && !defined(CONFIG_256_COLORS) */ +#elif defined(CONFIG_88_COLORS) && !defined(CONFIG_256_COLORS) && !defined(CONFIG_TRUE_COLOR) INIT_OPT_INT("document.dump", N_("Color mode"), "color_mode", 0, -1, 2, -1, N_("Color mode for dumps:\n" @@ -653,7 +654,7 @@ static struct option_info config_options_info[] = { "0 is mono mode\n" "1 is 16 color mode\n" "2 is 88 color mode")), -#elif defined(CONFIG_256_COLORS) /* && !defined(CONFIG_88_COLORS) */ +#elif defined(CONFIG_256_COLORS) && !defined(CONFIG_88_COLORS) && !defined(CONFIG_TRUE_COLOR) INIT_OPT_INT("document.dump", N_("Color mode"), "color_mode", 0, -1, 2, -1, N_("Color mode for dumps:\n" @@ -661,15 +662,50 @@ static struct option_info config_options_info[] = { "0 is mono mode\n" "1 is 16 color mode\n" "2 is 256 color mode")), -#else /* !defined(CONFIG_88_COLORS) && !defined(CONFIG_256_COLORS) */ +#elif !defined(CONFIG_88_COLORS) && !defined(CONFIG_256_COLORS) && !defined(CONFIG_TRUE_COLOR) INIT_OPT_INT("document.dump", N_("Color mode"), "color_mode", 0, -1, 1, -1, N_("Color mode for dumps:\n" "-1 is standard dump mode\n" "0 is mono mode\n" "1 is 16 color mode")), +#elif defined(CONFIG_88_COLORS) && defined(CONFIG_256_COLORS) && defined(CONFIG_TRUE_COLOR) + INIT_OPT_INT("document.dump", N_("Color mode"), + "color_mode", 0, -1, 3, -1, + N_("Color mode for dumps:\n" + "-1 is standard dump mode\n" + "0 is mono mode\n" + "1 is 16 color mode\n" + "2 is 88 color mode\n" + "3 is 256 color mode\n" + "4 is true color mode")), +#elif defined(CONFIG_88_COLORS) && !defined(CONFIG_256_COLORS) && defined(CONFIG_TRUE_COLOR) + INIT_OPT_INT("document.dump", N_("Color mode"), + "color_mode", 0, -1, 2, -1, + N_("Color mode for dumps:\n" + "-1 is standard dump mode\n" + "0 is mono mode\n" + "1 is 16 color mode\n" + "2 is 88 color mode\n" + "3 is true color mode\n")), +#elif defined(CONFIG_256_COLORS) && !defined(CONFIG_88_COLORS) && defined(CONFIG_TRUE_COLOR) + INIT_OPT_INT("document.dump", N_("Color mode"), + "color_mode", 0, -1, 2, -1, + N_("Color mode for dumps:\n" + "-1 is standard dump mode\n" + "0 is mono mode\n" + "1 is 16 color mode\n" + "2 is 256 color mode\n" + "3 is true color mode")), +#elif !defined(CONFIG_88_COLORS) && !defined(CONFIG_256_COLORS) && defined(CONFIG_TRUE_COLOR) + INIT_OPT_INT("document.dump", N_("Color mode"), + "color_mode", 0, -1, 1, -1, + N_("Color mode for dumps:\n" + "-1 is standard dump mode\n" + "0 is mono mode\n" + "1 is 16 color mode\n" + "2 is true color mode")), #endif /* !defined(CONFIG_88_COLORS) && !defined(CONFIG_256_COLORS) */ - INIT_OPT_STRING("document.dump", N_("Footer"), "footer", 0, "", N_("Footer string used in dumps. %u is substituted by URL.")), @@ -862,7 +898,8 @@ static struct option_info config_options_info[] = { "output to the terminal. The color modes are:\n" "0 is mono mode, only 2 colors are used\n" "1 is 16 color mode, uses the common ANSI colors\n" - "2 is 256 color mode, uses XTerm RGB codes")), + "2 is 256 color mode, uses XTerm RGB codes\n" + "3 is true color mode, uses konsole RGB codes.")), INIT_OPT_BOOL("terminal._template_", N_("Transparency"), "transparency", 0, 1, diff --git a/src/dialogs/options.c b/src/dialogs/options.c index da341ae0..91111f96 100644 --- a/src/dialogs/options.c +++ b/src/dialogs/options.c @@ -131,14 +131,26 @@ push_save_button(struct dialog_data *dlg_data, struct widget_data *button) return EVENT_PROCESSED; } -#if defined(CONFIG_88_COLORS) && defined(CONFIG_256_COLORS) -#define TERMOPT_WIDGETS_COUNT 21 -#elif defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS) -#define TERMOPT_WIDGETS_COUNT 20 +#if defined(CONFIG_88_COLORS) +#define RADIO_88 1 #else -#define TERMOPT_WIDGETS_COUNT 19 +#define RADIO_88 0 #endif +#if defined(CONFIG_256_COLORS) +#define RADIO_256 1 +#else +#define RADIO_256 0 +#endif + +#if defined(CONFIG_TRUE_COLOR) +#define RADIO_TRUE 1 +#else +#define RADIO_TRUE 0 +#endif + +#define TERMOPT_WIDGETS_COUNT (19 + RADIO_88 + RADIO_256 + RADIO_TRUE) + #define TERM_OPTION_VALUE_SIZE (sizeof(union option_value) * TERM_OPTIONS) void @@ -209,7 +221,9 @@ terminal_options(struct terminal *term, void *xxx, struct session *ses) #ifdef CONFIG_256_COLORS add_dlg_radio(dlg, _("256 colors", term), 2, COLOR_MODE_256, &values[TERM_OPT_COLORS].number); #endif - +#ifdef CONFIG_TRUE_COLOR + add_dlg_radio(dlg, _("true color", term), 2, COLOR_MODE_TRUE_COLOR, &values[TERM_OPT_COLORS].number); +#endif add_dlg_checkbox(dlg, _("Switch fonts for line drawing", term), &values[TERM_OPT_M11_HACK].number); add_dlg_checkbox(dlg, _("Restrict frames in cp850/852", term), &values[TERM_OPT_RESTRICT_852].number); add_dlg_checkbox(dlg, _("Block cursor", term), &values[TERM_OPT_BLOCK_CURSOR].number); diff --git a/src/terminal/color.c b/src/terminal/color.c index aaeb69b9..2ecdae68 100644 --- a/src/terminal/color.c +++ b/src/terminal/color.c @@ -325,6 +325,16 @@ set_term_color(struct screen_char *schar, struct color_pair *pair, /* TODO: Handle decrease lightness by converting to * hue-ligthness-saturation color model */ break; +#endif +#ifdef CONFIG_TRUE_COLOR + case COLOR_MODE_TRUE_COLOR: + schar->color[0] = (pair->foreground >> 16) & 255; /* r */ + schar->color[1] = (pair->foreground >> 8) & 255; /* g */ + schar->color[2] = pair->foreground & 255; /* b */ + schar->color[3] = (pair->background >> 16) & 255; /* r */ + schar->color[4] = (pair->background >> 8) & 255; /* g */ + schar->color[5] = pair->background & 255; /* b */ + return; #endif case COLOR_MODE_DUMP: return; @@ -371,6 +381,10 @@ set_term_color(struct screen_char *schar, struct color_pair *pair, TERM_COLOR_FOREGROUND(schar->color) = fg; TERM_COLOR_BACKGROUND(schar->color) = bg; break; +#endif +#ifdef CONFIG_TRUE_COLOR + case COLOR_MODE_TRUE_COLOR: + return; #endif case COLOR_MODE_MONO: case COLOR_MODE_16: diff --git a/src/terminal/color.h b/src/terminal/color.h index e72066d1..527454ff 100644 --- a/src/terminal/color.h +++ b/src/terminal/color.h @@ -51,7 +51,9 @@ enum color_mode { #ifdef CONFIG_256_COLORS COLOR_MODE_256, #endif - +#ifdef CONFIG_TRUE_COLOR + COLOR_MODE_TRUE_COLOR, +#endif COLOR_MODES, /* XXX: Keep last */ }; diff --git a/src/terminal/draw.c b/src/terminal/draw.c index 774f166e..ea5b0d0a 100644 --- a/src/terminal/draw.c +++ b/src/terminal/draw.c @@ -21,8 +21,9 @@ int_bounds(&(x), 0, (term)->width - 1); \ int_bounds(&(y), 0, (term)->height - 1); \ } while (0) - -#if defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS) +#if defined(CONFIG_TRUE_COLOR) +#define clear_screen_char_color(schar) do { memset((schar)->color, 0, 6); } while (0) +#elif defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS) #define clear_screen_char_color(schar) do { memset((schar)->color, 0, 2); } while (0) #else #define clear_screen_char_color(schar) do { (schar)->color[0] = 0; } while (0) diff --git a/src/terminal/draw.h b/src/terminal/draw.h index fcb6be18..75f1bdae 100644 --- a/src/terminal/draw.h +++ b/src/terminal/draw.h @@ -30,8 +30,12 @@ struct screen_char { /* Attributes are screen_char_attr bits. */ unsigned char attr; +#if defined(CONFIG_TRUE_COLOR) + /* 0, 1, 2 - rgb foreground, + 3, 4, 5 - rgb background */ + unsigned char color[6]; /* The encoded fore- and background color. */ -#if defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS) +#elif defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS) unsigned char color[2]; #else unsigned char color[1]; diff --git a/src/terminal/screen.c b/src/terminal/screen.c index 47487c0e..8d49ff9c 100644 --- a/src/terminal/screen.c +++ b/src/terminal/screen.c @@ -422,14 +422,23 @@ struct screen_state { unsigned char bold; unsigned char attr; /* Following should match struct screen_char color field. */ -#if defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS) +#if defined(CONFIG_TRUE_COLOR) + unsigned char color[6]; +#elif defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS) unsigned char color[2]; #else unsigned char color[1]; #endif }; -#if defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS) +#if defined(CONFIG_TRUE_COLOR) +#define compare_color(a, b) ((a)[0] == (b)[0] && (a)[1] == (b)[1] && (a)[2] == (b)[2] \ + && (a)[3] == (b)[3] && (a)[4] == (b)[4] && (a)[5] == (b)[5]) +#define copy_color(a, b) do { (a)[0] = (b)[0]; (a)[1] = (b)[1]; (a)[2] = (b)[2]; \ + (a)[3] = (b)[3]; (a)[4] = (b)[4]; (a)[5] = (b)[5];} while (0) +#define INIT_SCREEN_STATE { 0xFF, 0xFF, 0xFF, 0, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} } + +#elif defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS) #define compare_color(a, b) ((a)[0] == (b)[0] && (a)[1] == (b)[1]) #define copy_color(a, b) do { (a)[0] = (b)[0]; (a)[1] = (b)[1]; } while (0) #define INIT_SCREEN_STATE { 0xFF, 0xFF, 0xFF, 0, { 0xFF, 0xFF } } @@ -439,8 +448,13 @@ struct screen_state { #define INIT_SCREEN_STATE { 0xFF, 0xFF, 0xFF, 0, { 0xFF } } #endif +#if defined(CONFIG_TRUE_COLOR) +#define compare_bg_color(a, b) ((a)[3] == (b[3]) && (a)[4] == (b)[4] && (a)[5] == (b)[5]) +#define compare_fg_color(a, b) ((a)[0] == (b[0]) && (a)[1] == (b)[1] && (a)[2] == (b)[2]) +#else #define compare_bg_color(a, b) (TERM_COLOR_BACKGROUND(a) == TERM_COLOR_BACKGROUND(b)) #define compare_fg_color(a, b) (TERM_COLOR_FOREGROUND(a) == TERM_COLOR_FOREGROUND(b)) +#endif #ifdef CONFIG_UTF_8 static inline void @@ -683,6 +697,121 @@ add_char256(struct string *screen, struct screen_driver *driver, } #endif +#ifdef CONFIG_TRUE_COLOR +static struct string color_true_seqs[] = { + /* foreground: */ TERM_STRING("\033[0;38;2"), + /* background: */ TERM_STRING("\033[48;2"), +}; +#define add_true_background_color(str, seq, chr) add_char_true_color(str, &(seq)[1], &(chr)->color[3]) +#define add_true_foreground_color(str, seq, chr) add_char_true_color(str, &(seq)[0], &(chr)->color[0]) +static inline void +add_char_true_color(struct string *screen, struct string *seq, unsigned char *colors) +{ + unsigned char color_buf[3]; + int i; + + check_string_magic(seq); + add_string_to_string(screen, seq); + for (i = 0; i < 3; i++) { + unsigned char *color_pos = color_buf; + int color_len = 1; + unsigned char color = colors[i]; + + add_char_to_string(screen, ';'); + + if (color < 10) { + color_pos += 2; + } else { + int color2; + + ++color_len; + if (color < 100) { + ++color_pos; + } else { + ++color_len; + + if (color < 200) { + color_buf[0] = '1'; + color -= 100; + } else { + color_buf[0] = '2'; + color -= 200; + } + } + + color2 = (color % 10); + color /= 10; + color_buf[1] = '0' + color; + color = color2; + } + color_buf[2] = '0' + color; + + add_bytes_to_string(screen, color_pos, color_len); + } + add_char_to_string(screen, 'm'); +} + +/* Time critical section. */ +static inline void +add_char_true(struct string *screen, struct screen_driver *driver, + struct screen_char *ch, struct screen_state *state) +{ + unsigned char attr_delta = (ch->attr ^ state->attr); + + if ( +#ifdef CONFIG_UTF_8 + (!use_utf8_io(driver) || ch->data != UCS_NO_CHAR) && +#endif /* CONFIG_UTF_8 */ + attr_delta + ) { + if ((attr_delta & SCREEN_ATTR_FRAME) && driver->frame_seqs) { + state->border = !!(ch->attr & SCREEN_ATTR_FRAME); + add_term_string(screen, driver->frame_seqs[state->border]); + } + + if ((attr_delta & SCREEN_ATTR_UNDERLINE) && driver->underline) { + state->underline = !!(ch->attr & SCREEN_ATTR_UNDERLINE); + add_term_string(screen, driver->underline[state->underline]); + } + + if (attr_delta & SCREEN_ATTR_BOLD) { + if (ch->attr & SCREEN_ATTR_BOLD) { + add_bytes_to_string(screen, "\033[1m", 4); + } else { + /* Force repainting of the other attributes. */ + state->color[0] = ch->color[0] + 1; + } + } + + state->attr = ch->attr; + } + + if ( +#ifdef CONFIG_UTF_8 + (!use_utf8_io(driver) || ch->data != UCS_NO_CHAR) && +#endif /* CONFIG_UTF_8 */ + !compare_color(ch->color, state->color) + ) { + copy_color(state->color, ch->color); + + add_true_foreground_color(screen, color_true_seqs, ch); + if (!driver->transparent || ch->color[1] != 0) { + add_true_background_color(screen, color_true_seqs, ch); + } + + if (ch->attr & SCREEN_ATTR_BOLD) + add_bytes_to_string(screen, "\033[1m", 4); + + if (ch->attr & SCREEN_ATTR_UNDERLINE && driver->underline) { + state->underline = !!(ch->attr & SCREEN_ATTR_UNDERLINE); + add_term_string(screen, driver->underline[state->underline]); + } + } + + add_char_data(screen, driver, ch->data, ch->attr & SCREEN_ATTR_FRAME); +} +#endif + #define add_chars(image_, term_, driver_, state_, ADD_CHAR) \ { \ struct terminal_screen *screen = (term_)->screen; \ @@ -774,6 +903,11 @@ redraw_screen(struct terminal *term) case COLOR_MODE_256: add_chars(&image, term, driver, &state, add_char256); break; +#endif +#ifdef CONFIG_TRUE_COLOR + case COLOR_MODE_TRUE_COLOR: + add_chars(&image, term, driver, &state, add_char_true); + break; #endif case COLOR_MODES: case COLOR_MODE_DUMP: