Allow use of more than 8 colors diff -r f94e0af361e2 config.h --- a/config.h Sat Aug 23 20:28:07 2008 -0700 +++ b/config.h Mon Aug 25 02:07:18 2008 -0700 @@ -10,24 +10,21 @@ * A_BOLD Extra bright or bold * A_PROTECT Protected mode * A_INVIS Invisible or blank mode - * COLOR(fg,bg) Color where fg and bg are one of: * - * COLOR_BLACK - * COLOR_RED - * COLOR_GREEN - * COLOR_YELLOW - * COLOR_BLUE - * COLOR_MAGENTA - * COLOR_CYAN - * COLOR_WHITE */ -#define ATTR_SELECTED COLOR(COLOR_RED,COLOR_BLACK) +#define ATTR_SELECTED A_NORMAL +#define FG_SELECTED COLORS==256 ? 68 : COLOR_BLUE +#define BG_SELECTED -1 /* curses attributes for normal (not selected) windows */ #define ATTR_NORMAL A_NORMAL +#define FG_NORMAL -1 +#define BG_NORMAL -1 /* status bar (command line option -s) position */ #define BARPOS BarTop /* BarBot, BarOff */ /* curses attributes for the status bar */ -#define BAR_ATTR COLOR(COLOR_RED,COLOR_BLACK) +#define BAR_ATTR A_NORMAL +#define FG_BAR COLOR_RED +#define BG_BAR -1 /* true if the statusbar text should be right aligned, * set to false if you prefer it left aligned */ #define BAR_ALIGN_RIGHT true diff -r f94e0af361e2 dvtm.c --- a/dvtm.c Sat Aug 23 20:28:07 2008 -0700 +++ b/dvtm.c Mon Aug 25 02:07:18 2008 -0700 @@ -87,7 +87,6 @@ typedef struct { enum { BarTop, BarBot, BarOff }; -#define COLOR(fg, bg) madtty_color_pair(fg, bg) #define countof(arr) (sizeof(arr) / sizeof((arr)[0])) #define sstrlen(str) (sizeof(str) - 1) #define max(x, y) ((x) > (y) ? (x) : (y)) @@ -380,10 +379,13 @@ draw_border(Client *c) { char buf[256]; char *s, t = '\0'; int x, y, o; - if (sel == c) + if (sel == c) { wattrset(c->window, ATTR_SELECTED); - else + madtty_color_set(c->window, FG_SELECTED, BG_SELECTED); + } else { wattrset(c->window, ATTR_NORMAL); + madtty_color_set(c->window, FG_NORMAL, BG_NORMAL); + } debug("length %d\n", sizeof(c->title)); getyx(c->window, y, x); curs_set(0); @@ -476,6 +478,7 @@ drawbar() { return; curs_set(0); attrset(BAR_ATTR); + madtty_color_set(stdscr, FG_BAR, BG_BAR); mvaddch(by, 0, '['); stext[maxlen] = '\0'; l = strlen(stext); diff -r f94e0af361e2 madtty.c --- a/madtty.c Sat Aug 23 20:28:07 2008 -0700 +++ b/madtty.c Mon Aug 25 02:07:18 2008 -0700 @@ -49,7 +49,13 @@ #define IS_CONTROL(ch) !((ch) & 0xffffff60UL) -static int has_default, is_utf8; +static int has_default, is_utf8, use_palette; + +static const unsigned palette_start = 1; +static const unsigned palette_end = 256; +static unsigned palette_cur; +static short *color2palette; +static unsigned color_hash(short f, short b) { return ((f+1) * (COLORS+1)) + b+1 ; } enum { C0_NUL = 0x00, @@ -94,6 +100,7 @@ struct madtty_t { /* geometry */ int rows, cols; unsigned curattrs; + short curfg, curbg; /* scrollback buffer */ struct t_row_t *scroll_buf; @@ -124,6 +131,8 @@ typedef struct t_row_t { typedef struct t_row_t { wchar_t *text; uint16_t *attr; + short *fg; + short *bg; unsigned dirty : 1; } t_row_t; @@ -166,12 +175,24 @@ static char const * const keytable[KEY_M [KEY_F(20)] = "\e[34~", }; -static void t_row_set(t_row_t *row, int start, int len, uint16_t attr) +__attribute__((const)) +static uint16_t build_attrs(unsigned curattrs) +{ + return ((curattrs & ~A_COLOR) | COLOR_PAIR(curattrs & 0xff)) + >> NCURSES_ATTR_SHIFT; +} + +static void t_row_set(t_row_t *row, int start, int len, madtty_t *t) { row->dirty = true; wmemset(row->text + start, 0, len); + attr_t attr = t ? build_attrs(t->curattrs) : 0; + short fg = t ? t->curfg : -1; + short bg = t ? t->curbg : -1; for (int i = start; i < len + start; i++) { row->attr[i] = attr; + row->fg [i] = fg; + row->bg [i] = bg; } } @@ -267,14 +288,7 @@ static void cursor_line_down(madtty_t *t t->curs_row = t->scroll_bot - 1; fill_scroll_buf(t, 1); - t_row_set(t->curs_row, 0, t->cols, 0); -} - -__attribute__((const)) -static uint16_t build_attrs(unsigned curattrs) -{ - return ((curattrs & ~A_COLOR) | COLOR_PAIR(curattrs & 0xff)) - >> NCURSES_ATTR_SHIFT; + t_row_set(t->curs_row, 0, t->cols, t); } static void new_escape_sequence(madtty_t *t) @@ -306,13 +320,14 @@ static void interpret_csi_SGR(madtty_t * if (pcount == 0) { /* special case: reset attributes */ t->curattrs = A_NORMAL; + t->curfg = t->curbg = -1; return; } for (i = 0; i < pcount; i++) { switch (param[i]) { #define CASE(x, op) case x: op; break - CASE(0, t->curattrs = A_NORMAL); + CASE(0, t->curattrs = A_NORMAL; t->curfg = t->curbg = -1); CASE(1, t->curattrs |= A_BOLD); CASE(4, t->curattrs |= A_UNDERLINE); CASE(5, t->curattrs |= A_BLINK); @@ -326,31 +341,31 @@ static void interpret_csi_SGR(madtty_t * CASE(28, t->curattrs &= ~A_INVIS); case 30 ... 37: /* fg */ - if (has_default) { - t->curattrs &= ~0xf0; - t->curattrs |= (param[i] + 1 - 30) << 4; - } else { - t->curattrs &= ~070; - t->curattrs |= (7 - (param[i] - 30)) << 3; - } + t->curfg = param[i]-30; + break; + + case 38: + assert(param[i+1] == 5); + t->curfg = param[i+2]; + i+=2; break; case 39: - t->curattrs &= has_default ? ~0xf0 : ~070; + t->curfg = -1; break; case 40 ... 47: /* bg */ - if (has_default) { - t->curattrs &= ~0x0f; - t->curattrs |= (param[i] + 1 - 40); - } else { - t->curattrs &= ~007; - t->curattrs |= (param[i] - 40); - } + t->curbg = param[i] - 40; + break; + + case 48: + assert(param[i+1] == 5); + t->curbg = param[i+2]; + i+=2; break; case 49: - t->curattrs &= has_default ? ~0x0f : ~007; + t->curbg = -1; break; default: @@ -363,7 +378,6 @@ static void interpret_csi_ED(madtty_t *t static void interpret_csi_ED(madtty_t *t, int param[], int pcount) { t_row_t *row, *start, *end; - attr_t attr = build_attrs(t->curattrs); /* decide range */ if (pcount && param[0] == 2) { @@ -373,16 +387,16 @@ static void interpret_csi_ED(madtty_t *t if (pcount && param[0] == 1) { start = t->lines; end = t->curs_row; - t_row_set(t->curs_row, 0, t->curs_col + 1, attr); + t_row_set(t->curs_row, 0, t->curs_col + 1, t); } else { t_row_set(t->curs_row, t->curs_col, - t->cols - t->curs_col, attr); + t->cols - t->curs_col, t); start = t->curs_row + 1; end = t->lines + t->rows; } for (row = start; row < end; row++) { - t_row_set(row, 0, t->cols, attr); + t_row_set(row, 0, t->cols, t); } } @@ -429,18 +443,15 @@ interpret_csi_C(madtty_t *t, char verb, /* Interpret the 'erase line' escape sequence */ static void interpret_csi_EL(madtty_t *t, int param[], int pcount) { - attr_t attr = build_attrs(t->curattrs); - switch (pcount ? param[0] : 0) { case 1: - t_row_set(t->curs_row, 0, t->curs_col + 1, attr); + t_row_set(t->curs_row, 0, t->curs_col + 1, t); break; case 2: - t_row_set(t->curs_row, 0, t->cols, attr); + t_row_set(t->curs_row, 0, t->cols, t); break; default: - t_row_set(t->curs_row, t->curs_col, t->cols - t->curs_col, - attr); + t_row_set(t->curs_row, t->curs_col, t->cols - t->curs_col, t); break; } } @@ -459,9 +470,11 @@ static void interpret_csi_ICH(madtty_t * for (i = t->cols - 1; i >= t->curs_col + n; i--) { row->text[i] = row->text[i - n]; row->attr[i] = row->attr[i - n]; + row->bg [i] = row->fg [i - n]; + row->fg [i] = row->fg [i - n]; } - t_row_set(row, t->curs_col, n, build_attrs(t->curattrs)); + t_row_set(row, t->curs_col, n, t); } /* Interpret the 'delete chars' sequence (DCH) */ @@ -478,16 +491,18 @@ static void interpret_csi_DCH(madtty_t * for (i = t->curs_col; i < t->cols - n; i++) { row->text[i] = row->text[i + n]; row->attr[i] = row->attr[i + n]; + row->bg [i] = row->fg [i + n]; + row->fg [i] = row->fg [i + n]; } - t_row_set(row, t->cols - n, n, build_attrs(t->curattrs)); + t_row_set(row, t->cols - n, n, t); } /* Interpret a 'scroll reverse' (SR) */ static void interpret_csi_SR(madtty_t *t) { t_row_roll(t->scroll_top, t->scroll_bot, -1); - t_row_set(t->scroll_top, 0, t->cols, build_attrs(t->curattrs)); + t_row_set(t->scroll_top, 0, t->cols, t); } /* Interpret an 'insert line' sequence (IL) */ @@ -497,12 +512,12 @@ static void interpret_csi_IL(madtty_t *t if (t->curs_row + n >= t->scroll_bot) { for (t_row_t *row = t->curs_row; row < t->scroll_bot; row++) { - t_row_set(row, 0, t->cols, build_attrs(t->curattrs)); + t_row_set(row, 0, t->cols, t); } } else { t_row_roll(t->curs_row, t->scroll_bot, -n); for (t_row_t *row = t->curs_row; row < t->curs_row + n; row++) { - t_row_set(row, 0, t->cols, build_attrs(t->curattrs)); + t_row_set(row, 0, t->cols, t); } } } @@ -514,12 +529,12 @@ static void interpret_csi_DL(madtty_t *t if (t->curs_row + n >= t->scroll_bot) { for (t_row_t *row = t->curs_row; row < t->scroll_bot; row++) { - t_row_set(row, 0, t->cols, build_attrs(t->curattrs)); + t_row_set(row, 0, t->cols, t); } } else { t_row_roll(t->curs_row, t->scroll_bot, n); for (t_row_t *row = t->scroll_bot - n; row < t->scroll_bot; row++) { - t_row_set(row, 0, t->cols, build_attrs(t->curattrs)); + t_row_set(row, 0, t->cols, t); } } } @@ -532,7 +547,7 @@ static void interpret_csi_ECH(madtty_t * if (t->curs_col + n < t->cols) { n = t->cols - t->curs_col; } - t_row_set(t->curs_row, t->curs_col, n, build_attrs(t->curattrs)); + t_row_set(t->curs_row, t->curs_col, n, t); } /* Interpret a 'set scrolling region' (DECSTBM) sequence */ @@ -602,6 +617,11 @@ static void es_interpret_csi(madtty_t *t t->curshid = true; if (csiparam[0] == 1) /* DECCKM: reset ANSI cursor (normal) key mode */ t->curskeymode = 0; + if (csiparam[0] == 47) { + /* use normal screen buffer */ + t->curattrs = A_NORMAL; + t->curfg = t->curbg = -1; + } break; case 'h': @@ -609,6 +629,11 @@ static void es_interpret_csi(madtty_t *t t->curshid = false; if (csiparam[0] == 1) /* DECCKM: set ANSI cursor (application) key mode */ t->curskeymode = 1; + if (csiparam[0] == 47) { + /* use alternate screen buffer */ + t->curattrs = A_NORMAL; + t->curfg = t->curbg = -1; + } break; } } @@ -858,6 +883,8 @@ static void madtty_putc(madtty_t *t, wch tmp->dirty = true; tmp->text[t->curs_col] = 0; tmp->attr[t->curs_col] = build_attrs(t->curattrs); + tmp->bg[t->curs_col] = t->curbg; + tmp->fg[t->curs_col] = t->curfg; t->curs_col++; } @@ -874,14 +901,22 @@ static void madtty_putc(madtty_t *t, wch (t->cols - t->curs_col - width)); memmove(tmp->attr + t->curs_col + width, tmp->attr + t->curs_col, (t->cols - t->curs_col - width) * sizeof(tmp->attr[0])); + memmove(tmp->fg + t->curs_col + width, tmp->fg + t->curs_col, + (t->cols - t->curs_col - width) * sizeof(tmp->fg[0])); + memmove(tmp->bg + t->curs_col + width, tmp->bg + t->curs_col, + (t->cols - t->curs_col - width) * sizeof(tmp->bg[0])); } tmp->text[t->curs_col] = wc; tmp->attr[t->curs_col] = build_attrs(t->curattrs); + tmp->bg[t->curs_col] = t->curbg; + tmp->fg[t->curs_col] = t->curfg; t->curs_col++; if (width == 2) { tmp->text[t->curs_col] = 0; tmp->attr[t->curs_col] = build_attrs(t->curattrs); + tmp->bg[t->curs_col] = t->curbg; + tmp->fg[t->curs_col] = t->curfg; t->curs_col++; } } @@ -950,6 +985,8 @@ madtty_t *madtty_create(int rows, int co for (i = 0; i < t->rows; i++) { t->lines[i].text = (wchar_t *)calloc(sizeof(wchar_t), t->cols); t->lines[i].attr = (uint16_t *)calloc(sizeof(uint16_t), t->cols); + t->lines[i].fg = calloc(sizeof(short), t->cols); + t->lines[i].bg = calloc(sizeof(short), t->cols); } t->pty = -1; /* no pty for now */ @@ -958,6 +995,7 @@ madtty_t *madtty_create(int rows, int co t->curs_row = t->lines; t->curs_col = 0; t->curattrs = A_NORMAL; /* white text over black background */ + t->curfg = t->curbg = -1; /* initial scrolling area is the whole window */ t->scroll_top = t->lines; @@ -969,6 +1007,8 @@ madtty_t *madtty_create(int rows, int co for (i = 0; i < t->scroll_buf_sz; i++) { t->scroll_buf[i].text = calloc(sizeof(wchar_t), t->cols); t->scroll_buf[i].attr = calloc(sizeof(uint16_t), t->cols); + t->scroll_buf[i].fg = calloc(sizeof(short), t->cols); + t->scroll_buf[i].bg = calloc(sizeof(short), t->cols); } t->scroll_buf_ptr = t->scroll_buf_len = 0; t->scroll_amount = 0; @@ -1003,6 +1043,8 @@ void madtty_resize(madtty_t *t, int rows for (int row = 0; row < t->rows; row++) { lines[row].text = realloc(lines[row].text, sizeof(wchar_t) * cols); lines[row].attr = realloc(lines[row].attr, sizeof(uint16_t) * cols); + lines[row].fg = realloc(lines[row].fg, sizeof(short) * cols); + lines[row].bg = realloc(lines[row].bg, sizeof(short) * cols); if (t->cols < cols) t_row_set(lines + row, t->cols, cols - t->cols, 0); else @@ -1012,6 +1054,8 @@ void madtty_resize(madtty_t *t, int rows for (int row = 0; row < t->scroll_buf_sz; row++) { sbuf[row].text = realloc(sbuf[row].text, sizeof(wchar_t) * cols); sbuf[row].attr = realloc(sbuf[row].attr, sizeof(uint16_t) * cols); + sbuf[row].fg = realloc(sbuf[row].fg, sizeof(short) * cols); + sbuf[row].bg = realloc(sbuf[row].bg, sizeof(short) * cols); if (t->cols < cols) t_row_set(sbuf + row, t->cols, cols - t->cols, 0); } @@ -1021,6 +1065,8 @@ void madtty_resize(madtty_t *t, int rows while (t->rows < rows) { lines[t->rows].text = (wchar_t *)calloc(sizeof(wchar_t), cols); lines[t->rows].attr = (uint16_t *)calloc(sizeof(uint16_t), cols); + lines[t->rows].fg = calloc(sizeof(short), cols); + lines[t->rows].bg = calloc(sizeof(short), cols); t_row_set(lines + t->rows, 0, t->cols, 0); t->rows++; } @@ -1043,11 +1089,15 @@ void madtty_destroy(madtty_t *t) for (i = 0; i < t->rows; i++) { free(t->lines[i].text); free(t->lines[i].attr); + free(t->lines[i].fg); + free(t->lines[i].bg); } free(t->lines); for (i = 0; i < t->scroll_buf_sz; i++) { free(t->scroll_buf[i].text); free(t->scroll_buf[i].attr); + free(t->scroll_buf[i].fg); + free(t->scroll_buf[i].bg); } free(t->scroll_buf); free(t); @@ -1071,8 +1121,13 @@ void madtty_draw(madtty_t *t, WINDOW *wi wmove(win, srow + i, scol); for (int j = 0; j < t->cols; j++) { - if (!j || row->attr[j] != row->attr[j - 1]) + if (!j + || row->attr[j] != row->attr[j - 1] + || row->fg[j] != row->fg[j-1] + || row->bg[j] != row->bg[j-1]) { wattrset(win, (attr_t)row->attr[j] << NCURSES_ATTR_SHIFT); + madtty_color_set(win, row->fg[j], row->bg[j]); + } if (is_utf8 && row->text[j] >= 128) { char buf[MB_CUR_MAX + 1]; int len; @@ -1130,7 +1185,7 @@ pid_t madtty_forkpty(madtty_t *t, const if (pid == 0) { setsid(); - setenv("TERM", "rxvt", 1); + setenv("TERM", use_palette ? "rxvt-256color" : "rxvt", 1); execv(p, (char *const*)argv); fprintf(stderr, "\nexecv() failed.\nCommand: '%s'\n", argv[0]); exit(1); @@ -1197,9 +1252,60 @@ void madtty_keypress_sequence(madtty_t * term_write(t, seq, len); } +void madtty_color_set(WINDOW *win, short fg, short bg) +{ + if (use_palette) { + if (fg==-1 && bg==-1) { + wcolor_set(win, 0, 0); + } else { + unsigned c = color_hash(fg, bg); + if (color2palette[c] == 0) { + short f, g; + color2palette[c] = palette_cur; + pair_content(palette_cur, &f, &g); + color2palette[color_hash(f,g)] = 0; + init_pair(palette_cur, fg, bg); + palette_cur++; + if (palette_cur >= palette_end) { + palette_cur = palette_start; + /* possibly use mvwinch/mvchgat to update palette */ + } + } + wcolor_set(win, color2palette[c], 0); + } + } else { + if (has_default) { + wcolor_set(win, (fg+1)*16 + bg+1, 0); + } else { + if (fg==-1) fg = COLOR_WHITE; + if (bg==-1) bg = COLOR_BLACK; + wcolor_set(win, (7-fg)*8 + bg, 0); + } + } +} + void madtty_init_colors(void) { - if (COLOR_PAIRS > 64) { + use_palette = 0; + + if (1 && COLORS >= 256 && COLOR_PAIRS >= 256) { + use_palette = 1; + use_default_colors(); + has_default = 1; + + color2palette = calloc((COLORS+1)*(COLORS+1), sizeof(short)); + int bg = 0, fg = 0; + for (int i=palette_start; i 64) { use_default_colors(); has_default = 1; @@ -1224,22 +1330,6 @@ void madtty_init_colors(void) } } -int madtty_color_pair(int fg, int bg) -{ - if (has_default) { - if (fg < -1) - fg = -1; - if (bg < -1) - bg = -1; - return COLOR_PAIR((fg + 1) * 16 + bg + 1); - } - if (fg < 0) - fg = COLOR_WHITE; - if (bg < 0) - bg = COLOR_BLACK; - return COLOR_PAIR((7 - fg) * 8 + bg); -} - void madtty_set_handler(madtty_t *t, madtty_handler_t handler) { t->handler = handler; diff -r f94e0af361e2 madtty.h --- a/madtty.h Sat Aug 23 20:28:07 2008 -0700 +++ b/madtty.h Mon Aug 25 02:07:18 2008 -0700 @@ -71,6 +71,7 @@ void madtty_keypress_sequence(madtty_t * void madtty_keypress_sequence(madtty_t *, const char *seq); void madtty_dirty(madtty_t *t); void madtty_draw(madtty_t *, WINDOW *win, int startrow, int startcol); +void madtty_color_set(WINDOW *win, short fg, short bg); void madtty_scroll(madtty_t *, int rows); void madtty_noscroll(madtty_t *);