On some Windows terminals, if TIOCWINSZ does not return xpixel and
authornicm <nicm@openbsd.org>
Mon, 30 Sep 2024 08:10:20 +0000 (08:10 +0000)
committernicm <nicm@openbsd.org>
Mon, 30 Sep 2024 08:10:20 +0000 (08:10 +0000)
ypixel (they are zero), if this is the case then try the query escape
sequences. From Dmitry Galchinsky in GitHub issue 4099.

usr.bin/tmux/tmux.h
usr.bin/tmux/tty-keys.c
usr.bin/tmux/tty.c

index 731cf75..606c23c 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.1228 2024/09/30 07:54:51 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.1229 2024/09/30 08:10:20 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1474,6 +1474,7 @@ struct tty {
 #define TTY_HAVEXDA 0x200
 #define TTY_SYNCING 0x400
 #define TTY_HAVEDA2 0x800 /* Secondary DA. */
+#define TTY_WINSIZEQUERY 0x1000
 #define TTY_ALL_REQUEST_FLAGS \
        (TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA)
        int              flags;
@@ -2370,6 +2371,7 @@ void      tty_cell(struct tty *, const struct grid_cell *,
 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);
+void   tty_invalidate(struct tty *);
 void   tty_start_tty(struct tty *);
 void   tty_send_requests(struct tty *);
 void   tty_repeat_requests(struct tty *);
index a3b5f62..5109b88 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tty-keys.c,v 1.178 2024/08/26 07:45:05 nicm Exp $ */
+/* $OpenBSD: tty-keys.c,v 1.179 2024/09/30 08:10:20 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -654,6 +654,74 @@ tty_keys_next1(struct tty *tty, const char *buf, size_t len, key_code *key,
        return (-1);
 }
 
+/* Process window size change escape sequences. */
+static int
+tty_keys_winsz(struct tty *tty, const char *buf, size_t len, size_t *size)
+{
+       struct client   *c = tty->client;
+       size_t           end;
+       char             tmp[64];
+       u_int            sx, sy, xpixel, ypixel, char_x, char_y;
+
+       *size = 0;
+
+       /* If we did not request this, ignore it. */
+       if (!(tty->flags & TTY_WINSIZEQUERY))
+               return (-1);
+
+       /* First two bytes are always \033[. */
+       if (buf[0] != '\033')
+               return (-1);
+       if (len == 1)
+               return (1);
+       if (buf[1] != '[')
+               return (-1);
+       if (len == 2)
+               return (1);
+
+       /*
+        * Stop at either 't' or anything that isn't a
+        * number or ';'.
+        */
+       for (end = 2; end < len && end != sizeof tmp; end++) {
+               if (buf[end] == 't')
+                       break;
+               if (!isdigit((u_char)buf[end]) && buf[end] != ';')
+                       break;
+       }
+       if (end == len)
+               return (1);
+       if (end == sizeof tmp || buf[end] != 't')
+               return (-1);
+
+       /* Copy to the buffer. */
+       memcpy(tmp, buf + 2, end - 2);
+       tmp[end - 2] = '\0';
+
+       /* Try to parse the window size sequence. */
+       if (sscanf(tmp, "8;%u;%u", &sy, &sx) == 2) {
+               /* Window size in characters. */
+               tty_set_size(tty, sx, sy, tty->xpixel, tty->ypixel);
+
+               *size = end + 1;
+               return (0);
+       } else if (sscanf(tmp, "4;%u;%u", &ypixel, &xpixel) == 2) {
+               /* Window size in pixels. */
+               char_x = (xpixel && tty->sx) ? xpixel / tty->sx : 0;
+               char_y = (ypixel && tty->sy) ? ypixel / tty->sy : 0;
+               tty_set_size(tty, tty->sx, tty->sy, char_x, char_y);
+               tty_invalidate(tty);
+
+               tty->flags &= ~TTY_WINSIZEQUERY;
+               *size = end + 1;
+               return (0);
+       }
+
+       log_debug("%s: unrecognized window size sequence: %s", c->name, tmp);
+       return (-1);
+}
+
+
 /* Process at least one key in the buffer. Return 0 if no keys present. */
 int
 tty_keys_next(struct tty *tty)
@@ -754,6 +822,17 @@ tty_keys_next(struct tty *tty)
                goto partial_key;
        }
 
+       /* Check for window size query */
+       switch (tty_keys_winsz(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;
+       }
+
 first_key:
        /* Try to lookup complete key. */
        n = tty_keys_next1(tty, buf, len, &key, &size, expired);
index 51dd937..83e665f 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tty.c,v 1.438 2024/08/04 09:42:23 nicm Exp $ */
+/* $OpenBSD: tty.c,v 1.439 2024/09/30 08:10:20 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -42,7 +42,6 @@ static void   tty_cursor_pane(struct tty *, const struct tty_ctx *, u_int,
                    u_int);
 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 *, struct colour_palette *,
                    struct grid_cell *);
@@ -135,6 +134,14 @@ tty_resize(struct tty *tty)
                        ypixel = 0;
                } else
                        ypixel = ws.ws_ypixel / sy;
+
+               if ((xpixel == 0 || ypixel == 0) &&
+                   tty->out != NULL &&
+                   !(tty->flags & TTY_WINSIZEQUERY) &&
+                   (tty->term->flags & TERM_VT100LIKE)) {
+                       tty_puts(tty, "\033[18t\033[14t");
+                       tty->flags |= TTY_WINSIZEQUERY;
+               }
        } else {
                sx = 80;
                sy = 24;
@@ -2247,7 +2254,7 @@ tty_reset(struct tty *tty)
        memcpy(&tty->last_cell, &grid_default_cell, sizeof tty->last_cell);
 }
 
-static void
+void
 tty_invalidate(struct tty *tty)
 {
        memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell);