Because we defer actually resizing applications (calling TIOCSWINSZ)
authornicm <nicm@openbsd.org>
Wed, 31 May 2017 10:15:51 +0000 (10:15 +0000)
committernicm <nicm@openbsd.org>
Wed, 31 May 2017 10:15:51 +0000 (10:15 +0000)
until the end of the server loop, tmux may have gone through several
internal resizes in between. This can be a problem if the final size is
the same as the initial size (what the application things it currently
is), because the application may choose not to redraw, assuming the
screen state is unchanged, when in fact tmux has thrown away parts of
the screen, assuming the application will redraw them.

To avoid this, do an extra resize if the new size is the same size as
the initial size. This should force the application to redraw when tmux
needs it to, while retaining the benefits of deferring (so we now resize
at most two times instead of at most one - and only two very rarely).

Fixes a problem with break-pane and zoomed panes reported by Michal
Mazurek.

usr.bin/tmux/server-client.c
usr.bin/tmux/tmux.h
usr.bin/tmux/window.c

index e320895..94914ea 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: server-client.c,v 1.234 2017/05/29 20:41:29 nicm Exp $ */
+/* $OpenBSD: server-client.c,v 1.235 2017/05/31 10:15:51 nicm Exp $ */
 
 /*
  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1050,14 +1050,36 @@ server_client_resize_event(__unused int fd, __unused short events, void *data)
        if (!(wp->flags & PANE_RESIZE))
                return;
 
+       /*
+        * If we are resizing to the same size as when we entered the loop
+        * (that is, to the same size the application currently thinks it is),
+        * tmux may have gone through several resizes internally and thrown
+        * away parts of the screen. So we need the application to actually
+        * redraw even though its final size has not changed.
+        */
+       if (wp->sx == wp->osx &&
+           wp->sy == wp->osy &&
+           wp->sx > 1 &&
+           wp->sy > 1) {
+               memset(&ws, 0, sizeof ws);
+               ws.ws_col = wp->sx - 1;
+               ws.ws_row = wp->sy - 1;
+               if (ioctl(wp->fd, TIOCSWINSZ, &ws) == -1)
+                       fatal("ioctl failed");
+               log_debug("%s: %%%u forcing resize", __func__, wp->id);
+       }
+
        memset(&ws, 0, sizeof ws);
        ws.ws_col = wp->sx;
        ws.ws_row = wp->sy;
-
        if (ioctl(wp->fd, TIOCSWINSZ, &ws) == -1)
                fatal("ioctl failed");
+       log_debug("%s: %%%u resize to %u,%u", __func__, wp->id, wp->sx, wp->sy);
 
        wp->flags &= ~PANE_RESIZE;
+
+       wp->osx = wp->sx;
+       wp->osy = wp->sy;
 }
 
 /* Check if pane should be resized. */
@@ -1068,6 +1090,7 @@ server_client_check_resize(struct window_pane *wp)
 
        if (!(wp->flags & PANE_RESIZE))
                return;
+       log_debug("%s: %%%u resize to %u,%u", __func__, wp->id, wp->sx, wp->sy);
 
        if (!event_initialized(&wp->resize_timer))
                evtimer_set(&wp->resize_timer, server_client_resize_event, wp);
index eca50eb..c9bba5b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.776 2017/05/31 08:43:44 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.777 2017/05/31 10:15:51 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -745,6 +745,9 @@ struct window_pane {
        u_int            sx;
        u_int            sy;
 
+       u_int            osx;
+       u_int            osy;
+
        u_int            xoff;
        u_int            yoff;
 
index 49c8f26..66b1166 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: window.c,v 1.196 2017/05/30 21:44:59 nicm Exp $ */
+/* $OpenBSD: window.c,v 1.197 2017/05/31 10:15:51 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -800,8 +800,8 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
        wp->xoff = 0;
        wp->yoff = 0;
 
-       wp->sx = sx;
-       wp->sy = sy;
+       wp->sx = wp->osx = sx;
+       wp->sy = wp->osx = sy;
 
        wp->pipe_fd = -1;
        wp->pipe_off = 0;