mirror of
https://github.com/tmux/tmux.git
synced 2024-12-04 19:58:48 +00:00
Add support for the OSC 4 and OSC 104 palette setting escape sequences,
from S Gilles.
This commit is contained in:
parent
cae0fbbe8c
commit
314e933914
@ -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);
|
||||
}
|
||||
|
81
input.c
81
input.c
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
11
tmux.h
11
tmux.h
@ -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 *);
|
||||
|
36
tty.c
36
tty.c
@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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')
|
||||
|
@ -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) {
|
||||
|
59
window.c
59
window.c
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user