diff options
author | nicm <nicm> | 2017-01-07 15:28:13 +0000 |
---|---|---|
committer | nicm <nicm> | 2017-01-07 15:28:13 +0000 |
commit | 314e933914de4096c40e623c793049d26484d53a (patch) | |
tree | 8de850ef5c15384a8b2400af496200a235ed16ff | |
parent | cae0fbbe8c7cc16ac38aa8149ef9b4e2a54bce0e (diff) | |
download | rtmux-314e933914de4096c40e623c793049d26484d53a.tar.gz rtmux-314e933914de4096c40e623c793049d26484d53a.tar.bz2 rtmux-314e933914de4096c40e623c793049d26484d53a.zip |
Add support for the OSC 4 and OSC 104 palette setting escape sequences,
from S Gilles.
-rw-r--r-- | cmd-send-keys.c | 9 | ||||
-rw-r--r-- | input.c | 81 | ||||
-rw-r--r-- | screen-redraw.c | 4 | ||||
-rw-r--r-- | tmux.h | 11 | ||||
-rw-r--r-- | tty.c | 36 | ||||
-rw-r--r-- | window-choose.c | 1 | ||||
-rw-r--r-- | window-clock.c | 2 | ||||
-rw-r--r-- | window-copy.c | 2 | ||||
-rw-r--r-- | window.c | 59 |
9 files changed, 185 insertions, 20 deletions
diff --git a/cmd-send-keys.c b/cmd-send-keys.c index e660cfb3..ae861894 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -112,8 +112,10 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item) return (CMD_RETURN_NORMAL); } - if (args_has(args, 'R')) + if (args_has(args, 'R')) { + window_pane_reset_palette(wp); input_reset(wp, 1); + } for (; np != 0; np--) { for (i = 0; i < args->argc; i++) { @@ -128,8 +130,9 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item) if (literal) { ud = utf8_fromcstr(args->argv[i]); for (uc = ud; uc->size != 0; uc++) { - if (utf8_combine(uc, &wc) == UTF8_DONE) - window_pane_key(wp, NULL, s, wc, NULL); + if (utf8_combine(uc, &wc) != UTF8_DONE) + continue; + window_pane_key(wp, NULL, s, wc, NULL); } free(ud); } @@ -105,6 +105,9 @@ static void input_set_state(struct window_pane *, const struct input_transition *); static void input_reset_cell(struct input_ctx *); +static void input_osc_4(struct window_pane *, const char *); +static void input_osc_104(struct window_pane *, const char *); + /* Transition entry/exit handlers. */ static void input_clear(struct input_ctx *); static void input_ground(struct input_ctx *); @@ -162,6 +165,7 @@ enum input_esc_type { INPUT_ESC_SCSG0_ON, INPUT_ESC_SCSG1_OFF, INPUT_ESC_SCSG1_ON, + INPUT_ESC_ST, }; /* Escape command table. */ @@ -179,6 +183,7 @@ static const struct input_table_entry input_esc_table[] = { { 'E', "", INPUT_ESC_NEL }, { 'H', "", INPUT_ESC_HTS }, { 'M', "", INPUT_ESC_RI }, + { '\\', "", INPUT_ESC_ST }, { 'c', "", INPUT_ESC_RIS }, }; @@ -1141,6 +1146,7 @@ input_esc_dispatch(struct input_ctx *ictx) switch (entry->type) { case INPUT_ESC_RIS: + window_pane_reset_palette(ictx->wp); input_reset_cell(ictx); screen_write_reset(sctx); break; @@ -1188,6 +1194,9 @@ input_esc_dispatch(struct input_ctx *ictx) case INPUT_ESC_SCSG1_OFF: ictx->cell.g1set = 0; break; + case INPUT_ESC_ST: + /* ST terminates OSC but the state transition already did it. */ + break; } return (0); @@ -1850,10 +1859,16 @@ input_exit_osc(struct input_ctx *ictx) screen_set_title(ictx->ctx.s, p); server_status_window(ictx->wp->window); break; + case 4: + input_osc_4(ictx->wp, p); + break; case 12: if (*p != '?') /* ? is colour request */ screen_set_cursor_colour(ictx->ctx.s, p); break; + case 104: + input_osc_104(ictx->wp, p); + break; case 112: if (*p == '\0') /* no arguments allowed */ screen_set_cursor_colour(ictx->ctx.s, ""); @@ -1961,3 +1976,69 @@ input_utf8_close(struct input_ctx *ictx) return (0); } + +/* Handle the OSC 4 sequence for setting (multiple) palette entries. */ +static void +input_osc_4(struct window_pane *wp, const char *p) +{ + char *copy, *s, *next = NULL; + long idx; + u_int r, g, b; + + 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; + + s = strsep(&next, ";"); + if (sscanf(s, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3) { + s = next; + continue; + } + + window_pane_set_palette(wp, idx, colour_join_rgb(r, g, b)); + s = next; + } + + free(copy); + return; + +bad: + log_debug("bad OSC 4: %s", p); + free(copy); +} + +/* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */ +static void +input_osc_104(struct window_pane *wp, const char *p) +{ + char *copy, *s; + long idx; + + if (*p == '\0') { + window_pane_reset_palette(wp); + 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 == ';') + s++; + } + free(copy); + return; + +bad: + log_debug("bad OSC 104: %s", p); + free(copy); +} diff --git a/screen-redraw.c b/screen-redraw.c index 84a951dc..b7833716 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -588,6 +588,8 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp, u_int top) gc.bg = active_colour; else gc.bg = colour; + gc.flags |= GRID_FLAG_NOPALETTE; + tty_attributes(tty, &gc, wp); for (ptr = buf; *ptr != '\0'; ptr++) { if (*ptr < '0' || *ptr > '9') @@ -615,6 +617,8 @@ draw_text: gc.fg = active_colour; else gc.fg = colour; + gc.flags |= GRID_FLAG_NOPALETTE; + tty_attributes(tty, &gc, wp); tty_puts(tty, buf); @@ -576,6 +576,7 @@ enum utf8_state { #define GRID_FLAG_PADDING 0x4 #define GRID_FLAG_EXTENDED 0x8 #define GRID_FLAG_SELECTED 0x10 +#define GRID_FLAG_NOPALETTE 0x20 /* Grid line flags. */ #define GRID_LINE_WRAPPED 0x1 @@ -829,6 +830,8 @@ struct window_pane { struct grid_cell colgc; + int *palette; + int pipe_fd; struct bufferevent *pipe_event; size_t pipe_off; @@ -857,6 +860,11 @@ struct window_pane { TAILQ_HEAD(window_panes, window_pane); RB_HEAD(window_pane_tree, window_pane); +#define WINDOW_PANE_PALETTE_HAS(wp, c) \ + ((wp) != NULL && (wp)->palette != NULL && \ + ((c) < 0x100 || (c) & COLOUR_FLAG_256) && \ + (wp)->palette[(c) & 0xff] != 0) + /* Window structure. */ struct window { u_int id; @@ -2126,6 +2134,9 @@ void window_pane_alternate_on(struct window_pane *, struct grid_cell *, int); void window_pane_alternate_off(struct window_pane *, struct grid_cell *, 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_set_mode(struct window_pane *, const struct window_mode *); void window_pane_reset_mode(struct window_pane *); @@ -48,8 +48,10 @@ static void tty_cursor_pane(struct tty *, const struct tty_ctx *, u_int, u_int); static void tty_colours(struct tty *, const struct grid_cell *); -static void tty_check_fg(struct tty *, struct grid_cell *); -static void tty_check_bg(struct tty *, struct grid_cell *); +static void tty_check_fg(struct tty *, const struct window_pane *, + struct grid_cell *); +static void tty_check_bg(struct tty *, const struct window_pane *, + 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 *); @@ -1507,8 +1509,8 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc, } /* Fix up the colours if necessary. */ - tty_check_fg(tty, &gc2); - tty_check_bg(tty, &gc2); + tty_check_fg(tty, wp, &gc2); + tty_check_bg(tty, wp, &gc2); /* If any bits are being cleared, reset everything. */ if (tc->attr & ~gc2.attr) @@ -1604,12 +1606,18 @@ tty_colours(struct tty *tty, const struct grid_cell *gc) tty_colours_bg(tty, gc); } -void -tty_check_fg(struct tty *tty, struct grid_cell *gc) +static void +tty_check_fg(struct tty *tty, const struct window_pane *wp, + struct grid_cell *gc) { u_char r, g, b; u_int colours; + /* Perform substitution if this pane has a palette */ + if ((~gc->flags & GRID_FLAG_NOPALETTE) && + gc->fg != 8 && WINDOW_PANE_PALETTE_HAS(wp, gc->fg)) + gc->fg = wp->palette[gc->fg & 0xff]; + /* Is this a 24-bit colour? */ if (gc->fg & COLOUR_FLAG_RGB) { /* Not a 24-bit terminal? Translate to 256-colour palette. */ @@ -1646,12 +1654,18 @@ tty_check_fg(struct tty *tty, struct grid_cell *gc) } } -void -tty_check_bg(struct tty *tty, struct grid_cell *gc) +static void +tty_check_bg(struct tty *tty, const struct window_pane *wp, + struct grid_cell *gc) { u_char r, g, b; u_int colours; + /* Perform substitution if this pane has a palette */ + if ((~gc->flags & GRID_FLAG_NOPALETTE) && + gc->bg != 8 && WINDOW_PANE_PALETTE_HAS(wp, gc->bg)) + gc->bg = wp->palette[gc->bg & 0xff]; + /* Is this a 24-bit colour? */ if (gc->bg & COLOUR_FLAG_RGB) { /* Not a 24-bit terminal? Translate to 256-colour palette. */ @@ -1826,6 +1840,9 @@ tty_default_colours(struct grid_cell *gc, const struct window_pane *wp) gc->fg = agc->fg; else gc->fg = wgc->fg; + + if (gc->fg != 8 && WINDOW_PANE_PALETTE_HAS(wp, gc->fg)) + gc->fg = wp->palette[gc->fg & 0xff]; } if (gc->bg == 8) { @@ -1835,6 +1852,9 @@ tty_default_colours(struct grid_cell *gc, const struct window_pane *wp) gc->bg = agc->bg; else gc->bg = wgc->bg; + + if (gc->bg != 8 && WINDOW_PANE_PALETTE_HAS(wp, gc->bg)) + gc->bg = wp->palette[gc->bg & 0xff]; } } diff --git a/window-choose.c b/window-choose.c index a30916a1..e18b89a3 100644 --- a/window-choose.c +++ b/window-choose.c @@ -796,6 +796,7 @@ window_choose_write_line(struct window_pane *wp, struct screen_write_ctx *ctx, last = screen_size_y(s) - 1; memcpy(&gc, &grid_default_cell, sizeof gc); + gc.flags |= GRID_FLAG_NOPALETTE; if (data->selected == data->top + py) style_apply(&gc, oo, "mode-style"); diff --git a/window-clock.c b/window-clock.c index 97121108..94f014fc 100644 --- a/window-clock.c +++ b/window-clock.c @@ -230,6 +230,7 @@ window_clock_draw_screen(struct window_pane *wp) screen_write_cursormove(&ctx, x, y); memcpy(&gc, &grid_default_cell, sizeof gc); + gc.flags |= GRID_FLAG_NOPALETTE; gc.fg = colour; screen_write_puts(&ctx, &gc, "%s", tim); } @@ -242,6 +243,7 @@ window_clock_draw_screen(struct window_pane *wp) y = (screen_size_y(s) / 2) - 3; memcpy(&gc, &grid_default_cell, sizeof gc); + gc.flags |= GRID_FLAG_NOPALETTE; gc.bg = colour; for (ptr = tim; *ptr != '\0'; ptr++) { if (*ptr >= '0' && *ptr <= '9') diff --git a/window-copy.c b/window-copy.c index 2d19f6c6..398683e2 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1253,6 +1253,7 @@ window_copy_write_line(struct window_pane *wp, struct screen_write_ctx *ctx, size_t size = 0; style_apply(&gc, oo, "mode-style"); + gc.flags |= GRID_FLAG_NOPALETTE; if (py == 0) { size = xsnprintf(hdr, sizeof hdr, @@ -1455,6 +1456,7 @@ window_copy_update_selection(struct window_pane *wp, int may_redraw) /* Set colours and selection. */ style_apply(&gc, oo, "mode-style"); + gc.flags |= GRID_FLAG_NOPALETTE; screen_set_selection(s, sx, sy, endsx, endsy, data->rectflag, &gc); if (data->rectflag && may_redraw) { @@ -447,24 +447,30 @@ window_set_active_pane(struct window *w, struct window_pane *wp) void window_redraw_active_switch(struct window *w, struct window_pane *wp) { - const struct grid_cell *agc, *wgc; + const struct grid_cell *gc; if (wp == w->active) return; /* * If window-style and window-active-style are the same, we don't need - * to redraw panes when switching active panes. Otherwise, if the - * active or inactive pane do not have a custom style, they will need - * to be redrawn. + * to redraw panes when switching active panes. */ - agc = options_get_style(w->options, "window-active-style"); - wgc = options_get_style(w->options, "window-style"); - if (style_equal(agc, wgc)) + gc = options_get_style(w->options, "window-active-style"); + if (style_equal(gc, options_get_style(w->options, "window-style"))) return; - if (style_equal(&grid_default_cell, &w->active->colgc)) + + /* + * If the now active or inactive pane do not have a custom style or if + * the palette is different, they need to be redrawn. + */ + if (WINDOW_PANE_PALETTE_HAS(w->active, w->active->colgc.fg) || + WINDOW_PANE_PALETTE_HAS(w->active, w->active->colgc.bg) || + style_equal(&grid_default_cell, &w->active->colgc)) w->active->flags |= PANE_REDRAW; - if (style_equal(&grid_default_cell, &wp->colgc)) + if (WINDOW_PANE_PALETTE_HAS(wp, wp->colgc.fg) || + WINDOW_PANE_PALETTE_HAS(wp, wp->colgc.bg) || + style_equal(&grid_default_cell, &wp->colgc)) wp->flags |= PANE_REDRAW; } @@ -829,6 +835,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); free(wp); } @@ -1092,6 +1099,40 @@ window_pane_alternate_off(struct window_pane *wp, struct grid_cell *gc, wp->flags |= PANE_REDRAW; } +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; +} + static void window_pane_mode_timer(__unused int fd, __unused short events, void *arg) { |