]> asedeno.scripts.mit.edu Git - pssh.git/commitdiff
My 2007-03-13 release:
authorAlejandro R. Sedeño <asedeno@mit.edu>
Sun, 18 Mar 2007 18:51:57 +0000 (18:51 +0000)
committerAlejandro R. Sedeño <asedeno@mit.edu>
Sun, 18 Mar 2007 18:51:57 +0000 (18:51 +0000)
* 256-color terminal emulation

arm/vt100/palm/palmwindow.c
arm/vt100/putty.h
arm/vt100/terminal.c
arm/vt100/terminal.h
forms/displayprefsform.c

index ee25bcc3a4acff48174f96681725fe8844f65bb3..90b63e50f98a15837c9529d4c69dcf626bbef160 100644 (file)
 #include "swap.h"
 
 // Default color set
-// BOLD is more saturated, except for white and black themselves
+#define COLORS 256
 #define DEFAULT_COLORS \
-    {0, 0x00,0x00,0x00}, {0, 0x22,0x22,0x22},  \
-    {0, 0xdd,0x00,0x00}, {0, 0xff,0x00,0x00},  \
-    {0, 0x00,0xdd,0x00}, {0, 0x00,0xff,0x00},  \
-    {0, 0xdd,0xdd,0x00}, {0, 0xff,0xff,0x00},  \
-    {0, 0x00,0x00,0xdd}, {0, 0x00,0x00,0xff},  \
-    {0, 0xdd,0x00,0xdd}, {0, 0xff,0x00,0xff},  \
-    {0, 0x00,0xdd,0xdd}, {0, 0x00,0xff,0xff},  \
-    {0, 0xff,0xff,0xff}, {0, 0xdd,0xdd,0xdd},
-
-static RGBColorType defaultColors[16] = {
+    {0, 0x00,0x00,0x00}, {0, 0xbb,0x00,0x00}, {0, 0x00,0xbb,0x00}, {0, 0xbb,0xbb,0x00}, \
+    {0, 0x00,0x00,0xbb}, {0, 0xbb,0x00,0xbb}, {0, 0x00,0xbb,0xbb}, {0, 0xbb,0xbb,0xbb}, \
+    {0, 0x55,0x55,0x55}, {0, 0xff,0x55,0x55}, {0, 0x55,0xff,0x55}, {0, 0xff,0xff,0x55}, \
+    {0, 0x55,0x55,0xff}, {0, 0xff,0x55,0xff}, {0, 0x55,0xff,0xff}, {0, 0xff,0xff,0xff}, \
+    {0, 0x00,0x00,0x00}, {0, 0x00,0x00,0x33}, {0, 0x00,0x00,0x66}, \
+    {0, 0x00,0x00,0x99}, {0, 0x00,0x00,0xcc}, {0, 0x00,0x00,0xff}, \
+    {0, 0x00,0x33,0x00}, {0, 0x00,0x33,0x33}, {0, 0x00,0x33,0x66}, \
+    {0, 0x00,0x33,0x99}, {0, 0x00,0x33,0xcc}, {0, 0x00,0x33,0xff}, \
+    {0, 0x00,0x66,0x00}, {0, 0x00,0x66,0x33}, {0, 0x00,0x66,0x66}, \
+    {0, 0x00,0x66,0x99}, {0, 0x00,0x66,0xcc}, {0, 0x00,0x66,0xff}, \
+    {0, 0x00,0x99,0x00}, {0, 0x00,0x99,0x33}, {0, 0x00,0x99,0x66}, \
+    {0, 0x00,0x99,0x99}, {0, 0x00,0x99,0xcc}, {0, 0x00,0x99,0xff}, \
+    {0, 0x00,0xcc,0x00}, {0, 0x00,0xcc,0x33}, {0, 0x00,0xcc,0x66}, \
+    {0, 0x00,0xcc,0x99}, {0, 0x00,0xcc,0xcc}, {0, 0x00,0xcc,0xff}, \
+    {0, 0x00,0xff,0x00}, {0, 0x00,0xff,0x33}, {0, 0x00,0xff,0x66}, \
+    {0, 0x00,0xff,0x99}, {0, 0x00,0xff,0xcc}, {0, 0x00,0xff,0xff}, \
+    {0, 0x33,0x00,0x00}, {0, 0x33,0x00,0x33}, {0, 0x33,0x00,0x66}, \
+    {0, 0x33,0x00,0x99}, {0, 0x33,0x00,0xcc}, {0, 0x33,0x00,0xff}, \
+    {0, 0x33,0x33,0x00}, {0, 0x33,0x33,0x33}, {0, 0x33,0x33,0x66}, \
+    {0, 0x33,0x33,0x99}, {0, 0x33,0x33,0xcc}, {0, 0x33,0x33,0xff}, \
+    {0, 0x33,0x66,0x00}, {0, 0x33,0x66,0x33}, {0, 0x33,0x66,0x66}, \
+    {0, 0x33,0x66,0x99}, {0, 0x33,0x66,0xcc}, {0, 0x33,0x66,0xff}, \
+    {0, 0x33,0x99,0x00}, {0, 0x33,0x99,0x33}, {0, 0x33,0x99,0x66}, \
+    {0, 0x33,0x99,0x99}, {0, 0x33,0x99,0xcc}, {0, 0x33,0x99,0xff}, \
+    {0, 0x33,0xcc,0x00}, {0, 0x33,0xcc,0x33}, {0, 0x33,0xcc,0x66}, \
+    {0, 0x33,0xcc,0x99}, {0, 0x33,0xcc,0xcc}, {0, 0x33,0xcc,0xff}, \
+    {0, 0x33,0xff,0x00}, {0, 0x33,0xff,0x33}, {0, 0x33,0xff,0x66}, \
+    {0, 0x33,0xff,0x99}, {0, 0x33,0xff,0xcc}, {0, 0x33,0xff,0xff}, \
+    {0, 0x66,0x00,0x00}, {0, 0x66,0x00,0x33}, {0, 0x66,0x00,0x66}, \
+    {0, 0x66,0x00,0x99}, {0, 0x66,0x00,0xcc}, {0, 0x66,0x00,0xff}, \
+    {0, 0x66,0x33,0x00}, {0, 0x66,0x33,0x33}, {0, 0x66,0x33,0x66}, \
+    {0, 0x66,0x33,0x99}, {0, 0x66,0x33,0xcc}, {0, 0x66,0x33,0xff}, \
+    {0, 0x66,0x66,0x00}, {0, 0x66,0x66,0x33}, {0, 0x66,0x66,0x66}, \
+    {0, 0x66,0x66,0x99}, {0, 0x66,0x66,0xcc}, {0, 0x66,0x66,0xff}, \
+    {0, 0x66,0x99,0x00}, {0, 0x66,0x99,0x33}, {0, 0x66,0x99,0x66}, \
+    {0, 0x66,0x99,0x99}, {0, 0x66,0x99,0xcc}, {0, 0x66,0x99,0xff}, \
+    {0, 0x66,0xcc,0x00}, {0, 0x66,0xcc,0x33}, {0, 0x66,0xcc,0x66}, \
+    {0, 0x66,0xcc,0x99}, {0, 0x66,0xcc,0xcc}, {0, 0x66,0xcc,0xff}, \
+    {0, 0x66,0xff,0x00}, {0, 0x66,0xff,0x33}, {0, 0x66,0xff,0x66}, \
+    {0, 0x66,0xff,0x99}, {0, 0x66,0xff,0xcc}, {0, 0x66,0xff,0xff}, \
+    {0, 0x99,0x00,0x00}, {0, 0x99,0x00,0x33}, {0, 0x99,0x00,0x66}, \
+    {0, 0x99,0x00,0x99}, {0, 0x99,0x00,0xcc}, {0, 0x99,0x00,0xff}, \
+    {0, 0x99,0x33,0x00}, {0, 0x99,0x33,0x33}, {0, 0x99,0x33,0x66}, \
+    {0, 0x99,0x33,0x99}, {0, 0x99,0x33,0xcc}, {0, 0x99,0x33,0xff}, \
+    {0, 0x99,0x66,0x00}, {0, 0x99,0x66,0x33}, {0, 0x99,0x66,0x66}, \
+    {0, 0x99,0x66,0x99}, {0, 0x99,0x66,0xcc}, {0, 0x99,0x66,0xff}, \
+    {0, 0x99,0x99,0x00}, {0, 0x99,0x99,0x33}, {0, 0x99,0x99,0x66}, \
+    {0, 0x99,0x99,0x99}, {0, 0x99,0x99,0xcc}, {0, 0x99,0x99,0xff}, \
+    {0, 0x99,0xcc,0x00}, {0, 0x99,0xcc,0x33}, {0, 0x99,0xcc,0x66}, \
+    {0, 0x99,0xcc,0x99}, {0, 0x99,0xcc,0xcc}, {0, 0x99,0xcc,0xff}, \
+    {0, 0x99,0xff,0x00}, {0, 0x99,0xff,0x33}, {0, 0x99,0xff,0x66}, \
+    {0, 0x99,0xff,0x99}, {0, 0x99,0xff,0xcc}, {0, 0x99,0xff,0xff}, \
+    {0, 0xcc,0x00,0x00}, {0, 0xcc,0x00,0x33}, {0, 0xcc,0x00,0x66}, \
+    {0, 0xcc,0x00,0x99}, {0, 0xcc,0x00,0xcc}, {0, 0xcc,0x00,0xff}, \
+    {0, 0xcc,0x33,0x00}, {0, 0xcc,0x33,0x33}, {0, 0xcc,0x33,0x66}, \
+    {0, 0xcc,0x33,0x99}, {0, 0xcc,0x33,0xcc}, {0, 0xcc,0x33,0xff}, \
+    {0, 0xcc,0x66,0x00}, {0, 0xcc,0x66,0x33}, {0, 0xcc,0x66,0x66}, \
+    {0, 0xcc,0x66,0x99}, {0, 0xcc,0x66,0xcc}, {0, 0xcc,0x66,0xff}, \
+    {0, 0xcc,0x99,0x00}, {0, 0xcc,0x99,0x33}, {0, 0xcc,0x99,0x66}, \
+    {0, 0xcc,0x99,0x99}, {0, 0xcc,0x99,0xcc}, {0, 0xcc,0x99,0xff}, \
+    {0, 0xcc,0xcc,0x00}, {0, 0xcc,0xcc,0x33}, {0, 0xcc,0xcc,0x66}, \
+    {0, 0xcc,0xcc,0x99}, {0, 0xcc,0xcc,0xcc}, {0, 0xcc,0xcc,0xff}, \
+    {0, 0xcc,0xff,0x00}, {0, 0xcc,0xff,0x33}, {0, 0xcc,0xff,0x66}, \
+    {0, 0xcc,0xff,0x99}, {0, 0xcc,0xff,0xcc}, {0, 0xcc,0xff,0xff}, \
+    {0, 0xff,0x00,0x00}, {0, 0xff,0x00,0x33}, {0, 0xff,0x00,0x66}, \
+    {0, 0xff,0x00,0x99}, {0, 0xff,0x00,0xcc}, {0, 0xff,0x00,0xff}, \
+    {0, 0xff,0x33,0x00}, {0, 0xff,0x33,0x33}, {0, 0xff,0x33,0x66}, \
+    {0, 0xff,0x33,0x99}, {0, 0xff,0x33,0xcc}, {0, 0xff,0x33,0xff}, \
+    {0, 0xff,0x66,0x00}, {0, 0xff,0x66,0x33}, {0, 0xff,0x66,0x66}, \
+    {0, 0xff,0x66,0x99}, {0, 0xff,0x66,0xcc}, {0, 0xff,0x66,0xff}, \
+    {0, 0xff,0x99,0x00}, {0, 0xff,0x99,0x33}, {0, 0xff,0x99,0x66}, \
+    {0, 0xff,0x99,0x99}, {0, 0xff,0x99,0xcc}, {0, 0xff,0x99,0xff}, \
+    {0, 0xff,0xcc,0x00}, {0, 0xff,0xcc,0x33}, {0, 0xff,0xcc,0x66}, \
+    {0, 0xff,0xcc,0x99}, {0, 0xff,0xcc,0xcc}, {0, 0xff,0xcc,0xff}, \
+    {0, 0xff,0xff,0x00}, {0, 0xff,0xff,0x33}, {0, 0xff,0xff,0x66}, \
+    {0, 0xff,0xff,0x99}, {0, 0xff,0xff,0xcc}, {0, 0xff,0xff,0xff}, \
+    {0, 0x00,0x00,0x00}, {0, 0x11,0x11,0x11}, {0, 0x22,0x22,0x22}, {0, 0x33,0x33,0x33}, \
+    {0, 0x44,0x44,0x44}, {0, 0x55,0x55,0x55}, {0, 0x66,0x66,0x66}, {0, 0x77,0x77,0x77}, \
+    {0, 0x88,0x88,0x88}, {0, 0x99,0x99,0x99}, {0, 0xaa,0xaa,0xaa}, {0, 0xbb,0xbb,0xbb}, \
+    {0, 0xcc,0xcc,0xcc}, {0, 0xdd,0xdd,0xdd}, {0, 0xee,0xee,0xee}, {0, 0xff,0xff,0xff},
+    
+static RGBColorType defaultColors[COLORS] = {
     DEFAULT_COLORS
 };
 
-static RGBColorType colors[16] = {
+static RGBColorType colors[COLORS] = {
     DEFAULT_COLORS
 };
 
@@ -270,7 +342,6 @@ void beep(void *frontend, int mode)
     }
 }
 
-
 int char_width(Context ctx, unsigned int uc)
 {
     // palm: fixme
@@ -309,7 +380,7 @@ static int SectRect(RectangleType a, RectangleType b)
 
 
 void do_text(Context ctx, int x, int y, char *text, int len, 
-             unsigned long attr, unsigned long lattr)
+             struct attr_tag attrs, unsigned long lattr)
 {
 #define LEFT(rr) ((rr).topLeft.x)
 #define TOP(rr) ((rr).topLeft.y)
@@ -326,6 +397,8 @@ void do_text(Context ctx, int x, int y, char *text, int len,
     RectangleType r, big, fill;
     RectangleType closeBox;
     int closeBoxInvalid = 0;
+    unsigned long attr = attrs.attr;
+    unsigned long colors = attrs.color;
 
     closeBox.topLeft.x = RIGHT(dd->gadgetBounds) - dd->closeBoxSize;
     closeBox.topLeft.y = TOP(dd->gadgetBounds);
@@ -337,8 +410,8 @@ void do_text(Context ctx, int x, int y, char *text, int len,
     r.extent.x = len * font_width;
     r.extent.y = font_height;
 
-    fg_color = (attr & ATTR_FGMASK) >> ATTR_FGSHIFT;
-    bg_color = (attr & ATTR_BGMASK) >> ATTR_BGSHIFT;
+    fg_color = (colors & ATTR_FGMASK) >> ATTR_FGSHIFT;
+    bg_color = (colors & ATTR_BGMASK) >> ATTR_BGSHIFT;
 
     // handle VT100 linedraw chars
     // 0x5f maps to space
@@ -355,10 +428,6 @@ void do_text(Context ctx, int x, int y, char *text, int len,
     if (fg_color == (ATTR_DEFFG >> ATTR_FGSHIFT)) fg_color = DefaultForeColor;
     if (bg_color == (ATTR_DEFBG >> ATTR_BGSHIFT)) bg_color = DefaultBackColor;
 
-    // translate into indexes into colors[]
-    fg_color *= 2;
-    bg_color *= 2;
-
     if (attr & ATTR_REVERSE) {
         int temp = fg_color;
         fg_color = bg_color;
@@ -366,16 +435,17 @@ void do_text(Context ctx, int x, int y, char *text, int len,
     }
 
     // fixme can do real bold and underline with bigger fonts
-    if ((attr & ATTR_BOLD)  ||  (attr & ATTR_UNDER)) {
-        fg_color++;
+    if ((attr & ATTR_BOLD) && (fg_color < 8)) {//  ||  (attr & ATTR_UNDER)) {
+        fg_color += 8;
     }
     // fixme allow optional real blink
-    if (attr & ATTR_BLINK) {
-        bg_color++;
-    }
+/*     if (attr & ATTR_BLINK) { */
+/*         bg_color++; */
+/*     } */
 
     set_palm_color(fg_color, bg_color);
     WinDrawChars(text, len, r.topLeft.x, r.topLeft.y);
+
     if (SectRect(r, closeBox)) closeBoxInvalid = 1;
 
     // If the drawn rect extends to any edge of the text area, fill the 
@@ -446,7 +516,7 @@ void do_text(Context ctx, int x, int y, char *text, int len,
 
 
 void do_cursor(Context ctx, int x, int y, char *text, int len, 
-               unsigned long attr, unsigned long lattr)
+              struct attr_tag attr, unsigned long lattr)
 {
     do_text(ctx, x, y, text, len, attr, lattr);
 }
index 690281c34d57bf95ec2e9302ab550be1e7b60393..f50a4749ad97141b1dc399e452dc38e11842b5f1 100644 (file)
@@ -89,20 +89,32 @@ typedef struct terminal_tag Terminal;
  * ATTR_INVALID is an illegal colour combination.
  */
 
+struct attr_tag {
+    unsigned long attr;  /* Character and basic attributes */
+    unsigned long color; /* Color information */
+};
+
+/* Combines char/charset/attr and color attributes into the struct */
+#define ATTR_COMBINE(x,y) ((struct attr_tag){ x, y })
+#define ATTR_WRAP(x) ((struct attr_tag){ x, 0 })
+
+/* Stores line count and line attributes in attr_tag */
+/* Yes, this is a hack */
+#define LINE_COLS(x)  (((x)[0]).color)
+#define LINE_ATTRS(x) (((x)[0]).attr)
+
 #define TATTR_ACTCURS      0x4UL      /* active cursor (block) */
 #define TATTR_PASCURS      0x2UL      /* passive cursor (box) */
 #define TATTR_RIGHTCURS            0x1UL      /* cursor-on-RHS */
 
-#define LATTR_NORM   0x00000000UL
-#define LATTR_WIDE   0x01000000UL
-#define LATTR_TOP    0x02000000UL
-#define LATTR_BOT    0x03000000UL
-#define LATTR_MODE   0x03000000UL
-#define LATTR_WRAPPED 0x10000000UL
+#define LATTR_NORM     0x00000000UL
+#define LATTR_WIDE     0x01000000UL
+#define LATTR_TOP      0x02000000UL
+#define LATTR_BOT      0x03000000UL
+#define LATTR_MODE     0x03000000UL
+#define LATTR_WRAPPED  0x10000000UL
 #define LATTR_WRAPPED2 0x20000000UL
 
-#define ATTR_INVALID 0x03FF0000UL
-
 /* Like Linux use the F000 page for direct to font. */
 #define ATTR_OEMCP   0x0000F000UL      /* OEM Codepage DTF */
 #define ATTR_ACP     0x0000F100UL      /* Ansi Codepage DTF */
@@ -134,22 +146,44 @@ typedef struct terminal_tag Terminal;
 #define ATTR_UNDER   0x08000000UL
 #define ATTR_REVERSE 0x10000000UL
 #define ATTR_BLINK   0x20000000UL
-#define ATTR_FGMASK  0x001F0000UL
-#define ATTR_BGMASK  0x03E00000UL
-#define ATTR_COLOURS 0x03FF0000UL
-#define ATTR_FGSHIFT 16
-#define ATTR_BGSHIFT 21
-
-#define ATTR_DEFAULT 0x01280000UL      /* bg 9, fg 8 */
-#define ATTR_DEFFG   0x00080000UL
-#define ATTR_DEFBG   0x01200000UL
-#define ERASE_CHAR   (ATTR_DEFAULT | ATTR_ASCII | ' ')
-#define ATTR_MASK    0xFFFFFF00UL
+#define ATTR_CLEAR   0x00000000UL
+
+#define ATTR_FGMASK  0x000001FFUL
+#define ATTR_BGMASK  0x0003FE00UL
+#define ATTR_COLOURS 0x0003FFFFUL
+#define ATTR_FGSHIFT 0
+#define ATTR_BGSHIFT 9
+
+#define ATTR_DEFFG   (256 << ATTR_FGSHIFT)
+#define ATTR_DEFBG   (258 << ATTR_BGSHIFT)
+#define ATTR_DEFCOLORS (ATTR_DEFFG | ATTR_DEFBG)
+
+#define ATTR_INVALID ATTR_COMBINE( ATTR_CLEAR, ATTR_COLOURS )
+#define ATTR_INVALIDATE(x) ((x).color |= ATTR_COLOURS )
+#define ATTR_DEFAULT ATTR_COMBINE( ATTR_CLEAR, ATTR_DEFCOLORS )
+
+#define ERASE_CHAR   ATTR_COMBINE( ATTR_CLEAR | ATTR_ASCII | ' ', ATTR_DEFCOLORS )
+#define ATTR_MASK    0xFC00FF00UL
 #define CHAR_MASK    0x000000FFUL
 
 #define ATTR_CUR_AND (~(ATTR_BOLD|ATTR_REVERSE|ATTR_BLINK|ATTR_COLOURS))
 #define ATTR_CUR_XOR 0x016A0000UL
 
+#define ATTR_CHAR(x) ATTR_COMBINE((x).attr & CHAR_MASK, 0)
+#define ATTR_CHARALL(x) ATTR_COMBINE((x).attr & (CHAR_MASK | CSET_MASK), 0)
+#define ATTR_ATTRS(x) ATTR_COMBINE((x).attr & ATTR_MASK, (x).color)
+
+#define ATTR_AND(x,y) ATTR_COMBINE((x).attr & (y).attr, (x).color & (y).color)
+#define ATTR_OR(x,y)  ATTR_COMBINE((x).attr | (y).attr, (x).color | (y).color)
+#define ATTR_XOR(x,y) ATTR_COMBINE((x).attr ^ (y).attr, (x).color ^ (y).color)
+
+#define ATTR_ZERO(x) (!((x).attr | (x).color))
+#define ATTR_EQUAL(x,y) ATTR_ZERO(ATTR_XOR(x,y))
+
+#define ATTR_ON(x,y)  (ATTR_COMBINE((x).attr |  (y), (x).color))
+#define ATTR_OFF(x,y) (ATTR_COMBINE((x).attr & ~(y), (x).color))
+#define ATTR_STATE(x,y) ((x).attr & (y))
+
 struct sesslist {
     int nsessions;
     char **sessions;
@@ -496,8 +530,8 @@ struct config_tag {
  * Exports from window.c.
  */
 void request_resize(void *frontend, int, int);
-void do_text(Context, int, int, char *, int, unsigned long, unsigned long);
-void do_cursor(Context, int, int, char *, int, unsigned long, unsigned long);
+void do_text(Context, int, int, char *, int, struct attr_tag, unsigned long);
+void do_cursor(Context, int, int, char *, int, struct attr_tag, unsigned long);
 int char_width(Context ctx, unsigned int uc);
 #ifdef OPTIMISE_SCROLL
 void do_scroll(Context, int, int, int);
index b92ca5b65ad72271607cdcf5d8811f00163f3141..e2de7346db7c30f29a795cacdf3ef48676710ca4 100644 (file)
@@ -116,15 +116,15 @@ const wchar_t sel_nl[] = SEL_NL;
  * then we must look one space further to the left.
  */
 #define UCSGET(a, x) \
-    ( (x)>0 && ((a)[(x)] & (CHAR_MASK | CSET_MASK)) == UCSWIDE ? \
+    ( (x)>0 && ((a)[(x)].attr & (CHAR_MASK | CSET_MASK)) == UCSWIDE ? \
        (a)[(x)-1] : (a)[(x)] )
 
 /*
  * Internal prototypes.
  */
-static unsigned long *resizeline(unsigned long *, int);
+static struct attr_tag *resizeline(struct attr_tag *, int);
 static int sblines(Terminal *term);
-static unsigned long *lineptr(Terminal *, int, int);
+static struct attr_tag *lineptr(Terminal *, int, int);
 static void power_on(Terminal *term);
 static int find_last_nonempty_line(Terminal * term, tree234 * screen);
 static void swap_screen(Terminal *term, int which, int reset, int keep_cur_pos);
@@ -147,7 +147,7 @@ static void term_print_flush(Terminal *term);
 static void term_print_finish(Terminal *term);
 static void do_paint(Terminal *term, Context ctx, int may_optimise);
 static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel);
-static int wordtype(Terminal *term, uint32_t uc) /* NOT*/;
+static int wordtype(Terminal *term, struct attr_tag uc) /* NOT*/;
 static pos sel_spread_half(Terminal *term, pos p, int dir);
 static void sel_spread(Terminal *term);
 static void deselect(Terminal *term);
@@ -155,23 +155,32 @@ static void deselect(Terminal *term);
 /*
  * Resize a line to make it `cols' columns wide.
  */
-static unsigned long *resizeline(unsigned long *line, int cols)
+static struct attr_tag *resizeline(struct attr_tag *line, int cols)
 {
     int i, oldlen;
-    unsigned long lineattrs;
+    unsigned long  lineattrs;
 
-    if (line[0] != (unsigned long)cols) {
+    /*
+     * This is a bit of a hack here. We're going to use the attrs
+     * field to store line length. Since everthing used to be
+     * unsigned longs, this used to be trivial.
+     * Old structure: len[ul] {chars...}[ul+] lattrs[ul]
+     * New structure: len stored in color field of first attr_tag,
+                      line attrs in attr field of first attr_tag,
+                     attr_tags for each charater from there
+     */
+    if (LINE_COLS(line) != (unsigned long)cols) {
        /*
         * This line is the wrong length, which probably means it
         * hasn't been accessed since a resize. Resize it now.
         */
-       oldlen = line[0];
-       lineattrs = line[oldlen + 1];
-       line = sresize(line, 2 + cols, TTYPE);
-       line[0] = cols;
+       oldlen = LINE_COLS(line);
+       lineattrs = LINE_ATTRS(line);
+       line = sresize(line, 1 + cols, TTYPE);
+       LINE_COLS(line) = (unsigned long)cols;
        for (i = oldlen; i < cols; i++)
            line[i + 1] = ERASE_CHAR;
-       line[cols + 1] = lineattrs & LATTR_MODE;
+       LINE_ATTRS(line) = lineattrs & LATTR_MODE;
     }
 
     return line;
@@ -195,9 +204,9 @@ static int sblines(Terminal *term)
  * whether the y coordinate is non-negative or negative
  * (respectively).
  */
-static unsigned long *lineptr(Terminal *term, int y, int lineno)
+static struct attr_tag *lineptr(Terminal *term, int y, int lineno)
 {
-    unsigned long *line, *newline;
+    struct attr_tag *line, *newline;
     tree234 *whichtree;
     int treeindex;
 
@@ -262,7 +271,7 @@ static void power_on(Terminal *term)
     term->alt_utf = term->utf = term->save_utf = 0;
     term->utf_state = 0;
     term->alt_sco_acs = term->sco_acs = term->save_sco_acs = 0;
-    term->cset_attr[0] = term->cset_attr[1] = term->save_csattr = ATTR_ASCII;
+    term->cset_attr[0] = term->cset_attr[1] = term->save_csattr = ATTR_WRAP(ATTR_ASCII);
     term->rvideo = 0;
     term->in_vbell = FALSE;
     term->cursor_on = 1;
@@ -356,6 +365,13 @@ void term_pwron(Terminal *term)
     term_update(term);
 }
 
+static void set_erase_char(Terminal *term)
+{
+    term->erase_char = ERASE_CHAR;
+    if (term->use_bce)
+       term->erase_char = ATTR_OR(ERASE_CHAR, term->curr_attr);
+}
+
 /*
  * When the user reconfigures us, we need to check the forbidden-
  * alternate-screen config option, disable raw mouse mode if the
@@ -391,12 +407,7 @@ void term_reconfig(Terminal *term, Config *cfg)
        term->alt_om = term->dec_om = term->cfg.dec_om;
     if (reset_bce) {
        term->use_bce = term->cfg.bce;
-       if (term->use_bce)
-           term->erase_char = (' ' | ATTR_ASCII |
-                               (term->curr_attr &
-                                (ATTR_FGMASK | ATTR_BGMASK)));
-       else
-           term->erase_char = ERASE_CHAR;
+       set_erase_char(term);
     }
     if (reset_blink)
        term->blink_is_real = term->cfg.blinktext;
@@ -411,7 +422,7 @@ void term_reconfig(Terminal *term, Config *cfg)
        set_raw_mouse_mode(term->frontend, 0);
     }
     if (term->cfg.no_remote_charset) {
-       term->cset_attr[0] = term->cset_attr[1] = ATTR_ASCII;
+       term->cset_attr[0] = term->cset_attr[1] = ATTR_WRAP(ATTR_ASCII);
        term->sco_acs = term->alt_sco_acs = 0;
        term->utf = 0;
     }
@@ -425,7 +436,7 @@ void term_reconfig(Terminal *term, Config *cfg)
  */
 void term_clrsb(Terminal *term)
 {
-    unsigned long *line;
+    struct attr_tag *line;
     term->disptop = 0;
     while ((line = delpos234(term->scrollback, 0)) != NULL) {
        sfree(line);
@@ -490,7 +501,7 @@ Terminal *term_init(Config *mycfg, struct unicode_data *ucsdata,
     term->nbeeps = 0;
     term->lastbeep = FALSE;
     term->beep_overloaded = FALSE;
-    term->attr_mask = 0xffffffff;
+    term->attr_mask = ATTR_COMBINE(ATTR_MASK|CHAR_MASK, ATTR_COLOURS);
     term->resize_fn = NULL;
     term->resize_ctx = NULL;
     term->in_term_out = FALSE;
@@ -500,7 +511,7 @@ Terminal *term_init(Config *mycfg, struct unicode_data *ucsdata,
 
 void term_free(Terminal *term)
 {
-    unsigned long *line;
+    struct attr_tag *line;
 
     while ((line = delpos234(term->scrollback, 0)) != NULL)
        sfree(line);
@@ -531,7 +542,7 @@ void term_free(Terminal *term)
 void term_size(Terminal *term, int newrows, int newcols, int newsavelines)
 {
     tree234 *newalt;
-    unsigned long *newdisp, *line;
+    struct attr_tag *newdisp, *line;
     int i, j;
     int sblen;
     int save_alt_which = term->alt_which;
@@ -586,11 +597,11 @@ void term_size(Terminal *term, int newrows, int newcols, int newsavelines)
            term->savecurs.y += 1;
        } else {
            /* Add a new blank line at the bottom of the screen. */
-           line = snewn(newcols + 2, TTYPE);
-           line[0] = newcols;
+           line = snewn(newcols + 1, TTYPE);
+           LINE_COLS(line) = newcols;
+           LINE_ATTRS(line) = LATTR_NORM;
            for (j = 0; j < newcols; j++)
                line[j + 1] = ERASE_CHAR;
-            line[newcols + 1] = LATTR_NORM;
            addpos234(term->screen, line, count234(term->screen));
        }
        term->rows += 1;
@@ -636,11 +647,11 @@ void term_size(Terminal *term, int newrows, int newcols, int newsavelines)
     /* Make a new alternate screen. */
     newalt = newtree234(NULL);
     for (i = 0; i < newrows; i++) {
-       line = snewn(newcols + 2, TTYPE);
-       line[0] = newcols;
+       line = snewn(newcols + 1, TTYPE);
+       LINE_COLS(line) = newcols;
+       LINE_ATTRS(line) = LATTR_NORM;
        for (j = 0; j < newcols; j++)
            line[j + 1] = term->erase_char;
-        line[newcols + 1] = LATTR_NORM;
        addpos234(newalt, line, i);
     }
     if (term->alt_screen) {
@@ -704,11 +715,11 @@ static int find_last_nonempty_line(Terminal * term, tree234 * screen)
 {
     int i;
     for (i = count234(screen) - 1; i >= 0; i--) {
-       unsigned long *line = index234(screen, i);
+       struct attr_tag *line = index234(screen, i);
        int j;
-       int cols = line[0];
+       int cols = LINE_COLS(line);
        for (j = 0; j < cols; j++) {
-           if (line[j + 1] != term->erase_char) break;
+           if (!ATTR_EQUAL(line[j + 1], term->erase_char)) break;
        }
        if (j != cols) break;
     }
@@ -821,7 +832,7 @@ static void check_selection(Terminal *term, pos from, pos to)
  */
 static void scroll(Terminal *term, int topline, int botline, int lines, int sb)
 {
-    unsigned long *line, *line2;
+    struct attr_tag *line, *line2;
     int i, seltop, olddisptop, shift;
 
     if (topline != 0 || term->alt_which != 0)
@@ -835,7 +846,7 @@ static void scroll(Terminal *term, int topline, int botline, int lines, int sb)
             line = resizeline(line, term->cols);
            for (i = 0; i < term->cols; i++)
                line[i + 1] = term->erase_char;
-           line[term->cols + 1] = 0;
+           LINE_ATTRS(line) = 0;
            addpos234(term->screen, line, topline);
 
            if (term->selstart.y >= topline && term->selstart.y <= botline) {
@@ -869,8 +880,8 @@ static void scroll(Terminal *term, int topline, int botline, int lines, int sb)
                if (sblen == term->savelines) {
                    sblen--, line2 = delpos234(term->scrollback, 0);
                } else {
-                   line2 = snewn(term->cols + 2, TTYPE);
-                   line2[0] = term->cols;
+                   line2 = snewn(term->cols + 1, TTYPE);
+                   LINE_COLS(line2) = term->cols;
                    term->tempsblines += 1;
                }
                addpos234(term->scrollback, line, sblen);
@@ -896,7 +907,7 @@ static void scroll(Terminal *term, int topline, int botline, int lines, int sb)
             line = resizeline(line, term->cols);
            for (i = 0; i < term->cols; i++)
                line[i + 1] = term->erase_char;
-           line[term->cols + 1] = LATTR_NORM;
+           LINE_ATTRS(line) = LATTR_NORM;
            addpos234(term->screen, line, botline);
 
            /*
@@ -983,7 +994,7 @@ static void save_scroll(Terminal *term, int topline, int botline, int lines)
  */
 static void scroll_display(Terminal *term, int topline, int botline, int lines)
 {
-    unsigned long *start, *end;
+    struct attr_tag *start, *end;
     int distance, size, i;
 
     start = term->disptext + topline * (term->cols + 1);
@@ -996,13 +1007,13 @@ static void scroll_display(Terminal *term, int topline, int botline, int lines)
            term->dispcurs <= start + distance + size)
            term->dispcurs -= distance;
        for (i = 0; i < distance; i++)
-           (start + size)[i] |= ATTR_INVALID;
+           ATTR_INVALIDATE((start + size)[i]);
     } else {
        memmove(start + distance, start, size * TSIZE);
        if (term->dispcurs >= start && term->dispcurs <= start + size)
            term->dispcurs += distance;
        for (i = 0; i < distance; i++)
-           start[i] |= ATTR_INVALID;
+           ATTR_INVALIDATE(start[i]);
     }
     save_scroll(term, topline, botline, lines);
 }
@@ -1073,9 +1084,7 @@ static void save_cursor(Terminal *term, int save)
        term->sco_acs = term->save_sco_acs;
        fix_cpos;
        if (term->use_bce)
-           term->erase_char = (' ' | ATTR_ASCII |
-                               (term->curr_attr &
-                                (ATTR_FGMASK | ATTR_BGMASK)));
+           set_erase_char(term);
     }
 }
 
@@ -1100,7 +1109,7 @@ static void save_cursor(Terminal *term, int save)
  */
 static void check_boundary(Terminal *term, int x, int y)
 {
-    unsigned long *ldata;
+    struct attr_tag *ldata;
 
     /* Validate input coordinates, just in case. */
     if (x == 0 || x > term->cols)
@@ -1108,11 +1117,11 @@ static void check_boundary(Terminal *term, int x, int y)
 
     ldata = lineptr(y);
     if (x == term->cols) {
-       ldata[x] &= ~LATTR_WRAPPED2;
+       LINE_ATTRS(ldata-1) &= ~LATTR_WRAPPED2;
     } else {
-       if ((ldata[x] & (CHAR_MASK | CSET_MASK)) == UCSWIDE) {
-           ldata[x-1] = ldata[x] =
-               (ldata[x-1] &~ (CHAR_MASK | CSET_MASK)) | ATTR_ASCII | ' ';
+       if ((ldata[x].attr & (CHAR_MASK | CSET_MASK)) == UCSWIDE) {
+           ldata[x-1].attr = ldata[x].attr =
+               (ldata[x-1].attr &~ (CHAR_MASK | CSET_MASK)) | ATTR_ASCII | ' ';
        }
     }
 }
@@ -1174,13 +1183,13 @@ static void erase_lots(Terminal *term,
            scroll(term, 0, scrolllines - 1, scrolllines, TRUE);
        fix_cpos;
     } else {
-       unsigned long *ldata = lineptr(start.y);
+       struct attr_tag *ldata = lineptr(start.y);
        while (poslt(start, end)) {
            if (start.x == term->cols) {
                if (!erase_lattr)
-                   ldata[start.x] &= ~(LATTR_WRAPPED | LATTR_WRAPPED2);
+                   LINE_ATTRS(ldata-1) &= ~(LATTR_WRAPPED | LATTR_WRAPPED2);
                else
-                   ldata[start.x] = LATTR_NORM;
+                   LINE_ATTRS(ldata-1) = LATTR_NORM;
            } else {
                ldata[start.x] = term->erase_char;
            }
@@ -1205,7 +1214,7 @@ static void insch(Terminal *term, int n)
     int dir = (n < 0 ? -1 : +1);
     int m;
     pos cursplus;
-    unsigned long *ldata;
+    struct attr_tag *ldata;
 
     n = (n < 0 ? -n : n);
     if (n > term->cols - term->curs.x)
@@ -1611,7 +1620,7 @@ void term_out(Terminal *term)
               if (term->sco_acs == 2) c |= 0x80;
               c |= ATTR_SCOACS;
            } else {
-               switch (term->cset_attr[term->cset]) {
+               switch (term->cset_attr[term->cset].attr) {
                    /* 
                     * Linedraw characters are different from 'ESC ( B'
                     * only for a small range. For ones outside that
@@ -1658,8 +1667,8 @@ void term_out(Terminal *term)
                term->curs.x--;
            term->wrapnext = FALSE;
            fix_cpos;
-           if (!term->cfg.no_dbackspace)    /* destructive bksp might be disabled */
-               *term->cpos = (' ' | term->curr_attr | ATTR_ASCII);
+           if (!term->cfg.no_dbackspace)   /* destructive bksp might be disabled */
+               *term->cpos = ATTR_OR(term->curr_attr, ATTR_WRAP( ATTR_ASCII | ' '));
        } else
            /* Or normal C0 controls. */
        if ((c & 0xffffffe0L) == 0 && term->termstate < DO_CTRLS) {
@@ -1825,14 +1834,14 @@ void term_out(Terminal *term)
              case '\t':              /* HT: Character tabulation */
                {
                    pos old_curs = term->curs;
-                   unsigned long *ldata = lineptr(term->curs.y);
+                   struct attr_tag *ldata = lineptr(term->curs.y);
 
                    do {
                        term->curs.x++;
                    } while (term->curs.x < term->cols - 1 &&
                             !term->tabs[term->curs.x]);
 
-                   if ((ldata[term->cols] & LATTR_MODE) != LATTR_NORM) {
+                   if ((LINE_ATTRS(ldata-1) & LATTR_MODE) != LATTR_NORM) {
                        if (term->curs.x >= term->cols / 2)
                            term->curs.x = term->cols / 2 - 1;
                    } else {
@@ -1852,7 +1861,7 @@ void term_out(Terminal *term)
                /* Only graphic characters get this far;
                 * ctrls are stripped above */
                if (term->wrapnext && term->wrap) {
-                   term->cpos[1] |= LATTR_WRAPPED;
+                   LINE_ATTRS(lineptr(term->curs.y)-1) |= LATTR_WRAPPED;
                    if (term->curs.y == term->marg_b)
                        scroll(term, term->marg_t, term->marg_b, 1, TRUE);
                    else if (term->curs.y < term->rows - 1)
@@ -1898,8 +1907,8 @@ void term_out(Terminal *term)
                        check_boundary(term, term->curs.x, term->curs.y);
                        check_boundary(term, term->curs.x+2, term->curs.y);
                        if (term->curs.x == term->cols-1) {
-                           *term->cpos++ = ATTR_ASCII | ' ' | term->curr_attr;
-                           *term->cpos |= LATTR_WRAPPED | LATTR_WRAPPED2;
+                            *term->cpos = ATTR_OR(term->curr_attr, ATTR_WRAP(ATTR_ASCII | ' '));
+                           LINE_ATTRS(lineptr(term->curs.y)-1) |= LATTR_WRAPPED | LATTR_WRAPPED2;
                            if (term->curs.y == term->marg_b)
                                scroll(term, term->marg_t, term->marg_b,
                                       1, TRUE);
@@ -1911,14 +1920,14 @@ void term_out(Terminal *term)
                            check_boundary(term, term->curs.x, term->curs.y);
                            check_boundary(term, term->curs.x+2, term->curs.y);
                        }
-                       *term->cpos++ = c | term->curr_attr;
-                       *term->cpos++ = UCSWIDE | term->curr_attr;
+                       *term->cpos++ = ATTR_OR(ATTR_WRAP(c), term->curr_attr);
+                       *term->cpos++ = ATTR_OR(ATTR_WRAP(UCSWIDE), term->curr_attr);
                        term->curs.x++;
                        break;
                      case 1:
                        check_boundary(term, term->curs.x, term->curs.y);
                        check_boundary(term, term->curs.x+1, term->curs.y);
-                       *term->cpos++ = c | term->curr_attr;
+                       *term->cpos++ = ATTR_OR(ATTR_WRAP(c), term->curr_attr);
                        break;
                      default:
                        continue;
@@ -1930,7 +1939,7 @@ void term_out(Terminal *term)
                    term->curs.x--;
                    term->wrapnext = TRUE;
                    if (term->wrap && term->vt52_mode) {
-                       term->cpos[1] |= LATTR_WRAPPED;
+                       LINE_ATTRS(lineptr(term->curs.y)-1) |= LATTR_WRAPPED;
                        if (term->curs.y == term->marg_b)
                            scroll(term, term->marg_t, term->marg_b, 1, TRUE);
                        else if (term->curs.y < term->rows - 1)
@@ -2053,15 +2062,16 @@ void term_out(Terminal *term)
                  case ANSI('8', '#'):  /* DECALN: fills screen with Es :-) */
                    compatibility(VT100);
                    {
-                       unsigned long *ldata;
+                       struct attr_tag *ldata;
                        int i, j;
                        pos scrtop, scrbot;
 
                        for (i = 0; i < term->rows; i++) {
                            ldata = lineptr(i);
-                           for (j = 0; j < term->cols; j++)
-                               ldata[j] = ATTR_DEFAULT | 'E';
-                           ldata[term->cols] = 0;
+                           for (j = 0; j < term->cols; j++) {
+                               ldata[j] = ATTR_OR(ATTR_DEFAULT, ATTR_WRAP('E'));
+                           }
+                           LINE_ATTRS(ldata-1)= 0;
                        }
                        term->disptop = 0;
                        term->seen_disp_event = TRUE;
@@ -2079,7 +2089,7 @@ void term_out(Terminal *term)
                    compatibility(VT100);
                    {
                        unsigned long nlattr;
-                       unsigned long *ldata;
+                       struct attr_tag *ldata;
                        switch (ANSI(c, term->esc_query)) {
                          case ANSI('3', '#'): /* DECDHL: 2*height, top */
                            nlattr = LATTR_TOP;
@@ -2095,51 +2105,51 @@ void term_out(Terminal *term)
                            break;
                        }
                        ldata = lineptr(term->curs.y);
-                       ldata[term->cols] &= ~LATTR_MODE;
-                       ldata[term->cols] |= nlattr;
+                       LINE_ATTRS(ldata-1) &= ~LATTR_MODE;
+                       LINE_ATTRS(ldata-1) |= nlattr;
                    }
                    break;
                  /* GZD4: G0 designate 94-set */
                  case ANSI('A', '('):
                    compatibility(VT100);
                    if (!term->cfg.no_remote_charset)
-                       term->cset_attr[0] = ATTR_GBCHR;
+                       term->cset_attr[0] = ATTR_WRAP(ATTR_GBCHR);
                    break;
                  case ANSI('B', '('):
                    compatibility(VT100);
                    if (!term->cfg.no_remote_charset)
-                       term->cset_attr[0] = ATTR_ASCII;
+                       term->cset_attr[0] = ATTR_WRAP(ATTR_ASCII);
                    break;
                  case ANSI('0', '('):
                    compatibility(VT100);
                    if (!term->cfg.no_remote_charset)
-                       term->cset_attr[0] = ATTR_LINEDRW;
+                       term->cset_attr[0] = ATTR_WRAP(ATTR_LINEDRW);
                    break;
                  case ANSI('U', '('): 
                    compatibility(OTHER);
                    if (!term->cfg.no_remote_charset)
-                       term->cset_attr[0] = ATTR_SCOACS
+                       term->cset_attr[0] = ATTR_WRAP(ATTR_SCOACS)
                    break;
                  /* G1D4: G1-designate 94-set */
                  case ANSI('A', ')'):
                    compatibility(VT100);
                    if (!term->cfg.no_remote_charset)
-                       term->cset_attr[1] = ATTR_GBCHR;
+                       term->cset_attr[1] = ATTR_WRAP(ATTR_GBCHR);
                    break;
                  case ANSI('B', ')'):
                    compatibility(VT100);
                    if (!term->cfg.no_remote_charset)
-                       term->cset_attr[1] = ATTR_ASCII;
+                       term->cset_attr[1] = ATTR_WRAP(ATTR_ASCII);
                    break;
                  case ANSI('0', ')'):
                    compatibility(VT100);
                    if (!term->cfg.no_remote_charset)
-                       term->cset_attr[1] = ATTR_LINEDRW;
+                       term->cset_attr[1] = ATTR_WRAP(ATTR_LINEDRW);
                    break;
                  case ANSI('U', ')'): 
                    compatibility(OTHER);
                    if (!term->cfg.no_remote_charset)
-                       term->cset_attr[1] = ATTR_SCOACS
+                       term->cset_attr[1] = ATTR_WRAP(ATTR_SCOACS)
                    break;
                  /* DOCS: Designate other coding system */
                  case ANSI('8', '%'):  /* Old Linux code */
@@ -2435,25 +2445,25 @@ void term_out(Terminal *term)
                                    break;
                                  case 1:       /* enable bold */
                                    compatibility(VT100AVO);
-                                   term->curr_attr |= ATTR_BOLD;
+                                   term->curr_attr.attr |= ATTR_BOLD;
                                    break;
                                  case 21:      /* (enable double underline) */
                                    compatibility(OTHER);
                                  case 4:       /* enable underline */
                                    compatibility(VT100AVO);
-                                   term->curr_attr |= ATTR_UNDER;
+                                   term->curr_attr.attr |= ATTR_UNDER;
                                    break;
                                  case 5:       /* enable blink */
                                    compatibility(VT100AVO);
-                                   term->curr_attr |= ATTR_BLINK;
+                                   term->curr_attr.attr |= ATTR_BLINK;
                                    break;
                                  case 6:       /* SCO light bkgrd */
                                    compatibility(SCOANSI);
                                    term->blink_is_real = FALSE;
-                                   term->curr_attr |= ATTR_BLINK;
+                                   term->curr_attr.attr |= ATTR_BLINK;
                                    break;
                                  case 7:       /* enable reverse video */
-                                   term->curr_attr |= ATTR_REVERSE;
+                                   term->curr_attr.attr |= ATTR_REVERSE;
                                    break;
                                  case 10:      /* SCO acs off */
                                    compatibility(SCOANSI);
@@ -2469,19 +2479,19 @@ void term_out(Terminal *term)
                                    term->sco_acs = 2; break;
                                  case 22:      /* disable bold */
                                    compatibility2(OTHER, VT220);
-                                   term->curr_attr &= ~ATTR_BOLD;
+                                   term->curr_attr.attr &= ~ATTR_BOLD;
                                    break;
                                  case 24:      /* disable underline */
                                    compatibility2(OTHER, VT220);
-                                   term->curr_attr &= ~ATTR_UNDER;
+                                   term->curr_attr.attr &= ~ATTR_UNDER;
                                    break;
                                  case 25:      /* disable blink */
                                    compatibility2(OTHER, VT220);
-                                   term->curr_attr &= ~ATTR_BLINK;
+                                   term->curr_attr.attr &= ~ATTR_BLINK;
                                    break;
                                  case 27:      /* disable reverse video */
                                    compatibility2(OTHER, VT220);
-                                   term->curr_attr &= ~ATTR_REVERSE;
+                                   term->curr_attr.attr &= ~ATTR_REVERSE;
                                    break;
                                  case 30:
                                  case 31:
@@ -2492,8 +2502,8 @@ void term_out(Terminal *term)
                                  case 36:
                                  case 37:
                                    /* foreground */
-                                   term->curr_attr &= ~ATTR_FGMASK;
-                                   term->curr_attr |=
+                                   term->curr_attr.color &= ~ATTR_FGMASK;
+                                   term->curr_attr.color |=
                                        (uint32_t)(term->esc_args[i] - 30) << ATTR_FGSHIFT;
                                    break;
                                  case 90:
@@ -2505,13 +2515,13 @@ void term_out(Terminal *term)
                                  case 96:
                                  case 97:
                                    /* xterm-style bright foreground */
-                                   term->curr_attr &= ~ATTR_FGMASK;
-                                   term->curr_attr |=
-                                       ((uint32_t)(term->esc_args[i] - 90 + 16) << ATTR_FGSHIFT);
+                                   term->curr_attr.color &= ~ATTR_FGMASK;
+                                   term->curr_attr.color |=
+                                       ((uint32_t)(term->esc_args[i] - 90 + 8) << ATTR_FGSHIFT);
                                    break;
                                  case 39:      /* default-foreground */
-                                   term->curr_attr &= ~ATTR_FGMASK;
-                                   term->curr_attr |= ATTR_DEFFG;
+                                   term->curr_attr.color &= ~ATTR_FGMASK;
+                                   term->curr_attr.color |= ATTR_DEFFG;
                                    break;
                                  case 40:
                                  case 41:
@@ -2522,8 +2532,8 @@ void term_out(Terminal *term)
                                  case 46:
                                  case 47:
                                    /* background */
-                                   term->curr_attr &= ~ATTR_BGMASK;
-                                   term->curr_attr |=
+                                   term->curr_attr.color &= ~ATTR_BGMASK;
+                                   term->curr_attr.color |=
                                        (uint32_t)(term->esc_args[i] - 40) << ATTR_BGSHIFT;
                                    break;
                                  case 100:
@@ -2535,21 +2545,37 @@ void term_out(Terminal *term)
                                  case 106:
                                  case 107:
                                    /* xterm-style bright background */
-                                   term->curr_attr &= ~ATTR_BGMASK;
-                                   term->curr_attr |=
-                                       ((uint32_t)(term->esc_args[i] - 100 + 16) << ATTR_BGSHIFT);
+                                   term->curr_attr.color &= ~ATTR_BGMASK;
+                                   term->curr_attr.color |=
+                                       ((uint32_t)(term->esc_args[i] - 100 + 8) << ATTR_BGSHIFT);
                                    break;
                                  case 49:      /* default-background */
-                                   term->curr_attr &= ~ATTR_BGMASK;
-                                   term->curr_attr |= ATTR_DEFBG;
+                                   term->curr_attr.color &= ~ATTR_BGMASK;
+                                   term->curr_attr.color |= ATTR_DEFBG;
                                    break;
+                                 case 38:   /* xterm 256-colour mode */
+                                   if (i+2 < term->esc_nargs &&
+                                       term->esc_args[i+1] == 5) {
+                                       term->curr_attr.color &= ~ATTR_FGMASK;
+                                       term->curr_attr.color |=
+                                           ((term->esc_args[i+2] & 0xFF)
+                                            << ATTR_FGSHIFT);
+                                       i += 2;
+                                   }
+                                   break;
+                                 case 48:   /* xterm 256-colour mode */
+                                   if (i+2 < term->esc_nargs &&
+                                       term->esc_args[i+1] == 5) {
+                                       term->curr_attr.color &= ~ATTR_BGMASK;
+                                       term->curr_attr.color |=
+                                           ((term->esc_args[i+2] & 0xFF)
+                                            << ATTR_BGSHIFT);
+                                       i += 2;
+                                   }
                                }
                            }
                            if (term->use_bce)
-                               term->erase_char = (' ' | ATTR_ASCII |
-                                                   (term->curr_attr & 
-                                                    (ATTR_FGMASK |
-                                                     ATTR_BGMASK)));
+                               set_erase_char(term);
                        }
                        break;
                      case 's':       /* save cursor */
@@ -2749,7 +2775,7 @@ void term_out(Terminal *term)
                        {
                            int n = def(term->esc_args[0], 1);
                            pos cursplus;
-                           unsigned long *p = term->cpos;
+                           struct attr_tag *p = term->cpos;
                            if (n > term->cols - term->curs.x)
                                n = term->cols - term->curs.x;
                            cursplus = term->curs;
@@ -2825,9 +2851,9 @@ void term_out(Terminal *term)
                        compatibility(SCOANSI);
                        term->blink_is_real = FALSE;
                        if (term->esc_args[0]>=1)
-                           term->curr_attr |= ATTR_BLINK;
+                           term->curr_attr.attr |= ATTR_BLINK;
                        else
-                           term->curr_attr &= ~ATTR_BLINK;
+                           term->curr_attr.attr &= ~ATTR_BLINK;
                        break;
                      case ANSI('E', '='):
                        compatibility(SCOANSI);
@@ -2840,10 +2866,10 @@ void term_out(Terminal *term)
                                (sco2ansicolour[term->esc_args[0] & 0x7] |
                                 (uint32_t)((term->esc_args[0] & 0x8) << 1)) <<
                                ATTR_FGSHIFT;
-                           term->curr_attr &= ~ATTR_FGMASK;
-                           term->curr_attr |= colour;
-                           term->default_attr &= ~ATTR_FGMASK;
-                           term->default_attr |= colour;
+                           term->curr_attr.color &= ~ATTR_FGMASK;
+                           term->curr_attr.color |= colour;
+                           term->default_attr.color &= ~ATTR_FGMASK;
+                           term->default_attr.color |= colour;
                        }
                        break;
                      case ANSI('G', '='):      /* set normal background */
@@ -2853,20 +2879,16 @@ void term_out(Terminal *term)
                                (sco2ansicolour[term->esc_args[0] & 0x7] |
                                 (uint32_t)((term->esc_args[0] & 0x8) << 1)) <<
                                ATTR_BGSHIFT;
-                           term->curr_attr &= ~ATTR_BGMASK;
-                           term->curr_attr |= colour;
-                           term->default_attr &= ~ATTR_BGMASK;
-                           term->default_attr |= colour;
+                           term->curr_attr.color &= ~ATTR_BGMASK;
+                           term->curr_attr.color |= colour;
+                           term->default_attr.color &= ~ATTR_BGMASK;
+                           term->default_attr.color |= colour;
                        }
                        break;
                      case ANSI('L', '='):
                        compatibility(SCOANSI);
                        term->use_bce = (term->esc_args[0] <= 0);
-                       term->erase_char = ERASE_CHAR;
-                       if (term->use_bce)
-                           term->erase_char = (' ' | ATTR_ASCII |
-                                               (term->curr_attr & 
-                                                (ATTR_FGMASK | ATTR_BGMASK)));
+                       set_erase_char(term);
                        break;
                      case ANSI('p', '"'): /* DECSCL: set compat level */
                        /*
@@ -3121,10 +3143,10 @@ void term_out(Terminal *term)
                     *
                     */
                  case 'F':
-                   term->cset_attr[term->cset = 0] = ATTR_LINEDRW;
+                   term->cset_attr[term->cset = 0] = ATTR_WRAP(ATTR_LINEDRW);
                    break;
                  case 'G':
-                   term->cset_attr[term->cset = 0] = ATTR_ASCII;
+                   term->cset_attr[term->cset = 0] = ATTR_WRAP(ATTR_ASCII);
                    break;
                  case 'H':
                    move(term, 0, 0, 0);
@@ -3241,11 +3263,11 @@ void term_out(Terminal *term)
                    break;
                  case 'p':
                    /* compatibility(ATARI) */
-                   term->curr_attr |= ATTR_REVERSE;
+                   term->curr_attr.attr |= ATTR_REVERSE;
                    break;
                  case 'q':
                    /* compatibility(ATARI) */
-                   term->curr_attr &= ~ATTR_REVERSE;
+                   term->curr_attr.attr &= ~ATTR_REVERSE;
                    break;
                  case 'v':            /* wrap Autowrap on - Wyse style */
                    /* compatibility(ATARI) */
@@ -3260,28 +3282,25 @@ void term_out(Terminal *term)
                    /* compatibility(OTHER) */
                    term->vt52_bold = FALSE;
                    term->curr_attr = ATTR_DEFAULT;
-                   if (term->use_bce)
-                       term->erase_char = (' ' | ATTR_ASCII |
-                                           (term->curr_attr & 
-                                            (ATTR_FGMASK | ATTR_BGMASK)));
+                   set_erase_char(term);
                    break;
                  case 'S':
                    /* compatibility(VI50) */
-                   term->curr_attr |= ATTR_UNDER;
+                   term->curr_attr.attr |= ATTR_UNDER;
                    break;
                  case 'W':
                    /* compatibility(VI50) */
-                   term->curr_attr &= ~ATTR_UNDER;
+                   term->curr_attr.attr &= ~ATTR_UNDER;
                    break;
                  case 'U':
                    /* compatibility(VI50) */
                    term->vt52_bold = TRUE;
-                   term->curr_attr |= ATTR_BOLD;
+                   term->curr_attr.attr |= ATTR_BOLD;
                    break;
                  case 'T':
                    /* compatibility(VI50) */
                    term->vt52_bold = FALSE;
-                   term->curr_attr &= ~ATTR_BOLD;
+                   term->curr_attr.attr &= ~ATTR_BOLD;
                    break;
 #endif
                }
@@ -3298,31 +3317,24 @@ void term_out(Terminal *term)
 #ifdef VT52_PLUS
              case VT52_FG:
                term->termstate = TOPLEVEL;
-               term->curr_attr &= ~ATTR_FGMASK;
-               term->curr_attr &= ~ATTR_BOLD;
-               term->curr_attr |= (c & 0x7) << ATTR_FGSHIFT;
+               term->curr_attr.color &= ~ATTR_FGMASK;
+               term->curr_attr.attr &= ~ATTR_BOLD;
+               term->curr_attr.color |= (c & 0x7) << ATTR_FGSHIFT;
                if ((c & 0x8) || term->vt52_bold)
-                   term->curr_attr |= ATTR_BOLD;
+                   term->curr_attr.attr |= ATTR_BOLD;
 
-               if (term->use_bce)
-                   term->erase_char = (' ' | ATTR_ASCII |
-                                       (term->curr_attr &
-                                        (ATTR_FGMASK | ATTR_BGMASK)));
+               set_erase_char(term);
                break;
              case VT52_BG:
                term->termstate = TOPLEVEL;
-               term->curr_attr &= ~ATTR_BGMASK;
-               term->curr_attr &= ~ATTR_BLINK;
-               term->curr_attr |= (c & 0x7) << ATTR_BGSHIFT;
+               term->curr_attr.color &= ~ATTR_BGMASK;
+               term->curr_attr.attr &= ~ATTR_BLINK;
+               term->curr_attr.color |= (c & 0x7) << ATTR_BGSHIFT;
 
-               /* Note: bold background */
                if (c & 0x8)
-                   term->curr_attr |= ATTR_BLINK;
+                   term->curr_attr.attr |= ATTR_BLINK;
 
-               if (term->use_bce)
-                   term->erase_char = (' ' | ATTR_ASCII |
-                                       (term->curr_attr &
-                                        (ATTR_FGMASK | ATTR_BGMASK)));
+               set_erase_char(term);
                break;
 #endif
              default: break;          /* placate gcc warning about enum use */
@@ -3343,7 +3355,7 @@ void term_out(Terminal *term)
  * alike to scroll-optimise one to the other. Return the degree of
  * similarity.
  */
-static int linecmp(Terminal *term, unsigned long *a, unsigned long *b)
+static int linecmp(Terminal *term, struct attr_tag *a, struct attr_tag *b)
 {
     int i, n;
 
@@ -3363,7 +3375,7 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise)
     unsigned long rv, cursor;
     pos scrpos;
     char ch[1024];
-    long cursor_background = ERASE_CHAR;
+    struct attr_tag cursor_background = ERASE_CHAR;
     unsigned long ticks;
 #ifdef OPTIMISE_SCROLL
     struct scrollregion *sr;
@@ -3409,10 +3421,10 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise)
         * to display the cursor covering the _whole_ character,
         * exactly as if it were one space to the left.
         */
-       unsigned long *ldata = lineptr(term->curs.y);
+       struct attr_tag *ldata = lineptr(term->curs.y);
        our_curs_x = term->curs.x;
        if (our_curs_x > 0 &&
-           (ldata[our_curs_x] & (CHAR_MASK | CSET_MASK)) == UCSWIDE)
+           (ldata[our_curs_x].attr & (CHAR_MASK | CSET_MASK)) == UCSWIDE)
            our_curs_x--;
     }
 
@@ -3421,11 +3433,11 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise)
                           term->disptext + our_curs_y * (term->cols + 1) +
                           our_curs_x)) {
        if (term->dispcurs > term->disptext && 
-           (*term->dispcurs & (CHAR_MASK | CSET_MASK)) == UCSWIDE)
-           term->dispcurs[-1] |= ATTR_INVALID;
-       if ( (term->dispcurs[1] & (CHAR_MASK | CSET_MASK)) == UCSWIDE)
-           term->dispcurs[1] |= ATTR_INVALID;
-       *term->dispcurs |= ATTR_INVALID;
+           ((*term->dispcurs).attr & (CHAR_MASK | CSET_MASK)) == UCSWIDE)
+           ATTR_INVALIDATE(term->dispcurs[-1]);
+       if ( (term->dispcurs[1].attr & (CHAR_MASK | CSET_MASK)) == UCSWIDE)
+           ATTR_INVALIDATE(term->dispcurs[1]);
+       ATTR_INVALIDATE(*term->dispcurs);
        term->curstype = 0;
     }
     term->dispcurs = NULL;
@@ -3444,10 +3456,10 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise)
 
     /* The normal screen data */
     for (i = 0; i < term->rows; i++) {
-       unsigned long *ldata;
+       struct attr_tag *ldata;
        unsigned long lattr;
        int idx, dirty_line, dirty_run, selected;
-       unsigned long attr = 0;
+       struct attr_tag attr = ATTR_WRAP(ATTR_CLEAR);
        int updated_line = 0;
        int start = 0;
        int ccount = 0;
@@ -3455,21 +3467,22 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise)
 
        scrpos.y = i + term->disptop;
        ldata = lineptr(scrpos.y);
-       lattr = (ldata[term->cols] & LATTR_MODE);
+       lattr = (LINE_ATTRS(ldata-1) & LATTR_MODE);
 
        idx = i * (term->cols + 1);
-       dirty_run = dirty_line = (ldata[term->cols] !=
-                                 term->disptext[idx + term->cols]);
-       term->disptext[idx + term->cols] = ldata[term->cols];
+       dirty_run = dirty_line = (LINE_ATTRS(ldata-1) !=
+                                 term->disptext[idx].attr); /* abstraction violation */
+       term->disptext[idx + term->cols].attr = LINE_ATTRS(ldata-1); /* abstraction violation */
 
        for (j = 0; j < term->cols; j++, idx++) {
-           unsigned long tattr, tchar;
-           unsigned long *d = ldata + j;
+           struct attr_tag tattr, tchar;
+           struct attr_tag *d = ldata + j;
            int break_run;
            scrpos.x = j;
 
-           tchar = (*d & (CHAR_MASK | CSET_MASK));
-           tattr = (*d & (ATTR_MASK ^ CSET_MASK));
+           tchar = ATTR_CHARALL((*d));// & (CHAR_MASK | CSET_MASK));
+           tattr = ATTR_ATTRS((*d));// & (ATTR_MASK ^ CSET_MASK));
+           tattr.attr &= ~CSET_MASK;
             // GrP fixme Don't remap any characters here for now.
             /*
            switch (tchar & CSET_MASK) {
@@ -3484,10 +3497,10 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise)
                break;
            }
             */
-           tattr |= (tchar & CSET_MASK);
-           tchar &= CHAR_MASK;
-           if ((d[1] & (CHAR_MASK | CSET_MASK)) == UCSWIDE)
-                   tattr |= ATTR_WIDE;
+           tattr.attr |= (tchar.attr & CSET_MASK);
+           tchar.attr &= CHAR_MASK;
+           if ((d[1].attr & (CHAR_MASK | CSET_MASK)) == UCSWIDE)
+                   tattr.attr |= ATTR_WIDE;
 
            /* Video reversing things */
            if (term->selstate == DRAGGING || term->selstate == SELECTED) {
@@ -3499,49 +3512,54 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise)
                                posPlt(scrpos, term->selend));
            } else
                selected = FALSE;
-           tattr = (tattr ^ rv
-                    ^ (selected ? ATTR_REVERSE : 0UL));
+
+           tattr = ATTR_XOR( tattr,
+                             ATTR_WRAP( rv ^ (selected
+                                              ? ATTR_REVERSE
+                                              : ATTR_CLEAR) ) ) ;
 
            /* 'Real' blinking ? */
-           if (term->blink_is_real && (tattr & ATTR_BLINK)) {
+           if (term->blink_is_real && ATTR_STATE(tattr, ATTR_BLINK)) {
                if (term->has_focus && term->tblinker) {
-                   tchar = ' '; // term->ucsdata->unitab_line[(unsigned char)' '];
+                   tchar = ATTR_WRAP(' '); // term->ucsdata->unitab_line[(unsigned char)' '];
                }
-               tattr &= ~ATTR_BLINK;
+               tattr = ATTR_OFF(tattr, ATTR_BLINK);
            }
 
            /*
             * Check the font we'll _probably_ be using to see if 
             * the character is wide when we don't want it to be.
             */
-           if ((tchar | tattr) != (term->disptext[idx]& ~ATTR_NARROW)) {
-               if ((tattr & ATTR_WIDE) == 0 && 
-                   char_width(ctx, (tchar | tattr) & 0xFFFF) == 2)
-                   tattr |= ATTR_NARROW;
-           } else if (term->disptext[idx]&ATTR_NARROW)
-               tattr |= ATTR_NARROW;
+           if (!ATTR_EQUAL(ATTR_OR(tchar, tattr),
+                           ATTR_OFF(term->disptext[idx], ATTR_NARROW))) {
+               if (!ATTR_STATE(tattr, ATTR_WIDE) && 
+                   char_width(ctx, ATTR_AND(ATTR_OR(tchar, tattr), ATTR_WRAP(0xFFFF)).attr) == 2)
+                   tattr = ATTR_ON(tattr, ATTR_NARROW);
+           } else if (ATTR_STATE(term->disptext[idx], ATTR_NARROW))
+               tattr = ATTR_ON(tattr, ATTR_NARROW);
 
            /* Cursor here ? Save the 'background' */
            if (i == our_curs_y && j == our_curs_x) {
-               cursor_background = tattr | tchar;
+               cursor_background = ATTR_OR(tattr, tchar);
                term->dispcurs = term->disptext + idx;
            }
 
-           if ((term->disptext[idx] ^ tattr) & ATTR_WIDE)
+           if (ATTR_STATE( ATTR_XOR(term->disptext[idx], tattr), ATTR_WIDE))
                dirty_line = TRUE;
 
-           break_run = (((tattr ^ attr) & term->attr_mask) ||
-               j - start >= sizeof(ch));
+           break_run = (!(ATTR_ZERO(ATTR_AND(ATTR_XOR(tattr, attr), term->attr_mask)))) ||
+               j - start >= sizeof(ch);
 
            /* Special hack for VT100 Linedraw glyphs */
             // GrP vt100 horizontal linedraw causes break_run to be set? (why?)
-           if ((attr & CSET_MASK) == 0x2300 && tchar >= 0xBA && tchar <= 0xBD)
+           if (ATTR_EQUAL(ATTR_AND(attr, ATTR_WRAP(CSET_MASK)), ATTR_WRAP(0x2300)) &&
+               tchar.attr >= 0xBA && tchar.attr <= 0xBD)
             {
                 break_run = TRUE;
             }
 
            if (!term->ucsdata->dbcs_screenfont && !dirty_line) {
-               if ((tchar | tattr) == term->disptext[idx])
+               if (ATTR_EQUAL(ATTR_OR(tchar, tattr), term->disptext[idx]))
                    break_run = TRUE;
                else if (!dirty_run && ccount == 1)
                    break_run = TRUE;
@@ -3560,13 +3578,13 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise)
                dirty_run = dirty_line;
            }
 
-           if ((tchar | tattr) != term->disptext[idx])
+           if (!ATTR_EQUAL(ATTR_OR(tchar, tattr), term->disptext[idx]))
                dirty_run = TRUE;
-           ch[ccount++] = (char) tchar;
-           term->disptext[idx] = tchar | tattr;
+           ch[ccount++] = (char) tchar.attr;
+           term->disptext[idx] = ATTR_OR(tchar, tattr);
 
            /* If it's a wide char step along to the next one. */
-           if (tattr & ATTR_WIDE) {
+           if (ATTR_STATE(tattr, ATTR_WIDE)) {
                if (++j < term->cols) {
                    idx++;
                    d++;
@@ -3576,7 +3594,7 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise)
                     * Ever.
                     */
                    assert(!(i == our_curs_y && j == our_curs_x));
-                   if (term->disptext[idx] != *d)
+                   if (!ATTR_EQUAL(term->disptext[idx], *d))
                        dirty_run = TRUE;
                    term->disptext[idx] = *d;
                }
@@ -3589,8 +3607,8 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise)
 
        /* Cursor on this line ? (and changed) */
        if (i == our_curs_y && (term->curstype != cursor || updated_line)) {
-           ch[0] = (char) (cursor_background & CHAR_MASK);
-           attr = (cursor_background & ATTR_MASK) | cursor;
+           ch[0] = (char) ATTR_CHAR(cursor_background).attr;
+           attr = ATTR_OR(ATTR_ATTRS(cursor_background), ATTR_WRAP(cursor));
            do_cursor(ctx, our_curs_x, i, ch, 1, attr, lattr);
            term->curstype = cursor;
        }
@@ -3684,7 +3702,7 @@ void term_paint(Terminal *term, Context ctx,
     if (bottom >= term->rows) bottom = term->rows-1;
 
     for (i = top; i <= bottom && i < term->rows; i++) {
-       if ((term->disptext[i * (term->cols + 1) + term->cols] &
+       if ((term->disptext[i * (term->cols + 1)].attr & /* abstraction violation */
             LATTR_MODE) == LATTR_NORM)
            for (j = left; j <= right && j < term->cols; j++)
                term->disptext[i * (term->cols + 1) + j] = ATTR_INVALID;
@@ -3746,7 +3764,7 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel)
 
     while (poslt(top, bottom)) {
        int nl = FALSE;
-       unsigned long *ldata = lineptr(top.y);
+       struct attr_tag *ldata = lineptr(top.y);
        pos nlpos;
 
        /*
@@ -3763,15 +3781,15 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel)
         * because in normal selection mode this means we need a
         * newline at the end)...
         */
-       if (!(ldata[term->cols] & LATTR_WRAPPED)) {
-           while (((ldata[nlpos.x - 1] & 0xFF) == 0x20 ||
-                   (DIRECT_CHAR(ldata[nlpos.x - 1]) &&
-                    (ldata[nlpos.x - 1] & CHAR_MASK) == 0x20))
+       if (!(LINE_ATTRS(ldata-1) & LATTR_WRAPPED)) {
+           while (((ldata[nlpos.x - 1].attr & 0xFF) == 0x20 ||
+                   (DIRECT_CHAR(ldata[nlpos.x - 1].attr) &&
+                    (ldata[nlpos.x - 1].attr & CHAR_MASK) == 0x20))
                   && poslt(top, nlpos))
                decpos(nlpos);
            if (poslt(nlpos, bottom))
                nl = TRUE;
-       } else if (ldata[term->cols] & LATTR_WRAPPED2) {
+       } else if (LINE_ATTRS(ldata-1) & LATTR_WRAPPED2) {
            /* Ignore the last char on the line in a WRAPPED2 line. */
            decpos(nlpos);
        }
@@ -3790,7 +3808,7 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel)
        }
 
        while (poslt(top, bottom) && poslt(top, nlpos)) {
-           unsigned int uc = (ldata[top.x] & 0xFFFF);
+           unsigned int uc = (ldata[top.x].attr & 0xFFFF);
 
            if (uc == UCSWIDE) {
                top.x++;
@@ -3864,7 +3882,7 @@ void term_copyall(Terminal *term)
  * The wordness array is mainly for deciding the disposition of the
  * US-ASCII characters.
  */
-static int wordtype(Terminal *term, uint32_t uc)
+static int wordtype(Terminal *term, struct attr_tag uc_in)
 {
     struct ucsword {
        unsigned int start, end, ctype;
@@ -3934,6 +3952,7 @@ static int wordtype(Terminal *term, uint32_t uc)
        0, 0, 0}
     };
     const struct ucsword *wptr;
+    unsigned long uc = uc_in.attr;
 
     uc &= (CSET_MASK | CHAR_MASK);
 
@@ -3983,7 +4002,7 @@ static int wordtype(Terminal *term, uint32_t uc)
  */
 static pos sel_spread_half(Terminal *term, pos p, int dir)
 {
-    unsigned long *ldata;
+    struct attr_tag *ldata;
     short wvalue;
     int topy = -sblines(term);
 
@@ -3995,9 +4014,9 @@ static pos sel_spread_half(Terminal *term, pos p, int dir)
         * In this mode, every character is a separate unit, except
         * for runs of spaces at the end of a non-wrapping line.
         */
-       if (!(ldata[term->cols] & LATTR_WRAPPED)) {
-           unsigned long *q = ldata + term->cols;
-           while (q > ldata && (q[-1] & CHAR_MASK) == 0x20)
+       if (!(LINE_ATTRS(ldata-1) & LATTR_WRAPPED)) {
+           struct attr_tag *q = ldata + term->cols;
+           while (q > ldata && (q[-1].attr & CHAR_MASK) == 0x20)
                q--;
            if (q == ldata + term->cols)
                q--;
@@ -4013,7 +4032,7 @@ static pos sel_spread_half(Terminal *term, pos p, int dir)
        wvalue = wordtype(term, UCSGET(ldata, p.x));
        if (dir == +1) {
            while (1) {
-               int maxcols = (ldata[term->cols] & LATTR_WRAPPED2 ?
+               int maxcols = (LINE_ATTRS(ldata-1) & LATTR_WRAPPED2 ?
                               term->cols-1 : term->cols);
                if (p.x < maxcols-1) {
                    if (wordtype(term, UCSGET(ldata, p.x + 1)) == wvalue)
@@ -4021,8 +4040,8 @@ static pos sel_spread_half(Terminal *term, pos p, int dir)
                    else
                        break;
                } else {
-                   if (ldata[term->cols] & LATTR_WRAPPED) {
-                       unsigned long *ldata2;
+                   if (LINE_ATTRS(ldata-1) & LATTR_WRAPPED) {
+                       struct attr_tag *ldata2;
                        ldata2 = lineptr(p.y+1);
                        if (wordtype(term, UCSGET(ldata2, 0)) == wvalue) {
                            p.x = 0;
@@ -4042,14 +4061,14 @@ static pos sel_spread_half(Terminal *term, pos p, int dir)
                    else
                        break;
                } else {
-                   unsigned long *ldata2;
+                   struct attr_tag *ldata2;
                    int maxcols;
                    if (p.y <= topy)
                        break;
                    ldata2 = lineptr(p.y-1);
-                   maxcols = (ldata2[term->cols] & LATTR_WRAPPED2 ?
+                   maxcols = (LINE_ATTRS(ldata2-1) & LATTR_WRAPPED2 ?
                              term->cols-1 : term->cols);
-                   if (ldata2[term->cols] & LATTR_WRAPPED) {
+                   if (LINE_ATTRS(ldata2-1) & LATTR_WRAPPED) {
                        if (wordtype(term, UCSGET(ldata2, maxcols-1))
                            == wvalue) {
                            p.x = maxcols-1;
@@ -4138,7 +4157,7 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked,
                Mouse_Action a, int x, int y, int shift, int ctrl, int alt)
 {
     pos selpoint;
-    unsigned long *ldata;
+    struct attr_tag *ldata;
     int raw_mouse = (term->xterm_mouse &&
                     !term->cfg.no_mouse_rep &&
                     !(term->cfg.mouse_override && shift));
@@ -4167,7 +4186,7 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked,
     selpoint.y = y + term->disptop;
     selpoint.x = x;
     ldata = lineptr(selpoint.y);
-    if ((ldata[term->cols] & LATTR_MODE) != LATTR_NORM)
+    if ((LINE_ATTRS(ldata-1) & LATTR_MODE) != LATTR_NORM)
        selpoint.x /= 2;
 
     if (raw_mouse) {
index b7f0ff920c3d7b664e698122d417c0a5dc40e324..35888cb1e9951d42721d72bac01eb5f6931ccf0f 100644 (file)
@@ -67,10 +67,10 @@ struct terminal_tag {
     int tempsblines;                  /* number of lines in temporary
                                          scrollback */
 
-    unsigned long *cpos;              /* cursor position (convenience) */
+    struct attr_tag *cpos;            /* cursor position (convenience) */
 
-    unsigned long *disptext;          /* buffer of text on real screen */
-    unsigned long *dispcurs;          /* location of cursor on real screen */
+    struct attr_tag *disptext;        /* buffer of text on real screen */
+    struct attr_tag *dispcurs;        /* location of cursor on real screen */
     unsigned long curstype;           /* type of cursor on real screen */
 
 #define VBELL_TIMEOUT (TICKSPERSEC/10) /* visual bell lasts 1/10 sec */
@@ -80,7 +80,7 @@ struct terminal_tag {
     int beep_overloaded;
     long lastbeep;
 
-#define TTYPE unsigned long
+#define TTYPE struct attr_tag
 #define TSIZE (sizeof(TTYPE))
 #define fix_cpos do { \
     term->cpos = lineptr(term->curs.y) + term->curs.x; \
@@ -90,8 +90,8 @@ struct terminal_tag {
     struct scrollregion *scrollhead, *scrolltail;
 #endif /* OPTIMISE_SCROLL */
 
-    unsigned long default_attr, curr_attr, save_attr;
-    unsigned long erase_char;
+    struct attr_tag default_attr, curr_attr, save_attr;
+    struct attr_tag erase_char;
 
     bufchain inbuf;                   /* terminal input buffer */
     pos curs;                         /* cursor */
@@ -101,7 +101,8 @@ struct terminal_tag {
     int wrap, wrapnext;                       /* wrap flags */
     int insert;                               /* insert-mode flag */
     int cset;                         /* 0 or 1: which char set */
-    int save_cset, save_csattr;               /* saved with cursor position */
+    int save_cset;                    /* saved with cursor position */
+    struct attr_tag save_csattr;       /* saved with cursor position */
     int save_utf, save_wnext;         /* saved with cursor position */
     int rvideo;                               /* global reverse video flag */
     unsigned long rvbell_startpoint;   /* for ESC[?5hESC[?5l vbell */
@@ -139,7 +140,7 @@ struct terminal_tag {
     int xterm_mouse;                  /* send mouse messages to app */
     int mouse_is_down;                /* used while tracking mouse buttons */
 
-    unsigned long cset_attr[2];
+    struct attr_tag cset_attr[2];
 
 /*
  * Saved settings on the alternate screen.
@@ -200,7 +201,7 @@ struct terminal_tag {
     short wordness[256];
 
     /* Mask of attributes to pay attention to when painting. */
-    unsigned long attr_mask;
+    struct attr_tag attr_mask;
 
     wchar_t *paste_buffer;
     int paste_len, paste_pos, paste_hold;
index c599d4f2743d08533773c73b0d46123bca0ee424..da702b0333bcb7db56560ab021c7eab45c00fb3b 100644 (file)
@@ -258,7 +258,7 @@ static void DrawSampleText(RectangleType bounds)
     
     fg_color = LstGetSelection(PrvGetObjectByID(DisplayPrefsFormForeColorListID));
     bg_color = LstGetSelection(PrvGetObjectByID(DisplayPrefsFormBackColorListID));
-    set_palm_color(fg_color * 2, bg_color * 2);
+    set_palm_color(fg_color, bg_color);
     
     if (PrvGetControlValue(DisplayPrefsFormSmallFontCheckboxID)) {
         FntSetFont(font_for_screen(font4x6));