Break the colour palette into a struct rather than just a single array
authornicm <nicm@openbsd.org>
Wed, 11 Aug 2021 20:49:55 +0000 (20:49 +0000)
committernicm <nicm@openbsd.org>
Wed, 11 Aug 2021 20:49:55 +0000 (20:49 +0000)
and use that to support the OSC palette-setting sequences in popups.
Also add a pane-colours array option to specify the defaults. GitHub
issue 2815.

12 files changed:
usr.bin/tmux/cmd-send-keys.c
usr.bin/tmux/colour.c
usr.bin/tmux/input.c
usr.bin/tmux/options-table.c
usr.bin/tmux/options.c
usr.bin/tmux/popup.c
usr.bin/tmux/screen-redraw.c
usr.bin/tmux/screen-write.c
usr.bin/tmux/tmux.1
usr.bin/tmux/tmux.h
usr.bin/tmux/tty.c
usr.bin/tmux/window.c

index f332e85..81a15b4 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-send-keys.c,v 1.65 2020/05/27 14:45:35 nicm Exp $ */
+/* $OpenBSD: cmd-send-keys.c,v 1.66 2021/08/11 20:49:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -197,8 +197,9 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
        }
 
        if (args_has(args, 'R')) {
-               window_pane_reset_palette(wp);
+               colour_palette_clear(&wp->palette);
                input_reset(wp->ictx, 1);
+               wp->flags |= (PANE_STYLECHANGED|PANE_REDRAW);
        }
 
        for (; np != 0; np--) {
index 41f3a10..47e5795 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: colour.c,v 1.20 2021/02/15 09:39:37 nicm Exp $ */
+/* $OpenBSD: colour.c,v 1.21 2021/08/11 20:49:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -944,3 +944,115 @@ colour_byname(const char *name)
        }
        return (-1);
 }
+
+/* Initialize palette. */
+void
+colour_palette_init(struct colour_palette *p)
+{
+       p->fg = 8;
+       p->bg = 8;
+       p->palette = NULL;
+       p->default_palette = NULL;
+}
+
+/* Clear palette. */
+void
+colour_palette_clear(struct colour_palette *p)
+{
+       p->fg = 8;
+       p->bg = 8;
+       if (p != NULL) {
+               free(p->palette);
+               p->palette = NULL;
+       }
+}
+
+/* Free a palette. */
+void
+colour_palette_free(struct colour_palette *p)
+{
+       if (p != NULL) {
+               free(p->palette);
+               p->palette = NULL;
+               free(p->default_palette);
+               p->default_palette = NULL;
+       }
+}
+
+/* Get a colour from a palette. */
+int
+colour_palette_get(struct colour_palette *p, int c)
+{
+       if (p == NULL)
+               return (-1);
+
+       if (c >= 90 && c <= 97)
+               c = 8 + c - 90;
+       else if (c & COLOUR_FLAG_256)
+               c &= ~COLOUR_FLAG_256;
+       else if (c >= 8)
+               return (-1);
+
+       if (p->palette != NULL && p->palette[c] != -1)
+               return (p->palette[c]);
+       if (p->default_palette != NULL && p->default_palette[c] != -1)
+               return (p->default_palette[c]);
+       return (-1);
+}
+
+/* Set a colour in a palette. */
+int
+colour_palette_set(struct colour_palette *p, int n, int c)
+{
+       u_int   i;
+
+       if (p == NULL || n > 255)
+               return (0);
+
+       if (c == -1 && p->palette == NULL)
+               return (0);
+
+       if (c != -1 && p->palette == NULL) {
+               if (p->palette == NULL)
+                       p->palette = xcalloc(256, sizeof *p->palette);
+               for (i = 0; i < 256; i++)
+                       p->palette[i] = -1;
+       }
+       p->palette[n] = c;
+       return (1);
+}
+
+/* Build palette defaults from an option. */
+void
+colour_palette_from_option(struct colour_palette *p, struct options *oo)
+{
+       struct options_entry            *o;
+       struct options_array_item       *a;
+       u_int                            i, n;
+       int                              c;
+
+       if (p == NULL)
+               return;
+
+       o = options_get(oo, "pane-colours");
+       if ((a = options_array_first(o)) == NULL) {
+               if (p->default_palette != NULL) {
+                       free(p->default_palette);
+                       p->default_palette = NULL;
+               }
+               return;
+       }
+       if (p->default_palette == NULL)
+               p->default_palette = xcalloc(256, sizeof *p->default_palette);
+       for (i = 0; i < 256; i++)
+               p->default_palette[i] = -1;
+       while (a != NULL) {
+               n = options_array_item_index(a);
+               if (n < 256) {
+                       c = options_array_item_value(a)->number;
+                       p->default_palette[n] = c;
+               }
+               a = options_array_next(a);
+       }
+
+}
index c791567..162faf2 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: input.c,v 1.189 2021/06/10 07:24:10 nicm Exp $ */
+/* $OpenBSD: input.c,v 1.190 2021/08/11 20:49:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -77,6 +77,7 @@ struct input_ctx {
        struct window_pane     *wp;
        struct bufferevent     *event;
        struct screen_write_ctx ctx;
+       struct colour_palette  *palette;
 
        struct input_cell       cell;
 
@@ -797,13 +798,15 @@ input_restore_state(struct input_ctx *ictx)
 
 /* Initialise input parser. */
 struct input_ctx *
-input_init(struct window_pane *wp, struct bufferevent *bev)
+input_init(struct window_pane *wp, struct bufferevent *bev,
+    struct colour_palette *palette)
 {
        struct input_ctx        *ictx;
 
        ictx = xcalloc(1, sizeof *ictx);
        ictx->wp = wp;
        ictx->event = bev;
+       ictx->palette = palette;
 
        ictx->input_space = INPUT_BUF_START;
        ictx->input_buf = xmalloc(INPUT_BUF_START);
@@ -1252,7 +1255,6 @@ static int
 input_esc_dispatch(struct input_ctx *ictx)
 {
        struct screen_write_ctx         *sctx = &ictx->ctx;
-       struct window_pane              *wp = ictx->wp;
        struct screen                   *s = sctx->s;
        struct input_table_entry        *entry;
 
@@ -1269,10 +1271,10 @@ input_esc_dispatch(struct input_ctx *ictx)
 
        switch (entry->type) {
        case INPUT_ESC_RIS:
-               if (wp != NULL)
-                       window_pane_reset_palette(wp);
+               colour_palette_clear(ictx->palette);
                input_reset_cell(ictx);
                screen_write_reset(sctx);
+               screen_write_fullredraw(sctx);
                break;
        case INPUT_ESC_IND:
                screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
@@ -1874,11 +1876,11 @@ input_csi_dispatch_winops(struct input_ctx *ictx)
                        case 0:
                        case 2:
                                screen_pop_title(sctx->s);
-                               if (wp != NULL) {
-                                       notify_pane("pane-title-changed", wp);
-                                       server_redraw_window_borders(wp->window);
-                                       server_status_window(wp->window);
-                               }
+                               if (wp == NULL)
+                                       break;
+                               notify_pane("pane-title-changed", wp);
+                               server_redraw_window_borders(wp->window);
+                               server_status_window(wp->window);
                                break;
                        }
                        break;
@@ -2498,37 +2500,35 @@ input_osc_colour_reply(struct input_ctx *ictx, u_int n, int c)
 static void
 input_osc_4(struct input_ctx *ictx, const char *p)
 {
-       struct window_pane      *wp = ictx->wp;
-       char                    *copy, *s, *next = NULL;
-       long                     idx;
-       int                      c;
-
-       if (wp == NULL)
-               return;
+       char    *copy, *s, *next = NULL;
+       long     idx;
+       int      c, bad = 0, redraw = 0;
 
        copy = s = xstrdup(p);
        while (s != NULL && *s != '\0') {
                idx = strtol(s, &next, 10);
-               if (*next++ != ';')
-                       goto bad;
-               if (idx < 0 || idx >= 0x100)
-                       goto bad;
+               if (*next++ != ';') {
+                       bad = 1;
+                       break;
+               }
+               if (idx < 0 || idx >= 256) {
+                       bad = 1;
+                       break;
+               }
 
                s = strsep(&next, ";");
                if ((c = input_osc_parse_colour(s)) == -1) {
                        s = next;
                        continue;
                }
-
-               window_pane_set_palette(wp, idx, c);
+               if (colour_palette_set(ictx->palette, idx, c))
+                       redraw = 1;
                s = next;
        }
-
-       free(copy);
-       return;
-
-bad:
-       log_debug("bad OSC 4: %s", p);
+       if (bad)
+               log_debug("bad OSC 4: %s", p);
+       if (redraw)
+               screen_write_fullredraw(&ictx->ctx);
        free(copy);
 }
 
@@ -2540,24 +2540,22 @@ input_osc_10(struct input_ctx *ictx, const char *p)
        struct grid_cell         defaults;
        int                      c;
 
-       if (wp == NULL)
-               return;
-
        if (strcmp(p, "?") == 0) {
-               tty_default_colours(&defaults, wp);
-               input_osc_colour_reply(ictx, 10, defaults.fg);
+               if (wp != NULL) {
+                       tty_default_colours(&defaults, wp);
+                       input_osc_colour_reply(ictx, 10, defaults.fg);
+               }
                return;
        }
 
-       if ((c = input_osc_parse_colour(p)) == -1)
-               goto bad;
-       wp->fg = c;
-       wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
-
-       return;
-
-bad:
-       log_debug("bad OSC 10: %s", p);
+       if ((c = input_osc_parse_colour(p)) == -1) {
+               log_debug("bad OSC 10: %s", p);
+               return;
+       }
+       ictx->palette->fg = c;
+       if (wp != NULL)
+               wp->flags |= PANE_STYLECHANGED;
+       screen_write_fullredraw(&ictx->ctx);
 }
 
 /* Handle the OSC 110 sequence for resetting background colour. */
@@ -2566,14 +2564,12 @@ input_osc_110(struct input_ctx *ictx, const char *p)
 {
        struct window_pane      *wp = ictx->wp;
 
-       if (wp == NULL)
-               return;
-
        if (*p != '\0')
                return;
-
-       wp->fg = 8;
-       wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
+       ictx->palette->fg = 8;
+       if (wp != NULL)
+               wp->flags |= PANE_STYLECHANGED;
+       screen_write_fullredraw(&ictx->ctx);
 }
 
 /* Handle the OSC 11 sequence for setting and querying background colour. */
@@ -2584,24 +2580,22 @@ input_osc_11(struct input_ctx *ictx, const char *p)
        struct grid_cell         defaults;
        int                      c;
 
-       if (wp == NULL)
-               return;
-
        if (strcmp(p, "?") == 0) {
-               tty_default_colours(&defaults, wp);
-               input_osc_colour_reply(ictx, 11, defaults.bg);
+               if (wp != NULL) {
+                       tty_default_colours(&defaults, wp);
+                       input_osc_colour_reply(ictx, 11, defaults.bg);
+               }
                return;
        }
 
-       if ((c = input_osc_parse_colour(p)) == -1)
-               goto bad;
-       wp->bg = c;
-       wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
-
-       return;
-
-bad:
-       log_debug("bad OSC 11: %s", p);
+       if ((c = input_osc_parse_colour(p)) == -1) {
+               log_debug("bad OSC 11: %s", p);
+               return;
+       }
+       ictx->palette->bg = c;
+       if (wp != NULL)
+               wp->flags |= PANE_STYLECHANGED;
+       screen_write_fullredraw(&ictx->ctx);
 }
 
 /* Handle the OSC 111 sequence for resetting background colour. */
@@ -2610,14 +2604,12 @@ input_osc_111(struct input_ctx *ictx, const char *p)
 {
        struct window_pane      *wp = ictx->wp;
 
-       if (wp == NULL)
-               return;
-
        if (*p != '\0')
                return;
-
-       wp->bg = 8;
-       wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
+       ictx->palette->bg = 8;
+       if (wp != NULL)
+               wp->flags |= PANE_STYLECHANGED;
+       screen_write_fullredraw(&ictx->ctx);
 }
 
 /* Handle the OSC 52 sequence for setting the clipboard. */
@@ -2692,34 +2684,35 @@ input_osc_52(struct input_ctx *ictx, const char *p)
 static void
 input_osc_104(struct input_ctx *ictx, const char *p)
 {
-       struct window_pane      *wp = ictx->wp;
-       char                    *copy, *s;
-       long                     idx;
-
-       if (wp == NULL)
-               return;
+       char    *copy, *s;
+       long     idx;
+       int      bad = 0, redraw = 0;
 
        if (*p == '\0') {
-               window_pane_reset_palette(wp);
+               colour_palette_clear(ictx->palette);
+               screen_write_fullredraw(&ictx->ctx);
                return;
        }
 
        copy = s = xstrdup(p);
        while (*s != '\0') {
                idx = strtol(s, &s, 10);
-               if (*s != '\0' && *s != ';')
-                       goto bad;
-               if (idx < 0 || idx >= 0x100)
-                       goto bad;
-
-               window_pane_unset_palette(wp, idx);
+               if (*s != '\0' && *s != ';') {
+                       bad = 1;
+                       break;
+               }
+               if (idx < 0 || idx >= 256) {
+                       bad = 1;
+                       break;
+               }
+               if (colour_palette_set(ictx->palette, idx, -1))
+                       redraw = 1;
                if (*s == ';')
                        s++;
        }
-       free(copy);
-       return;
-
-bad:
-       log_debug("bad OSC 104: %s", p);
+       if (bad)
+               log_debug("bad OSC 104: %s", p);
+       if (redraw)
+               screen_write_fullredraw(&ictx->ctx);
        free(copy);
 }
index 8cb25b2..a598756 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: options-table.c,v 1.148 2021/08/06 09:19:02 nicm Exp $ */
+/* $OpenBSD: options-table.c,v 1.149 2021/08/11 20:49:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -185,6 +185,7 @@ const struct options_name_map options_other_names[] = {
        { "display-panes-color", "display-panes-colour" },
        { "display-panes-active-color", "display-panes-active-colour" },
        { "clock-mode-color", "clock-mode-colour" },
+       { "pane-colors", "pane-colours" },
        { NULL, NULL }
 };
 
@@ -973,6 +974,14 @@ const struct options_table_entry options_table[] = {
          .text = "Style of the pane status lines."
        },
 
+       { .name = "pane-colours",
+         .type = OPTIONS_TABLE_COLOUR,
+         .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
+         .default_str = "",
+         .flags = OPTIONS_TABLE_IS_ARRAY,
+         .text = "The default colour palette for colours zero to 255."
+       },
+
        { .name = "remain-on-exit",
          .type = OPTIONS_TABLE_CHOICE,
          .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
index 87be58a..c07d691 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: options.c,v 1.62 2021/03/11 06:31:05 nicm Exp $ */
+/* $OpenBSD: options.c,v 1.63 2021/08/11 20:49:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -402,7 +402,7 @@ options_array_clear(struct options_entry *o)
                return;
 
        RB_FOREACH_SAFE(a, options_array, &o->value.array, a1)
-           options_array_free(o, a);
+               options_array_free(o, a);
 }
 
 union options_value *
@@ -425,6 +425,7 @@ options_array_set(struct options_entry *o, u_int idx, const char *value,
        struct options_array_item       *a;
        char                            *new;
        struct cmd_parse_result         *pr;
+       long long                        number;
 
        if (!OPTIONS_IS_ARRAY(o)) {
                if (cause != NULL)
@@ -479,6 +480,20 @@ options_array_set(struct options_entry *o, u_int idx, const char *value,
                return (0);
        }
 
+       if (o->tableentry->type == OPTIONS_TABLE_COLOUR) {
+               if ((number = colour_fromstring(value)) == -1) {
+                       xasprintf(cause, "bad colour: %s", value);
+                       return (-1);
+               }
+               a = options_array_item(o, idx);
+               if (a == NULL)
+                       a = options_array_new(o, idx);
+               else
+                       options_value_free(o, &a->value);
+               a->value.number = number;
+               return (0);
+       }
+
        if (cause != NULL)
                *cause = xstrdup("wrong array type");
        return (-1);
@@ -1113,6 +1128,10 @@ options_push_changes(const char *name)
                RB_FOREACH(wp, window_pane_tree, &all_window_panes)
                        wp->flags |= PANE_STYLECHANGED;
        }
+       if (strcmp(name, "pane-colours") == 0) {
+               RB_FOREACH(wp, window_pane_tree, &all_window_panes)
+                       colour_palette_from_option(&wp->palette, wp->options);
+       }
        if (strcmp(name, "pane-border-status") == 0) {
                RB_FOREACH(w, windows, &windows)
                        layout_fix_panes(w, NULL);
index 08b2fb2..34a06f5 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: popup.c,v 1.24 2021/08/05 09:43:51 nicm Exp $ */
+/* $OpenBSD: popup.c,v 1.25 2021/08/11 20:49:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -33,6 +33,7 @@ struct popup_data {
        int                       flags;
 
        struct screen             s;
+       struct colour_palette     palette;
        struct job               *job;
        struct input_ctx         *ictx;
        int                       status;
@@ -101,6 +102,7 @@ popup_init_ctx_cb(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx)
 {
        struct popup_data       *pd = ctx->arg;
 
+       ttyctx->palette = &pd->palette;
        ttyctx->redraw_cb = popup_redraw_cb;
        ttyctx->set_client_cb = popup_set_client_cb;
        ttyctx->arg = pd;
@@ -136,6 +138,8 @@ popup_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0)
        struct screen            s;
        struct screen_write_ctx  ctx;
        u_int                    i, px = pd->px, py = pd->py;
+       struct colour_palette   *palette = &pd->palette;
+       struct grid_cell         gc;
 
        screen_init(&s, pd->sx, pd->sy, 0);
        screen_write_start(&ctx, &s);
@@ -150,11 +154,13 @@ popup_draw_cb(struct client *c, __unused struct screen_redraw_ctx *ctx0)
        }
        screen_write_stop(&ctx);
 
+       memcpy(&gc, &grid_default_cell, sizeof gc);
+       gc.fg = pd->palette.fg;
+       gc.bg = pd->palette.bg;
+
        c->overlay_check = NULL;
-       for (i = 0; i < pd->sy; i++){
-               tty_draw_line(tty, &s, 0, i, pd->sx, px, py + i,
-                   &grid_default_cell, NULL);
-       }
+       for (i = 0; i < pd->sy; i++)
+               tty_draw_line(tty, &s, 0, i, pd->sx, px, py + i, &gc, palette);
        c->overlay_check = popup_check_cb;
 }
 
@@ -180,6 +186,7 @@ popup_free_cb(struct client *c)
        input_free(pd->ictx);
 
        screen_free(&pd->s);
+       colour_palette_free(&pd->palette);
        free(pd);
 }
 
@@ -389,6 +396,8 @@ popup_display(int flags, struct cmdq_item *item, u_int px, u_int py, u_int sx,
        pd->status = 128 + SIGHUP;
 
        screen_init(&pd->s, sx - 2, sy - 2, 0);
+       colour_palette_init(&pd->palette);
+       colour_palette_from_option(&pd->palette, global_w_options);
 
        pd->px = px;
        pd->py = py;
@@ -403,7 +412,7 @@ popup_display(int flags, struct cmdq_item *item, u_int px, u_int py, u_int sx,
        pd->job = job_run(shellcmd, argc, argv, s, cwd,
            popup_job_update_cb, popup_job_complete_cb, NULL, pd,
            JOB_NOWAIT|JOB_PTY|JOB_KEEPWRITE, pd->sx - 2, pd->sy - 2);
-       pd->ictx = input_init(NULL, job_get_event(pd->job));
+       pd->ictx = input_init(NULL, job_get_event(pd->job), &pd->palette);
 
        server_client_set_overlay(c, 0, popup_check_cb, popup_mode_cb,
            popup_draw_cb, popup_key_cb, popup_free_cb, popup_resize_cb, pd);
index e6230d5..51c6955 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: screen-redraw.c,v 1.86 2021/08/11 09:05:21 nicm Exp $ */
+/* $OpenBSD: screen-redraw.c,v 1.87 2021/08/11 20:49:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -800,12 +800,13 @@ screen_redraw_draw_status(struct screen_redraw_ctx *ctx)
 static void
 screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
 {
-       struct client   *c = ctx->c;
-       struct window   *w = c->session->curw->window;
-       struct tty      *tty = &c->tty;
-       struct screen   *s;
-       struct grid_cell defaults;
-       u_int            i, j, top, x, y, width;
+       struct client           *c = ctx->c;
+       struct window           *w = c->session->curw->window;
+       struct tty              *tty = &c->tty;
+       struct screen           *s = wp->screen;
+       struct colour_palette   *palette = &wp->palette;
+       struct grid_cell         defaults;
+       u_int                    i, j, top, x, y, width;
 
        log_debug("%s: %s @%u %%%u", __func__, c->name, w->id, wp->id);
 
@@ -815,8 +816,6 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
                top = ctx->statuslines;
        else
                top = 0;
-
-       s = wp->screen;
        for (j = 0; j < wp->sy; j++) {
                if (wp->yoff + j < ctx->oy || wp->yoff + j >= ctx->oy + ctx->sy)
                        continue;
@@ -849,7 +848,6 @@ screen_redraw_draw_pane(struct screen_redraw_ctx *ctx, struct window_pane *wp)
                    __func__, c->name, wp->id, i, j, x, y, width);
 
                tty_default_colours(&defaults, wp);
-               tty_draw_line(tty, s, i, j, width, x, y, &defaults,
-                   wp->palette);
+               tty_draw_line(tty, s, i, j, width, x, y, &defaults, palette);
        }
 }
index 42a8ba6..01b9477 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: screen-write.c,v 1.196 2021/08/06 09:34:09 nicm Exp $ */
+/* $OpenBSD: screen-write.c,v 1.197 2021/08/11 20:49:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -171,15 +171,6 @@ screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx,
 
        memset(ttyctx, 0, sizeof *ttyctx);
 
-       if (ctx->wp != NULL) {
-               tty_default_colours(&ttyctx->defaults, ctx->wp);
-               ttyctx->palette = ctx->wp->palette;
-       } else {
-               memcpy(&ttyctx->defaults, &grid_default_cell,
-                   sizeof ttyctx->defaults);
-               ttyctx->palette = NULL;
-       }
-
        ttyctx->s = s;
        ttyctx->sx = screen_size_x(s);
        ttyctx->sy = screen_size_y(s);
@@ -189,15 +180,21 @@ screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx,
        ttyctx->orlower = s->rlower;
        ttyctx->orupper = s->rupper;
 
-       if (ctx->init_ctx_cb != NULL)
+       memcpy(&ttyctx->defaults, &grid_default_cell, sizeof ttyctx->defaults);
+       if (ctx->init_ctx_cb != NULL) {
                ctx->init_ctx_cb(ctx, ttyctx);
-       else {
+               if (ttyctx->palette != NULL) {
+                       ttyctx->defaults.fg = ttyctx->palette->fg;
+                       ttyctx->defaults.bg = ttyctx->palette->bg;
+               }
+       } else {
                ttyctx->redraw_cb = screen_write_redraw_cb;
-               if (ctx->wp == NULL)
-                       ttyctx->set_client_cb = NULL;
-               else
+               if (ctx->wp != NULL) {
+                       tty_default_colours(&ttyctx->defaults, ctx->wp);
+                       ttyctx->palette = &ctx->wp->palette;
                        ttyctx->set_client_cb = screen_write_set_client_cb;
-               ttyctx->arg = ctx->wp;
+                       ttyctx->arg = ctx->wp;
+               }
        }
 
        if (ctx->wp != NULL &&
@@ -680,6 +677,7 @@ screen_write_box(struct screen_write_ctx *ctx, u_int nx, u_int ny)
 
        memcpy(&gc, &grid_default_cell, sizeof gc);
        gc.attr |= GRID_ATTR_CHARSET;
+       gc.flags |= GRID_FLAG_NOPALETTE;
 
        screen_write_putc(ctx, &gc, 'l');
        for (i = 1; i < nx - 1; i++)
@@ -1423,6 +1421,18 @@ screen_write_clearhistory(struct screen_write_ctx *ctx)
        grid_clear_history(ctx->s->grid);
 }
 
+/* Force a full redraw. */
+void
+screen_write_fullredraw(struct screen_write_ctx *ctx)
+{
+       struct tty_ctx   ttyctx;
+
+       screen_write_collect_flush(ctx, 0, __func__);
+
+       screen_write_initctx(ctx, &ttyctx, 1);
+       ttyctx.redraw_cb(&ttyctx);
+}
+
 /* Trim collected items. */
 static struct screen_write_citem *
 screen_write_collect_trim(struct screen_write_ctx *ctx, u_int y, u_int x,
index 5c96dd9..d15bde2 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tmux.1,v 1.849 2021/08/11 20:35:46 nicm Exp $
+.\" $OpenBSD: tmux.1,v 1.850 2021/08/11 20:49:55 nicm Exp $
 .\"
 .\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
 .\"
@@ -4147,7 +4147,6 @@ see the
 .Sx STYLES
 section.
 Attributes are ignored.
-.Pp
 .It Ic pane-base-index Ar index
 Like
 .Ic base-index ,
@@ -4305,6 +4304,13 @@ The alternate screen feature preserves the contents of the window when an
 interactive application starts and restores it on exit, so that any output
 visible before the application starts reappears unchanged after it exits.
 .Pp
+.It Ic pane-colours[] Ar colour
+The default colour palette.
+Each entry in the array defines the colour
+.Nm
+uses when the colour with that index is requested.
+The index may be from zero to 255.
+.Pp
 .It Xo Ic remain-on-exit
 .Op Ic on | off | failed
 .Xc
index 7afd130..ad96643 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.1114 2021/08/11 09:05:21 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.1115 2021/08/11 20:49:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -652,6 +652,15 @@ enum utf8_state {
 /* Special colours. */
 #define COLOUR_DEFAULT(c) ((c) == 8 || (c) == 9)
 
+/* Replacement palette. */
+struct colour_palette {
+       int      fg;
+       int      bg;
+
+       int     *palette;
+       int     *default_palette;
+};
+
 /* Grid attributes. Anything above 0xff is stored in an extended cell. */
 #define GRID_ATTR_BRIGHT 0x1
 #define GRID_ATTR_DIM 0x2
@@ -989,9 +998,6 @@ struct window_pane {
        u_int            xoff;
        u_int            yoff;
 
-       int              fg;
-       int              bg;
-
        int              flags;
 #define PANE_REDRAW 0x1
 #define PANE_DROP 0x2
@@ -1029,7 +1035,7 @@ struct window_pane {
 
        struct grid_cell cached_gc;
        struct grid_cell cached_active_gc;
-       int             *palette;
+       struct colour_palette palette;
 
        int              pipe_fd;
        struct bufferevent *pipe_event;
@@ -1427,7 +1433,7 @@ struct tty_ctx {
 
        /* The default colours and palette. */
        struct grid_cell defaults;
-       int             *palette;
+       struct colour_palette *palette;
 
        /* Containing region (usually window) offset and size. */
        int              bigger;
@@ -1827,11 +1833,11 @@ RB_HEAD(key_tables, key_table);
 /* Option data. */
 RB_HEAD(options_array, options_array_item);
 union options_value {
-       char                             *string;
-       long long                         number;
-       struct style                      style;
-       struct options_array              array;
-       struct cmd_list                  *cmdlist;
+       char                    *string;
+       long long                number;
+       struct style             style;
+       struct options_array     array;
+       struct cmd_list         *cmdlist;
 };
 
 /* Option table entries. */
@@ -2165,7 +2171,7 @@ void      tty_update_window_offset(struct window *);
 void   tty_update_client_offset(struct client *);
 void   tty_raw(struct tty *, const char *);
 void   tty_attributes(struct tty *, const struct grid_cell *,
-           const struct grid_cell *, int *);
+           const struct grid_cell *, struct colour_palette *);
 void   tty_reset(struct tty *);
 void   tty_region_off(struct tty *);
 void   tty_margin_off(struct tty *);
@@ -2181,7 +2187,7 @@ void      tty_puts(struct tty *, const char *);
 void   tty_putc(struct tty *, u_char);
 void   tty_putn(struct tty *, const void *, size_t, u_int);
 void   tty_cell(struct tty *, const struct grid_cell *,
-           const struct grid_cell *, int *);
+           const struct grid_cell *, struct colour_palette *);
 int    tty_init(struct tty *, struct client *);
 void   tty_resize(struct tty *);
 void   tty_set_size(struct tty *, u_int, u_int, u_int, u_int);
@@ -2191,7 +2197,7 @@ void      tty_stop_tty(struct tty *);
 void   tty_set_title(struct tty *, const char *);
 void   tty_update_mode(struct tty *, int, struct screen *);
 void   tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int,
-           u_int, u_int, const struct grid_cell *, int *);
+           u_int, u_int, const struct grid_cell *, struct colour_palette *);
 void   tty_sync_start(struct tty *);
 void   tty_sync_end(struct tty *);
 int    tty_open(struct tty *, char **);
@@ -2573,7 +2579,8 @@ void       recalculate_sizes(void);
 void    recalculate_sizes_now(int);
 
 /* input.c */
-struct input_ctx *input_init(struct window_pane *, struct bufferevent *);
+struct input_ctx *input_init(struct window_pane *, struct bufferevent *,
+            struct colour_palette *);
 void    input_free(struct input_ctx *);
 void    input_reset(struct input_ctx *, int);
 struct evbuffer *input_pending(struct input_ctx *);
@@ -2598,6 +2605,12 @@ int       colour_fromstring(const char *s);
 int     colour_256toRGB(int);
 int     colour_256to16(int);
 int     colour_byname(const char *);
+void    colour_palette_init(struct colour_palette *);
+void    colour_palette_clear(struct colour_palette *);
+void    colour_palette_free(struct colour_palette *);
+int     colour_palette_get(struct colour_palette *, int);
+int     colour_palette_set(struct colour_palette *, int, int);
+void    colour_palette_from_option(struct colour_palette *, struct options *);
 
 /* attributes.c */
 const char *attributes_tostring(int);
@@ -2737,6 +2750,7 @@ void       screen_write_clearendofscreen(struct screen_write_ctx *, u_int);
 void    screen_write_clearstartofscreen(struct screen_write_ctx *, u_int);
 void    screen_write_clearscreen(struct screen_write_ctx *, u_int);
 void    screen_write_clearhistory(struct screen_write_ctx *);
+void    screen_write_fullredraw(struct screen_write_ctx *);
 void    screen_write_collect_end(struct screen_write_ctx *);
 void    screen_write_collect_add(struct screen_write_ctx *,
             const struct grid_cell *);
@@ -2834,10 +2848,6 @@ struct window_pane *window_pane_find_by_id_str(const char *);
 struct window_pane *window_pane_find_by_id(u_int);
 int             window_pane_destroy_ready(struct window_pane *);
 void            window_pane_resize(struct window_pane *, u_int, u_int);
-void            window_pane_set_palette(struct window_pane *, u_int, int);
-void            window_pane_unset_palette(struct window_pane *, u_int);
-void            window_pane_reset_palette(struct window_pane *);
-int             window_pane_get_palette(struct window_pane *, int);
 int             window_pane_set_mode(struct window_pane *,
                     struct window_pane *, const struct window_mode *,
                     struct cmd_find_state *, struct args *);
index dd1ea91..e475a47 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tty.c,v 1.398 2021/08/11 07:51:31 nicm Exp $ */
+/* $OpenBSD: tty.c,v 1.399 2021/08/11 20:49:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -45,9 +45,12 @@ static void  tty_cursor_pane_unless_wrap(struct tty *,
                    const struct tty_ctx *, u_int, u_int);
 static void    tty_invalidate(struct tty *);
 static void    tty_colours(struct tty *, const struct grid_cell *);
-static void    tty_check_fg(struct tty *, int *, struct grid_cell *);
-static void    tty_check_bg(struct tty *, int *, struct grid_cell *);
-static void    tty_check_us(struct tty *, int *, struct grid_cell *);
+static void    tty_check_fg(struct tty *, struct colour_palette *,
+                   struct grid_cell *);
+static void    tty_check_bg(struct tty *, struct colour_palette *,
+                   struct grid_cell *);
+static void    tty_check_us(struct tty *, struct colour_palette *,
+                   struct grid_cell *);
 static void    tty_colours_fg(struct tty *, const struct grid_cell *);
 static void    tty_colours_bg(struct tty *, const struct grid_cell *);
 static void    tty_colours_us(struct tty *, const struct grid_cell *);
@@ -66,7 +69,7 @@ static void   tty_emulate_repeat(struct tty *, enum tty_code_code,
 static void    tty_repeat_space(struct tty *, u_int);
 static void    tty_draw_pane(struct tty *, const struct tty_ctx *, u_int);
 static void    tty_default_attributes(struct tty *, const struct grid_cell *,
-                   int *, u_int);
+                   struct colour_palette *, u_int);
 static int     tty_check_overlay(struct tty *, u_int, u_int);
 
 #define tty_use_margin(tty) \
@@ -939,27 +942,6 @@ tty_update_client_offset(struct client *c)
        c->flags |= (CLIENT_REDRAWWINDOW|CLIENT_REDRAWSTATUS);
 }
 
-/* Get a palette entry. */
-static int
-tty_get_palette(int *palette, int c)
-{
-       int     new;
-
-       if (palette == NULL)
-               return (-1);
-
-       new = -1;
-       if (c < 8)
-               new = palette[c];
-       else if (c >= 90 && c <= 97)
-               new = palette[8 + c - 90];
-       else if (c & COLOUR_FLAG_256)
-               new = palette[c & ~COLOUR_FLAG_256];
-       if (new == 0)
-               return (-1);
-       return (new);
-}
-
 /*
  * Is the region large enough to be worth redrawing once later rather than
  * probably several times now? Currently yes if it is more than 50% of the
@@ -1341,7 +1323,8 @@ tty_check_overlay(struct tty *tty, u_int px, u_int py)
 
 void
 tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
-    u_int atx, u_int aty, const struct grid_cell *defaults, int *palette)
+    u_int atx, u_int aty, const struct grid_cell *defaults,
+    struct colour_palette *palette)
 {
        struct grid             *gd = s->grid;
        struct grid_cell         gc, last;
@@ -1356,6 +1339,8 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
 
        log_debug("%s: px=%u py=%u nx=%u atx=%u aty=%u", __func__,
            px, py, nx, atx, aty);
+       log_debug("%s: defaults: fg=%d, bg=%d", __func__, defaults->fg,
+           defaults->bg);
 
        /*
         * py is the line in the screen to draw.
@@ -2061,7 +2046,7 @@ tty_cmd_syncstart(struct tty *tty, __unused const struct tty_ctx *ctx)
 
 void
 tty_cell(struct tty *tty, const struct grid_cell *gc,
-    const struct grid_cell *defaults, int *palette)
+    const struct grid_cell *defaults, struct colour_palette *palette)
 {
        const struct grid_cell  *gcp;
 
@@ -2381,17 +2366,19 @@ out:
 
 void
 tty_attributes(struct tty *tty, const struct grid_cell *gc,
-    const struct grid_cell *defaults, int *palette)
+    const struct grid_cell *defaults, struct colour_palette *palette)
 {
        struct grid_cell        *tc = &tty->cell, gc2;
        int                      changed;
 
        /* Copy cell and update default colours. */
        memcpy(&gc2, gc, sizeof gc2);
-       if (gc2.fg == 8)
-               gc2.fg = defaults->fg;
-       if (gc2.bg == 8)
-               gc2.bg = defaults->bg;
+       if (~gc->flags & GRID_FLAG_NOPALETTE) {
+               if (gc2.fg == 8)
+                       gc2.fg = defaults->fg;
+               if (gc2.bg == 8)
+                       gc2.bg = defaults->bg;
+       }
 
        /* Ignore cell if it is the same as the last one. */
        if (gc2.attr == tty->last_cell.attr &&
@@ -2533,13 +2520,14 @@ tty_colours(struct tty *tty, const struct grid_cell *gc)
        if (!COLOUR_DEFAULT(gc->bg) && gc->bg != tc->bg)
                tty_colours_bg(tty, gc);
 
-       /* Set the underscore color. */
+       /* Set the underscore colour. */
        if (gc->us != tc->us)
                tty_colours_us(tty, gc);
 }
 
 static void
-tty_check_fg(struct tty *tty, int *palette, struct grid_cell *gc)
+tty_check_fg(struct tty *tty, struct colour_palette *palette,
+    struct grid_cell *gc)
 {
        u_char  r, g, b;
        u_int   colours;
@@ -2554,7 +2542,7 @@ tty_check_fg(struct tty *tty, int *palette, struct grid_cell *gc)
                c = gc->fg;
                if (c < 8 && gc->attr & GRID_ATTR_BRIGHT)
                        c += 90;
-               if ((c = tty_get_palette(palette, c)) != -1)
+               if ((c = colour_palette_get(palette, c)) != -1)
                        gc->fg = c;
        }
 
@@ -2595,7 +2583,8 @@ tty_check_fg(struct tty *tty, int *palette, struct grid_cell *gc)
 }
 
 static void
-tty_check_bg(struct tty *tty, int *palette, struct grid_cell *gc)
+tty_check_bg(struct tty *tty, struct colour_palette *palette,
+    struct grid_cell *gc)
 {
        u_char  r, g, b;
        u_int   colours;
@@ -2603,7 +2592,7 @@ tty_check_bg(struct tty *tty, int *palette, struct grid_cell *gc)
 
        /* Perform substitution if this pane has a palette. */
        if (~gc->flags & GRID_FLAG_NOPALETTE) {
-               if ((c = tty_get_palette(palette, gc->bg)) != -1)
+               if ((c = colour_palette_get(palette, gc->bg)) != -1)
                        gc->bg = c;
        }
 
@@ -2646,13 +2635,14 @@ tty_check_bg(struct tty *tty, int *palette, struct grid_cell *gc)
 }
 
 static void
-tty_check_us(__unused struct tty *tty, int *palette, struct grid_cell *gc)
+tty_check_us(__unused struct tty *tty, struct colour_palette *palette,
+    struct grid_cell *gc)
 {
        int     c;
 
        /* Perform substitution if this pane has a palette. */
        if (~gc->flags & GRID_FLAG_NOPALETTE) {
-               if ((c = tty_get_palette(palette, gc->us)) != -1)
+               if ((c = colour_palette_get(palette, gc->us)) != -1)
                        gc->us = c;
        }
 
@@ -2793,8 +2783,8 @@ static void
 tty_window_default_style(struct grid_cell *gc, struct window_pane *wp)
 {
        memcpy(gc, &grid_default_cell, sizeof *gc);
-       gc->fg = wp->fg;
-       gc->bg = wp->bg;
+       gc->fg = wp->palette.fg;
+       gc->bg = wp->palette.bg;
 }
 
 void
@@ -2831,7 +2821,7 @@ tty_default_colours(struct grid_cell *gc, struct window_pane *wp)
 
 static void
 tty_default_attributes(struct tty *tty, const struct grid_cell *defaults,
-    int *palette, u_int bg)
+    struct colour_palette *palette, u_int bg)
 {
        struct grid_cell        gc;
 
index c267b43..fbf3da3 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: window.c,v 1.272 2021/06/10 07:33:41 nicm Exp $ */
+/* $OpenBSD: window.c,v 1.273 2021/08/11 20:49:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -478,6 +478,14 @@ window_set_active_pane(struct window *w, struct window_pane *wp, int notify)
        return (1);
 }
 
+static int
+window_pane_get_palette(struct window_pane *wp, int c)
+{
+       if (wp == NULL)
+               return (-1);
+       return (colour_palette_get(&wp->palette, c));
+}
+
 void
 window_redraw_active_switch(struct window *w, struct window_pane *wp)
 {
@@ -855,9 +863,6 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
 
        wp->fd = -1;
 
-       wp->fg = 8;
-       wp->bg = 8;
-
        TAILQ_INIT(&wp->modes);
 
        TAILQ_INIT (&wp->resize_queue);
@@ -867,6 +872,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
 
        wp->pipe_fd = -1;
 
+       colour_palette_init(&wp->palette);
        screen_init(&wp->base, sx, sy, hlimit);
        wp->screen = &wp->base;
 
@@ -916,7 +922,7 @@ window_pane_destroy(struct window_pane *wp)
        free((void *)wp->cwd);
        free(wp->shell);
        cmd_free_argv(wp->argc, wp->argv);
-       free(wp->palette);
+       colour_palette_free(&wp->palette);
        free(wp);
 }
 
@@ -968,7 +974,7 @@ window_pane_set_event(struct window_pane *wp)
 
        wp->event = bufferevent_new(wp->fd, window_pane_read_callback,
            NULL, window_pane_error_callback, wp);
-       wp->ictx = input_init(wp, wp->event);
+       wp->ictx = input_init(wp, wp->event, &wp->palette);
 
        bufferevent_enable(wp->event, EV_READ|EV_WRITE);
 }
@@ -1000,60 +1006,6 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
                wme->mode->resize(wme, sx, sy);
 }
 
-void
-window_pane_set_palette(struct window_pane *wp, u_int n, int colour)
-{
-       if (n > 0xff)
-               return;
-
-       if (wp->palette == NULL)
-               wp->palette = xcalloc(0x100, sizeof *wp->palette);
-
-       wp->palette[n] = colour;
-       wp->flags |= PANE_REDRAW;
-}
-
-void
-window_pane_unset_palette(struct window_pane *wp, u_int n)
-{
-       if (n > 0xff || wp->palette == NULL)
-               return;
-
-       wp->palette[n] = 0;
-       wp->flags |= PANE_REDRAW;
-}
-
-void
-window_pane_reset_palette(struct window_pane *wp)
-{
-       if (wp->palette == NULL)
-               return;
-
-       free(wp->palette);
-       wp->palette = NULL;
-       wp->flags |= PANE_REDRAW;
-}
-
-int
-window_pane_get_palette(struct window_pane *wp, int c)
-{
-       int     new;
-
-       if (wp == NULL || wp->palette == NULL)
-               return (-1);
-
-       new = -1;
-       if (c < 8)
-               new = wp->palette[c];
-       else if (c >= 90 && c <= 97)
-               new = wp->palette[8 + c - 90];
-       else if (c & COLOUR_FLAG_256)
-               new = wp->palette[c & ~COLOUR_FLAG_256];
-       if (new == 0)
-               return (-1);
-       return (new);
-}
-
 int
 window_pane_set_mode(struct window_pane *wp, struct window_pane *swp,
     const struct window_mode *mode, struct cmd_find_state *fs,