Query the client terminal for foreground and background colours and if
authornicm <nicm@openbsd.org>
Tue, 3 Jan 2023 11:43:24 +0000 (11:43 +0000)
committernicm <nicm@openbsd.org>
Tue, 3 Jan 2023 11:43:24 +0000 (11:43 +0000)
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).

usr.bin/tmux/cmd-queue.c
usr.bin/tmux/colour.c
usr.bin/tmux/input.c
usr.bin/tmux/tmux.h
usr.bin/tmux/tty-keys.c
usr.bin/tmux/tty.c

index 2ca2eb8..cfeb48c 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-queue.c,v 1.112 2022/12/16 08:22:05 nicm Exp $ */
+/* $OpenBSD: cmd-queue.c,v 1.113 2023/01/03 11:43:24 nicm Exp $ */
 
 /*
  * Copyright (c) 2013 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -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);
index 16080ae..4f7a9a0 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: colour.c,v 1.25 2022/03/24 12:07:25 nicm Exp $ */
+/* $OpenBSD: colour.c,v 1.26 2023/01/03 11:43:24 nicm Exp $ */
 
 /*
  * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -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);
        }
-
 }
index fd3ed07..6ca2f08 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: input.c,v 1.212 2022/11/11 08:37:55 nicm Exp $ */
+/* $OpenBSD: input.c,v 1.213 2023/01/03 11:43:24 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -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;
        }
index 4c2544b..f3b5766 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.1188 2022/12/26 19:16:03 jmc Exp $ */
+/* $OpenBSD: tmux.h,v 1.1189 2023/01/03 11:43:24 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -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 *);
index 06ac225..d0a423d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tty-keys.c,v 1.162 2022/11/11 08:44:11 nicm Exp $ */
+/* $OpenBSD: tty-keys.c,v 1.163 2023/01/03 11:43:24 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -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);
+}
index d3c6f96..a810aed 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tty.c,v 1.425 2022/11/11 08:37:55 nicm Exp $ */
+/* $OpenBSD: tty.c,v 1.426 2023/01/03 11:43:24 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -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