[PATCH] 256 color support for libvte (and so gnome-terminal)



[CCing Nalin because it says so in HACKING, though his
last change to the source was done over a year ago.]

Hi list,

I wasn't sure where to send this, but this list seems
close enough.  Yell at me if it isn't.

Okay, so I implemented 256 color support for libvte.
This is nice if you run Emacs in gnome-terminal and want to
use fancy color themes.  Maybe you can think of other
cool applications.  Personally I'd like to see an aalib-like
library utilizing the 256 colors.

The current implementation doesn't support dynamically
changing the palette, mostly because I don't know of any
programs that use that feature --- Emacs doesn't.  :-(

The patch doesn't break API compatibility and shouldn't
break ABI compatibility unless someone is poking around in
the `vte_charcell' struct (declared in `vte-private.h').

The one thing I'm uncertain about is this change:

  (struct vte_charcell): Increase size of `fore' and `back' fields
  from 5 to 9 bits.  Decrease size of `columns' field from 11 to 3.

I don't know if and why the `columns' field needed to be 11
bits wide before.  Raise your hand if you have a character
that occupies two thousand horizontal terminal cells.
My guess is that three bits will do fine, but chances are
I'm missing something.  --- Nalin, are you listening? :-)

(I also didn't know what to do about the termcap entries,
but maybe that doesn't matter as much.)

Anyway, to test the feature, try this:

   ./configure --enable-256-colors && make install
   gnome-terminal
   TERM=xterm-256color emacs -nw -f list-colors-display

If your Emacs doesn't support 256 colors, find yourself a
copy of the `256colors2.pl' script that ships with XTerm.
(Maybe it should also be shipped with libvte now?)

Here's the ChangeLog entry:

2006-02-27  Daniel Brockman  <daniel brockman se>

	* termcaps/xterm.baseline: Add entries for `xterm-256color',
	`xterm-88color' and `xterm-16color' taken from the XTerm tarball.

	* src/vteseq.c (vte_sequence_handler_character_attributes)
	[VTE_ENABLE_256_COLORS]: Interpret the `38;5;foo' and `48;5;foo'
	sequences used to pick colors from the 256-entry palette.
	Disable interpretation of the `38' sequence used to enable
	underlining and setting the foreground color to its default value.

	* src/vte.c (vte_terminal_set_colors) [VTE_ENABLE_256_COLORS]:
	Allow `palette_size' to equal 256.
	(vte_terminal_set_colors): Fix cases in switch to use
	`VTE_COLOR_PLAIN_OFFSET' instead of hardcoding `0',
	`VTE_COLOR_BRIGHT_OFFSET' instead of hardcoding `8', and
	`VTE_COLOR_DIM_OFFSET' instead of hardcoding `16'.
	[VTE_ENABLE_256_COLORS]: Set up the standard color cube and
	grayscale ramp palette entries.

	* src/vte-private.h [VTE_ENABLE_256_COLORS]
	(VTE_COLOR_DIM_OFFSET): Change from 16 to 256.
	(struct vte_charcell): Increase size of `fore' and `back' fields
	from 5 to 9 bits.  Decrease size of `columns' field from 11 to 3.

	* src/vte-private.h (VTE_COLOR_DIM_LAST): New macro.
	(VTE_DEF_FG, VTE_DEF_BG, VTE_BOLD_FG, VTE_DIM_FG)
	(VTE_DEF_HL, VTE_CUR_BG): Depend on `VTE_COLOR_DIM_LAST'.

	* configure.in (--enable-256-colors): New option.  Define macro
	`VTE_ENABLE_256_COLORS' and set conditional `ENABLE_256_COLORS'.

and... here's the patch:
        
diff -cr vte-0.11.18/ vte-0.11.18-256-colors/
diff -cr vte-0.11.18/configure.in vte-0.11.18-256-colors/configure.in
*** vte-0.11.18/configure.in	2006-02-11 20:53:52.000000000 +0100
--- vte-0.11.18-256-colors/configure.in	2006-02-27 07:09:57.000000000 +0100
***************
*** 58,63 ****
--- 58,76 ----
  VTE_DEFAULT_EMULATION=$emulation
  AC_SUBST(VTE_DEFAULT_EMULATION)
  
+ AC_ARG_ENABLE([256-colors],
+   AS_HELP_STRING([--enable-256-colors], [enable support for 256 colors]),
+   [enable_256_colors=yes],
+   [enable_256_colors=no])
+ AM_CONDITIONAL([ENABLE_256_COLORS], [test "$enable_256_colors" != no])
+ AC_MSG_CHECKING([whether you want support for 256 colors])
+ if test "$enable_256_colors" != no ; then
+   AC_DEFINE([VTE_ENABLE_256_COLORS], 1, [enable support for 256 colors])
+   AC_MSG_RESULT([yes])
+ else
+   AC_MSG_RESULT([no])
+ fi
+ 
  # Use Xft2 if Pango has Xft2 support and it isn't disabled.
  if test "$have_x" = yes ; then
  	AC_ARG_WITH(xft2,[AS_HELP_STRING(--with-xft2,enable drawing using Xft2)],with_xft2=$withval,with_xft2=yes)
diff -cr vte-0.11.18/src/vte.c vte-0.11.18-256-colors/src/vte.c
*** vte-0.11.18/src/vte.c	2006-02-11 19:24:52.000000000 +0100
--- vte-0.11.18-256-colors/src/vte.c	2006-02-27 06:47:06.000000000 +0100
***************
*** 2012,2017 ****
--- 2012,2020 ----
  	g_return_if_fail((palette_size == 0) ||
  			 (palette_size == 8) ||
  			 (palette_size == 16) ||
+ #ifdef VTE_ENABLE_256_COLORS
+ 			 (palette_size == 256) ||
+ #endif
  			 (palette_size == G_N_ELEMENTS(terminal->pvt->palette)));
  
  	/* Accept NULL as the default foreground and background colors if we
***************
*** 2069,2113 ****
  			color.blue = 0x0000;
  			color.green = 0x0000;
  			break;
! 		case 0 + 0:
! 		case 0 + 1:
! 		case 0 + 2:
! 		case 0 + 3:
! 		case 0 + 4:
! 		case 0 + 5:
! 		case 0 + 6:
! 		case 0 + 7:
! 		case 8 + 0:
! 		case 8 + 1:
! 		case 8 + 2:
! 		case 8 + 3:
! 		case 8 + 4:
! 		case 8 + 5:
! 		case 8 + 6:
! 		case 8 + 7:
! 			color.blue = (i & 4) ? 0xc000 : 0;
  			color.green = (i & 2) ? 0xc000 : 0;
! 			color.red = (i & 1) ? 0xc000 : 0;
! 			if (i > 8) {
! 				color.blue += 0x3fff;
! 				color.green += 0x3fff;
! 				color.red += 0x3fff;
! 			}
! 			break;
! 		case 16 + 0:
! 		case 16 + 1:
! 		case 16 + 2:
! 		case 16 + 3:
! 		case 16 + 4:
! 		case 16 + 5:
! 		case 16 + 6:
! 		case 16 + 7:
! 			color.blue = (i & 4) ? 0x8000 : 0;
  			color.green = (i & 2) ? 0x8000 : 0;
! 			color.red = (i & 1) ? 0x8000 : 0;
  			break;
  		default:
! 			g_assert_not_reached();
  			break;
  		}
  
--- 2072,2159 ----
  			color.blue = 0x0000;
  			color.green = 0x0000;
  			break;
! 		case VTE_COLOR_PLAIN_OFFSET + 0:
! 		case VTE_COLOR_PLAIN_OFFSET + 1:
! 		case VTE_COLOR_PLAIN_OFFSET + 2:
! 		case VTE_COLOR_PLAIN_OFFSET + 3:
! 		case VTE_COLOR_PLAIN_OFFSET + 4:
! 		case VTE_COLOR_PLAIN_OFFSET + 5:
! 		case VTE_COLOR_PLAIN_OFFSET + 6:
! 		case VTE_COLOR_PLAIN_OFFSET + 7:
! 			color.blue  = (i & 4) ? 0xc000 : 0;
  			color.green = (i & 2) ? 0xc000 : 0;
! 			color.red   = (i & 1) ? 0xc000 : 0;
! 			break;
! 		case VTE_COLOR_BRIGHT_OFFSET + 0:
! 		case VTE_COLOR_BRIGHT_OFFSET + 1:
! 		case VTE_COLOR_BRIGHT_OFFSET + 2:
! 		case VTE_COLOR_BRIGHT_OFFSET + 3:
! 		case VTE_COLOR_BRIGHT_OFFSET + 4:
! 		case VTE_COLOR_BRIGHT_OFFSET + 5:
! 		case VTE_COLOR_BRIGHT_OFFSET + 6:
! 		case VTE_COLOR_BRIGHT_OFFSET + 7:
! 			color.blue  = (i & 4) ? 0xffff : 0;
! 			color.green = (i & 2) ? 0xffff : 0;
! 			color.red   = (i & 1) ? 0xffff : 0;
! 			break;
! 		case VTE_COLOR_DIM_OFFSET + 0:
! 		case VTE_COLOR_DIM_OFFSET + 1:
! 		case VTE_COLOR_DIM_OFFSET + 2:
! 		case VTE_COLOR_DIM_OFFSET + 3:
! 		case VTE_COLOR_DIM_OFFSET + 4:
! 		case VTE_COLOR_DIM_OFFSET + 5:
! 		case VTE_COLOR_DIM_OFFSET + 6:
! 		case VTE_COLOR_DIM_OFFSET + 7:
! 			color.blue  = (i & 4) ? 0x8000 : 0;
  			color.green = (i & 2) ? 0x8000 : 0;
! 			color.red   = (i & 1) ? 0x8000 : 0;
  			break;
  		default:
! #ifdef VTE_ENABLE_256_COLORS
! 			if (i >= 16 && i <= 231) {
! 			     /* The standard color cube is defined by the
! 			      * following formula
! 			      *
! 			      *          i = 16 + 36r + 6g + b,
! 			      *
! 			      * where the color components `r', `g' and `b'
! 			      * range from zero to five and map into the
! 			      * normal colorspace according to these rules:
! 			      *
! 			      *     byte(c)  =  0             if c = 0
! 			      *     byte(c)  =  c * 40 + 55   otherwise
! 			      *
! 			      */
! 			     guint16 jumble = (guint16) i - 16;
! 			     guint8 r, g, b;
! 			  
! 			     b = (jumble % 6) * 40; jumble /= 6;
! 			     if (b != 0) b += 55;
! 			     
! 			     g = (jumble % 6) * 40; jumble /= 6;
! 			     if (g != 0) g += 55;
! 
! 			     r = (jumble % 6) * 40; jumble /= 6;
! 			     if (r != 0) r += 55;
! 
! 			     g_assert (jumble == 0);
! 
! 			     /* The GDK components, of course, are _two_
! 			      * bytes each, so we have to scale them up. */
! 			     color.red   = (guint16) r << 8;
! 			     color.green = (guint16) g << 8;
! 			     color.blue  = (guint16) b << 8;
! 			}
! 			else if (i >= 232 && i <= 255)
! 			     /* The standard grayscale ramp consists of
! 			      * fourteen levels of gray, excluding both
! 			      * totally black and totally white. */
! 			     color.blue = color.green = color.red =
! 				  (((guint16) i - 232) * 10 + 8) << 8;
! 			else
! #endif
! 			     g_assert_not_reached();
! 
  			break;
  		}
  
diff -cr vte-0.11.18/src/vte-private.h vte-0.11.18-256-colors/src/vte-private.h
*** vte-0.11.18/src/vte-private.h	2006-02-10 10:30:23.000000000 +0100
--- vte-0.11.18-256-colors/src/vte-private.h	2006-02-27 06:36:46.000000000 +0100
***************
*** 59,71 ****
  #define VTE_COLOR_SET_SIZE		8
  #define VTE_COLOR_PLAIN_OFFSET		0
  #define VTE_COLOR_BRIGHT_OFFSET		8
! #define VTE_COLOR_DIM_OFFSET		16
! #define VTE_DEF_FG			24
! #define VTE_DEF_BG			25
! #define VTE_BOLD_FG			26
! #define VTE_DIM_FG			27
! #define VTE_DEF_HL			28
! #define VTE_CUR_BG			29
  #define VTE_SATURATION_MAX		10000
  #define VTE_SCROLLBACK_MIN		100
  #define VTE_DEFAULT_CURSOR		GDK_XTERM
--- 59,79 ----
  #define VTE_COLOR_SET_SIZE		8
  #define VTE_COLOR_PLAIN_OFFSET		0
  #define VTE_COLOR_BRIGHT_OFFSET		8
! #ifdef VTE_ENABLE_256_COLORS
! /* I'm sorry to put the dim colors so far away from their plain and
!    bright counterparts, but 256-color-aware applications expect to
!    find the color cube at color index 16.  --- Daniel Brockman */
! #  define VTE_COLOR_DIM_OFFSET		256
! #else
! #  define VTE_COLOR_DIM_OFFSET		16 
! #endif
! #define VTE_COLOR_DIM_LAST		(VTE_COLOR_DIM_OFFSET + 7)
! #define VTE_DEF_FG			(VTE_COLOR_DIM_LAST + 1)
! #define VTE_DEF_BG			(VTE_COLOR_DIM_LAST + 2)
! #define VTE_BOLD_FG			(VTE_COLOR_DIM_LAST + 3)
! #define VTE_DIM_FG			(VTE_COLOR_DIM_LAST + 4)
! #define VTE_DEF_HL			(VTE_COLOR_DIM_LAST + 5)
! #define VTE_CUR_BG			(VTE_COLOR_DIM_LAST + 6)
  #define VTE_SATURATION_MAX		10000
  #define VTE_SCROLLBACK_MIN		100
  #define VTE_DEFAULT_CURSOR		GDK_XTERM
***************
*** 88,100 ****
   * includes any supported visible attributes. */
  struct vte_charcell {
  	gunichar c;		/* The Unicode character. */
! 	guint32 columns: 11;	/* Number of visible columns (as determined
! 				   by g_unicode_iswide(c)).  Use as many bits
! 				   as possible without making this structure
! 				   grow any larger. */
  	guint32 fragment: 1;	/* The nth fragment of a wide character. */
  	guint32 fore: 5;	/* Indices in the color palette for the */
  	guint32 back: 5;	/* foreground and background of the cell. */
  	guint32 standout: 1;	/* Single-bit attributes. */
  	guint32 underline: 1;
  	guint32 strikethrough: 1;
--- 96,126 ----
   * includes any supported visible attributes. */
  struct vte_charcell {
  	gunichar c;		/* The Unicode character. */
! 
! /* Use as many leftover bits as possible for the `columns' field. */
! #ifdef VTE_ENABLE_256_COLORS
! /* I don't understand why this field should be larger than a
!  * single bit (which is enough if you just want to store the
!  * result of `g_unicode_iswide'), so I stripped it down to
!  * make room for the 256 colors data.  --- Daniel Brockman */
! /* XXX: Is this a bad idea? */
! 	guint32 columns: 3;	/* Number of visible columns (as determined
! 				   by g_unicode_iswide(c)). */
! #else
! 	guint32 columns: 11;	/* Number of visible columns (as determined 
! 				   by g_unicode_iswide(c)). */
! #endif
! 
  	guint32 fragment: 1;	/* The nth fragment of a wide character. */
+ 
+ #ifdef VTE_ENABLE_256_COLORS
+ 	guint32 fore: 9;	/* Indices in the color palette for the */
+ 	guint32 back: 9;	/* foreground and background of the cell. */
+ #else
  	guint32 fore: 5;	/* Indices in the color palette for the */
  	guint32 back: 5;	/* foreground and background of the cell. */
+ #endif
+ 
  	guint32 standout: 1;	/* Single-bit attributes. */
  	guint32 underline: 1;
  	guint32 strikethrough: 1;
diff -cr vte-0.11.18/src/vteseq.c vte-0.11.18-256-colors/src/vteseq.c
*** vte-0.11.18/src/vteseq.c	2006-02-10 10:25:56.000000000 +0100
--- vte-0.11.18-256-colors/src/vteseq.c	2006-02-25 11:44:34.000000000 +0100
***************
*** 2750,2755 ****
--- 2750,2789 ----
  			continue;
  		}
  		param = g_value_get_long(value);
+ 
+ #ifdef VTE_ENABLE_256_COLORS
+                 /*
+                  * XTerm understands the following sequences:
+ 		 * 
+ 		 *   `38;5;foo' --- set foreground color to `foo'.
+ 		 *   `48;5;foo' --- set background color to `foo'.
+                  */
+                 if ((param == 38 || param == 48)
+                     && params->n_values - i >= 2) {
+ 		     GValue *value1 = g_value_array_get_nth(params, i + 1);
+ 		     GValue *value2 = g_value_array_get_nth(params, i + 2);
+                     
+ 		     if (G_VALUE_HOLDS_LONG(value1)
+ 			 && g_value_get_long(value1) == 5
+ 			 && G_VALUE_HOLDS_LONG(value2)) {
+ 			  glong color = g_value_get_long(value2);
+ 
+ 			  if (color >= 0 && color <= 255) {
+ 			       if (param == 38)
+ 				    terminal->pvt->screen->
+ 					 defaults.fore = color;
+ 			       else
+ 				    terminal->pvt->screen->
+ 					 defaults.back = color;
+ 
+ 			       /* The loop increment adds one,
+ 				  so we only have to add two.  */
+ 			       i += 2; continue;
+                           }
+ 		     }
+ 		}
+ #endif
+                 
  		switch (param) {
  		case 0:
  			_vte_terminal_set_default_attributes(terminal);
***************
*** 2807,2817 ****
--- 2841,2856 ----
  		case 37:
  			terminal->pvt->screen->defaults.fore = param - 30;
  			break;
+ #ifndef VTE_ENABLE_256_COLORS
+                         /* I at least don't see this making much sense
+ 			 * alongside the `38;5;foo' sequence used for 256
+ 			 * color support.  --- Daniel Brockman */
  		case 38:
  			/* default foreground, underscore */
  			terminal->pvt->screen->defaults.fore = VTE_DEF_FG;
  			terminal->pvt->screen->defaults.underline = 1;
  			break;
+ #endif
  		case 39:
  			/* default foreground, no underscore */
  			terminal->pvt->screen->defaults.fore = VTE_DEF_FG;
diff -cr vte-0.11.18/termcaps/xterm.baseline vte-0.11.18-256-colors/termcaps/xterm.baseline
*** vte-0.11.18/termcaps/xterm.baseline	2002-11-25 21:39:20.000000000 +0100
--- vte-0.11.18-256-colors/termcaps/xterm.baseline	2006-02-27 05:59:47.000000000 +0100
***************
*** 28,33 ****
--- 28,44 ----
  xterm-color|generic "ANSI" color xterm (X Window System):\
  	:Co#8:NC@:pa#64:\
  	:AB=\E[4%dm:AF=\E[3%dm:op=\E[m:tc=xterm-r6:
+ # These aliases are for compatibility with the terminfo; termcap cannot provide
+ # the extra features such as color initialization, but termcap applications
+ # still want the names.  Note that AF/AB really should be Sf/Sb, but there are
+ # applications which expect the former.  The terminfo contains both strings.
+ xterm-16color|xterm alias:\
+ 	:tc=xterm-new:
+ xterm-88color|xterm alias:\
+ 	:Co#88:pa#7744:tc=xterm-256color:
+ xterm-256color|xterm alias:\
+ 	:Co#256:pa#32767:\
+ 	:AB=\E[48;5;%dm:AF=\E[38;5;%dm:tc=xterm-redhat:
  # This is the only entry which you should have to customize, since "xterm"
  # is widely used for a variety of incompatible terminal emulations including
  # color_xterm and rxvt.

Diff finished.  Mon Feb 27 07:10:42 2006

Here's another totally unrelated tiny patch:

2006-02-27  Daniel Brockman  <daniel brockman se>

	* configure.in: Add check for `IT_PROG_INTLTOOL'.

diff -c old/vte-0.11.18-256-colors/configure.in new/vte-0.11.18-256-colors/configure.in
*** old/vte-0.11.18-256-colors/configure.in	2006-02-27 05:57:34.000000000 +0100
--- new/vte-0.11.18-256-colors/configure.in	2006-02-27 07:14:43.000000000 +0100
***************
*** 12,17 ****
--- 12,18 ----
  AM_MAINTAINER_MODE
  
  AM_PROG_LIBTOOL
+ IT_PROG_INTLTOOL
  ALL_LINGUAS="ang am ar az be bg bn bs ca cs cy da de 
  el en_CA en_GB es et eu fa fi fr ga gl gu he hi hr hu 
  id is it ja ka ko ku ky li lt lv mi mk ml mn ms nb ne 

Diff finished.  Mon Feb 27 07:19:15 2006

Regards,

-- 
Daniel Brockman <daniel brockman se>

A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]