mirror of
https://github.com/tmux/tmux.git
synced 2024-12-24 18:38:48 +00:00
Query the client terminal for foreground and background colours and if
OSC 10 or 11 is received but no colour has been set inside tmux, return the colour from the first attached client (probably most people will have all light or or all dark terminals).
This commit is contained in:
parent
3fe01ff09c
commit
a41a927441
@ -834,7 +834,8 @@ cmdq_print_data(struct cmdq_item *item, int parse, struct evbuffer *evb)
|
||||
char *sanitized, *msg, *line;
|
||||
|
||||
if (!parse) {
|
||||
utf8_stravisx(&msg, data, size, VIS_OCTAL|VIS_CSTYLE);
|
||||
utf8_stravisx(&msg, data, size,
|
||||
VIS_OCTAL|VIS_CSTYLE|VIS_NOSLASH);
|
||||
log_debug("%s: %s", __func__, msg);
|
||||
} else {
|
||||
msg = EVBUFFER_DATA(evb);
|
||||
|
42
colour.c
42
colour.c
@ -960,6 +960,47 @@ colour_byname(const char *name)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Parse colour from an X11 string. */
|
||||
int
|
||||
colour_parseX11(const char *p)
|
||||
{
|
||||
double c, m, y, k = 0;
|
||||
u_int r, g, b;
|
||||
size_t len = strlen(p);
|
||||
int colour = -1;
|
||||
char *copy;
|
||||
|
||||
if ((len == 12 && sscanf(p, "rgb:%02x/%02x/%02x", &r, &g, &b) == 3) ||
|
||||
(len == 7 && sscanf(p, "#%02x%02x%02x", &r, &g, &b) == 3) ||
|
||||
sscanf(p, "%d,%d,%d", &r, &g, &b) == 3)
|
||||
colour = colour_join_rgb(r, g, b);
|
||||
else if ((len == 18 &&
|
||||
sscanf(p, "rgb:%04x/%04x/%04x", &r, &g, &b) == 3) ||
|
||||
(len == 13 && sscanf(p, "#%04x%04x%04x", &r, &g, &b) == 3))
|
||||
colour = colour_join_rgb(r >> 8, g >> 8, b >> 8);
|
||||
else if ((sscanf(p, "cmyk:%lf/%lf/%lf/%lf", &c, &m, &y, &k) == 4 ||
|
||||
sscanf(p, "cmy:%lf/%lf/%lf", &c, &m, &y) == 3) &&
|
||||
c >= 0 && c <= 1 && m >= 0 && m <= 1 &&
|
||||
y >= 0 && y <= 1 && k >= 0 && k <= 1) {
|
||||
colour = colour_join_rgb(
|
||||
(1 - c) * (1 - k) * 255,
|
||||
(1 - m) * (1 - k) * 255,
|
||||
(1 - y) * (1 - k) * 255);
|
||||
} else {
|
||||
while (len != 0 && *p == ' ') {
|
||||
p++;
|
||||
len--;
|
||||
}
|
||||
while (len != 0 && p[len - 1] == ' ')
|
||||
len--;
|
||||
copy = xstrndup(p, len);
|
||||
colour = colour_byname(copy);
|
||||
free(copy);
|
||||
}
|
||||
log_debug("%s: %s = %s", __func__, p, colour_tostring(colour));
|
||||
return (colour);
|
||||
}
|
||||
|
||||
/* Initialize palette. */
|
||||
void
|
||||
colour_palette_init(struct colour_palette *p)
|
||||
@ -1069,5 +1110,4 @@ colour_palette_from_option(struct colour_palette *p, struct options *oo)
|
||||
}
|
||||
a = options_array_next(a);
|
||||
}
|
||||
|
||||
}
|
||||
|
115
input.c
115
input.c
@ -1086,6 +1086,7 @@ input_reply(struct input_ctx *ictx, const char *fmt, ...)
|
||||
xvasprintf(&reply, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
log_debug("%s: %s", __func__, reply);
|
||||
bufferevent_write(bev, reply, strlen(reply));
|
||||
free(reply);
|
||||
}
|
||||
@ -2456,47 +2457,6 @@ input_top_bit_set(struct input_ctx *ictx)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Parse colour from OSC. */
|
||||
static int
|
||||
input_osc_parse_colour(const char *p)
|
||||
{
|
||||
double c, m, y, k = 0;
|
||||
u_int r, g, b;
|
||||
size_t len = strlen(p);
|
||||
int colour = -1;
|
||||
char *copy;
|
||||
|
||||
if ((len == 12 && sscanf(p, "rgb:%02x/%02x/%02x", &r, &g, &b) == 3) ||
|
||||
(len == 7 && sscanf(p, "#%02x%02x%02x", &r, &g, &b) == 3) ||
|
||||
sscanf(p, "%d,%d,%d", &r, &g, &b) == 3)
|
||||
colour = colour_join_rgb(r, g, b);
|
||||
else if ((len == 18 &&
|
||||
sscanf(p, "rgb:%04x/%04x/%04x", &r, &g, &b) == 3) ||
|
||||
(len == 13 && sscanf(p, "#%04x%04x%04x", &r, &g, &b) == 3))
|
||||
colour = colour_join_rgb(r >> 8, g >> 8, b >> 8);
|
||||
else if ((sscanf(p, "cmyk:%lf/%lf/%lf/%lf", &c, &m, &y, &k) == 4 ||
|
||||
sscanf(p, "cmy:%lf/%lf/%lf", &c, &m, &y) == 3) &&
|
||||
c >= 0 && c <= 1 && m >= 0 && m <= 1 &&
|
||||
y >= 0 && y <= 1 && k >= 0 && k <= 1) {
|
||||
colour = colour_join_rgb(
|
||||
(1 - c) * (1 - k) * 255,
|
||||
(1 - m) * (1 - k) * 255,
|
||||
(1 - y) * (1 - k) * 255);
|
||||
} else {
|
||||
while (len != 0 && *p == ' ') {
|
||||
p++;
|
||||
len--;
|
||||
}
|
||||
while (len != 0 && p[len - 1] == ' ')
|
||||
len--;
|
||||
copy = xstrndup(p, len);
|
||||
colour = colour_byname(copy);
|
||||
free(copy);
|
||||
}
|
||||
log_debug("%s: %s = %s", __func__, p, colour_tostring(colour));
|
||||
return (colour);
|
||||
}
|
||||
|
||||
/* Reply to a colour request. */
|
||||
static void
|
||||
input_osc_colour_reply(struct input_ctx *ictx, u_int n, int c)
|
||||
@ -2545,7 +2505,7 @@ input_osc_4(struct input_ctx *ictx, const char *p)
|
||||
input_osc_colour_reply(ictx, 4, c);
|
||||
continue;
|
||||
}
|
||||
if ((c = input_osc_parse_colour(s)) == -1) {
|
||||
if ((c = colour_parseX11(s)) == -1) {
|
||||
s = next;
|
||||
continue;
|
||||
}
|
||||
@ -2601,6 +2561,47 @@ bad:
|
||||
free(id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a client with a foreground for the pane. There isn't much to choose
|
||||
* between them so just use the first.
|
||||
*/
|
||||
static int
|
||||
input_get_fg_client(struct window_pane *wp)
|
||||
{
|
||||
struct window *w = wp->window;
|
||||
struct client *loop;
|
||||
|
||||
TAILQ_FOREACH(loop, &clients, entry) {
|
||||
if (loop->flags & CLIENT_UNATTACHEDFLAGS)
|
||||
continue;
|
||||
if (loop->session == NULL || !session_has(loop->session, w))
|
||||
continue;
|
||||
if (loop->tty.fg == -1)
|
||||
continue;
|
||||
return (loop->tty.fg);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Get a client with a background for the pane. */
|
||||
static int
|
||||
input_get_bg_client(struct window_pane *wp)
|
||||
{
|
||||
struct window *w = wp->window;
|
||||
struct client *loop;
|
||||
|
||||
TAILQ_FOREACH(loop, &clients, entry) {
|
||||
if (loop->flags & CLIENT_UNATTACHEDFLAGS)
|
||||
continue;
|
||||
if (loop->session == NULL || !session_has(loop->session, w))
|
||||
continue;
|
||||
if (loop->tty.bg == -1)
|
||||
continue;
|
||||
return (loop->tty.bg);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Handle the OSC 10 sequence for setting and querying foreground colour. */
|
||||
static void
|
||||
input_osc_10(struct input_ctx *ictx, const char *p)
|
||||
@ -2610,14 +2611,18 @@ input_osc_10(struct input_ctx *ictx, const char *p)
|
||||
int c;
|
||||
|
||||
if (strcmp(p, "?") == 0) {
|
||||
if (wp != NULL) {
|
||||
tty_default_colours(&defaults, wp);
|
||||
input_osc_colour_reply(ictx, 10, defaults.fg);
|
||||
}
|
||||
if (wp == NULL)
|
||||
return;
|
||||
tty_default_colours(&defaults, wp);
|
||||
if (COLOUR_DEFAULT(defaults.fg))
|
||||
c = input_get_fg_client(wp);
|
||||
else
|
||||
c = defaults.fg;
|
||||
input_osc_colour_reply(ictx, 10, c);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((c = input_osc_parse_colour(p)) == -1) {
|
||||
if ((c = colour_parseX11(p)) == -1) {
|
||||
log_debug("bad OSC 10: %s", p);
|
||||
return;
|
||||
}
|
||||
@ -2654,14 +2659,18 @@ input_osc_11(struct input_ctx *ictx, const char *p)
|
||||
int c;
|
||||
|
||||
if (strcmp(p, "?") == 0) {
|
||||
if (wp != NULL) {
|
||||
tty_default_colours(&defaults, wp);
|
||||
input_osc_colour_reply(ictx, 11, defaults.bg);
|
||||
}
|
||||
if (wp == NULL)
|
||||
return;
|
||||
tty_default_colours(&defaults, wp);
|
||||
if (COLOUR_DEFAULT(defaults.bg))
|
||||
c = input_get_bg_client(wp);
|
||||
else
|
||||
c = defaults.bg;
|
||||
input_osc_colour_reply(ictx, 11, c);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((c = input_osc_parse_colour(p)) == -1) {
|
||||
if ((c = colour_parseX11(p)) == -1) {
|
||||
log_debug("bad OSC 11: %s", p);
|
||||
return;
|
||||
}
|
||||
@ -2706,7 +2715,7 @@ input_osc_12(struct input_ctx *ictx, const char *p)
|
||||
return;
|
||||
}
|
||||
|
||||
if ((c = input_osc_parse_colour(p)) == -1) {
|
||||
if ((c = colour_parseX11(p)) == -1) {
|
||||
log_debug("bad OSC 12: %s", p);
|
||||
return;
|
||||
}
|
||||
|
7
tmux.h
7
tmux.h
@ -1380,6 +1380,8 @@ struct tty {
|
||||
u_int osy;
|
||||
|
||||
int mode;
|
||||
int fg;
|
||||
int bg;
|
||||
|
||||
u_int rlower;
|
||||
u_int rupper;
|
||||
@ -1411,6 +1413,10 @@ struct tty {
|
||||
#define TTY_HAVEXDA 0x200
|
||||
#define TTY_SYNCING 0x400
|
||||
#define TTY_HAVEDA2 0x800 /* Secondary DA. */
|
||||
#define TTY_HAVEFG 0x1000
|
||||
#define TTY_HAVEBG 0x2000
|
||||
#define TTY_ALL_REQUEST_FLAGS \
|
||||
(TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA|TTY_HAVEFG|TTY_HAVEBG)
|
||||
int flags;
|
||||
|
||||
struct tty_term *term;
|
||||
@ -2759,6 +2765,7 @@ int colour_fromstring(const char *s);
|
||||
int colour_256toRGB(int);
|
||||
int colour_256to16(int);
|
||||
int colour_byname(const char *);
|
||||
int colour_parseX11(const char *);
|
||||
void colour_palette_init(struct colour_palette *);
|
||||
void colour_palette_clear(struct colour_palette *);
|
||||
void colour_palette_free(struct colour_palette *);
|
||||
|
83
tty-keys.c
83
tty-keys.c
@ -59,6 +59,7 @@ static int tty_keys_device_attributes2(struct tty *, const char *, size_t,
|
||||
size_t *);
|
||||
static int tty_keys_extended_device_attributes(struct tty *, const char *,
|
||||
size_t, size_t *);
|
||||
static int tty_keys_colours(struct tty *, const char *, size_t, size_t *);
|
||||
|
||||
/* A key tree entry. */
|
||||
struct tty_key {
|
||||
@ -719,6 +720,17 @@ tty_keys_next(struct tty *tty)
|
||||
goto partial_key;
|
||||
}
|
||||
|
||||
/* Is this a colours response? */
|
||||
switch (tty_keys_colours(tty, buf, len, &size)) {
|
||||
case 0: /* yes */
|
||||
key = KEYC_UNKNOWN;
|
||||
goto complete_key;
|
||||
case -1: /* no, or not valid */
|
||||
break;
|
||||
case 1: /* partial */
|
||||
goto partial_key;
|
||||
}
|
||||
|
||||
/* Is this a mouse key press? */
|
||||
switch (tty_keys_mouse(tty, buf, len, &size, &m)) {
|
||||
case 0: /* yes */
|
||||
@ -1278,7 +1290,7 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len,
|
||||
if (len == 3)
|
||||
return (1);
|
||||
|
||||
/* Copy the rest up to a 'c'. */
|
||||
/* Copy the rest up to a c. */
|
||||
for (i = 0; i < (sizeof tmp); i++) {
|
||||
if (3 + i == len)
|
||||
return (1);
|
||||
@ -1352,7 +1364,7 @@ tty_keys_device_attributes2(struct tty *tty, const char *buf, size_t len,
|
||||
if (len == 3)
|
||||
return (1);
|
||||
|
||||
/* Copy the rest up to a 'c'. */
|
||||
/* Copy the rest up to a c. */
|
||||
for (i = 0; i < (sizeof tmp); i++) {
|
||||
if (3 + i == len)
|
||||
return (1);
|
||||
@ -1433,7 +1445,7 @@ tty_keys_extended_device_attributes(struct tty *tty, const char *buf,
|
||||
if (len == 4)
|
||||
return (1);
|
||||
|
||||
/* Copy the rest up to a '\033\\'. */
|
||||
/* Copy the rest up to \033\. */
|
||||
for (i = 0; i < (sizeof tmp) - 1; i++) {
|
||||
if (4 + i == len)
|
||||
return (1);
|
||||
@ -1465,3 +1477,68 @@ tty_keys_extended_device_attributes(struct tty *tty, const char *buf,
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle foreground or background input. Returns 0 for success, -1 for
|
||||
* failure, 1 for partial.
|
||||
*/
|
||||
static int
|
||||
tty_keys_colours(struct tty *tty, const char *buf, size_t len, size_t *size)
|
||||
{
|
||||
struct client *c = tty->client;
|
||||
u_int i;
|
||||
char tmp[128];
|
||||
int n;
|
||||
|
||||
*size = 0;
|
||||
if ((tty->flags & TTY_HAVEFG) && (tty->flags & TTY_HAVEBG))
|
||||
return (-1);
|
||||
|
||||
/* First four bytes are always \033]1 and 0 or 1 and ;. */
|
||||
if (buf[0] != '\033')
|
||||
return (-1);
|
||||
if (len == 1)
|
||||
return (1);
|
||||
if (buf[1] != ']')
|
||||
return (-1);
|
||||
if (len == 2)
|
||||
return (1);
|
||||
if (buf[2] != '1')
|
||||
return (-1);
|
||||
if (len == 3)
|
||||
return (1);
|
||||
if (buf[3] != '0' && buf[3] != '1')
|
||||
return (-1);
|
||||
if (len == 4)
|
||||
return (1);
|
||||
if (buf[4] != ';')
|
||||
return (-1);
|
||||
if (len == 5)
|
||||
return (1);
|
||||
|
||||
/* Copy the rest up to \033\. */
|
||||
for (i = 0; i < (sizeof tmp) - 1; i++) {
|
||||
if (5 + i == len)
|
||||
return (1);
|
||||
if (buf[5 + i - 1] == '\033' && buf[5 + i] == '\\')
|
||||
break;
|
||||
tmp[i] = buf[5 + i];
|
||||
}
|
||||
if (i == (sizeof tmp) - 1)
|
||||
return (-1);
|
||||
tmp[i - 1] = '\0';
|
||||
*size = 6 + i;
|
||||
|
||||
n = colour_parseX11(tmp);
|
||||
if (n != -1 && buf[3] == '0') {
|
||||
log_debug("%s: foreground is %s", c->name, colour_tostring(n));
|
||||
tty->fg = n;
|
||||
tty->flags |= TTY_HAVEFG;
|
||||
} else if (n != -1) {
|
||||
log_debug("%s: background is %s", c->name, colour_tostring(n));
|
||||
tty->bg = n;
|
||||
tty->flags |= TTY_HAVEBG;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
10
tty.c
10
tty.c
@ -108,6 +108,7 @@ tty_init(struct tty *tty, struct client *c)
|
||||
|
||||
tty->cstyle = SCREEN_CURSOR_DEFAULT;
|
||||
tty->ccolour = -1;
|
||||
tty->fg = tty->bg = -1;
|
||||
|
||||
if (tcgetattr(c->fd, &tty->tio) != 0)
|
||||
return (-1);
|
||||
@ -286,7 +287,6 @@ tty_open(struct tty *tty, char **cause)
|
||||
evtimer_set(&tty->timer, tty_timer_callback, tty);
|
||||
|
||||
tty_start_tty(tty);
|
||||
|
||||
tty_keys_build(tty);
|
||||
|
||||
return (0);
|
||||
@ -301,7 +301,7 @@ tty_start_timer_callback(__unused int fd, __unused short events, void *data)
|
||||
log_debug("%s: start timer fired", c->name);
|
||||
if ((tty->flags & (TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA)) == 0)
|
||||
tty_update_features(tty);
|
||||
tty->flags |= (TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA);
|
||||
tty->flags |= TTY_ALL_REQUEST_FLAGS;
|
||||
}
|
||||
|
||||
void
|
||||
@ -369,8 +369,12 @@ tty_send_requests(struct tty *tty)
|
||||
tty_puts(tty, "\033[>c");
|
||||
if (~tty->flags & TTY_HAVEXDA)
|
||||
tty_puts(tty, "\033[>q");
|
||||
if (~tty->flags & TTY_HAVEFG)
|
||||
tty_puts(tty, "\033]10;?\033\\");
|
||||
if (~tty->flags & TTY_HAVEBG)
|
||||
tty_puts(tty, "\033]11;?\033\\");
|
||||
} else
|
||||
tty->flags |= (TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA);
|
||||
tty->flags |= TTY_ALL_REQUEST_FLAGS;
|
||||
}
|
||||
|
||||
void
|
||||
|
Loading…
Reference in New Issue
Block a user