-/* $OpenBSD: server-client.c,v 1.373 2021/06/10 07:21:46 nicm Exp $ */
+/* $OpenBSD: server-client.c,v 1.374 2021/06/10 07:33:41 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
evtimer_del(&wp->resize_timer);
}
-/* Start the resize timer. */
-static void
-server_client_start_resize_timer(struct window_pane *wp)
-{
- struct timeval tv = { .tv_usec = 250000 };
-
- log_debug("%s: %%%u resize timer started", __func__, wp->id);
- evtimer_add(&wp->resize_timer, &tv);
-}
-
-/* Force timer event. */
-static void
-server_client_force_timer(__unused int fd, __unused short events, void *data)
-{
- struct window_pane *wp = data;
-
- log_debug("%s: %%%u force timer expired", __func__, wp->id);
- evtimer_del(&wp->force_timer);
- wp->flags |= PANE_RESIZENOW;
-}
-
-/* Start the force timer. */
-static void
-server_client_start_force_timer(struct window_pane *wp)
-{
- struct timeval tv = { .tv_usec = 10000 };
-
- log_debug("%s: %%%u force timer started", __func__, wp->id);
- evtimer_add(&wp->force_timer, &tv);
-}
-
/* Check if pane should be resized. */
static void
server_client_check_pane_resize(struct window_pane *wp)
{
- if (!event_initialized(&wp->resize_timer))
- evtimer_set(&wp->resize_timer, server_client_resize_timer, wp);
- if (!event_initialized(&wp->force_timer))
- evtimer_set(&wp->force_timer, server_client_force_timer, wp);
+ struct window_pane_resize *r;
+ struct window_pane_resize *r1;
+ struct window_pane_resize *first;
+ struct window_pane_resize *last;
+ struct timeval tv = { .tv_usec = 250000 };
- if (~wp->flags & PANE_RESIZE)
+ if (TAILQ_EMPTY(&wp->resize_queue))
return;
- log_debug("%s: %%%u needs to be resized", __func__, wp->id);
- if (evtimer_pending(&wp->resize_timer, NULL)) {
- log_debug("%s: %%%u resize timer is running", __func__, wp->id);
+ if (!event_initialized(&wp->resize_timer))
+ evtimer_set(&wp->resize_timer, server_client_resize_timer, wp);
+ if (evtimer_pending(&wp->resize_timer, NULL))
return;
+
+ log_debug("%s: %%%u needs to be resized", __func__, wp->id);
+ TAILQ_FOREACH(r, &wp->resize_queue, entry) {
+ log_debug("queued resize: %ux%u -> %ux%u", r->osx, r->osy,
+ r->sx, r->sy);
}
- server_client_start_resize_timer(wp);
- if (~wp->flags & PANE_RESIZEFORCE) {
- /*
- * The timer is not running and we don't need to force a
- * resize, so just resize immediately.
- */
- log_debug("%s: resizing %%%u now", __func__, wp->id);
- window_pane_send_resize(wp, 0);
- wp->flags &= ~PANE_RESIZE;
+ /*
+ * There are three cases that matter:
+ *
+ * - Only one resize. It can just be applied.
+ *
+ * - Multiple resizes and the ending size is different from the
+ * starting size. We can discard all resizes except the most recent.
+ *
+ * - Multiple resizes and the ending size is the same as the starting
+ * size. We must resize at least twice to force the application to
+ * redraw. So apply the first and leave the last on the queue for
+ * next time.
+ */
+ first = TAILQ_FIRST(&wp->resize_queue);
+ last = TAILQ_LAST(&wp->resize_queue, window_pane_resizes);
+ if (first == last) {
+ /* Only one resize. */
+ window_pane_send_resize(wp, first->sx, first->sy);
+ TAILQ_REMOVE(&wp->resize_queue, first, entry);
+ free(first);
+ } else if (last->sx != first->osx || last->sy != first->osy) {
+ /* Multiple resizes ending up with a different size. */
+ window_pane_send_resize(wp, last->sx, last->sy);
+ TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) {
+ TAILQ_REMOVE(&wp->resize_queue, r, entry);
+ free(r);
+ }
} else {
/*
- * The timer is not running, but we need to force a resize. If
- * the force timer has expired, resize to the real size now.
- * Otherwise resize to the force size and start the timer.
+ * Multiple resizes ending up with the same size. There will
+ * not be more than one to the same size in succession so we
+ * can just use the last-but-one on the list and leave the last
+ * for later. We reduce the time until the next check to avoid
+ * a long delay between the resizes.
*/
- if (wp->flags & PANE_RESIZENOW) {
- log_debug("%s: resizing %%%u after forced resize",
- __func__, wp->id);
- window_pane_send_resize(wp, 0);
- wp->flags &= ~(PANE_RESIZE|PANE_RESIZEFORCE|PANE_RESIZENOW);
- } else if (!evtimer_pending(&wp->force_timer, NULL)) {
- log_debug("%s: forcing resize of %%%u", __func__,
- wp->id);
- window_pane_send_resize(wp, 1);
- server_client_start_force_timer(wp);
+ r = TAILQ_PREV(last, window_pane_resizes, entry);
+ window_pane_send_resize(wp, r->sx, r->sy);
+ TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) {
+ if (r == last)
+ break;
+ TAILQ_REMOVE(&wp->resize_queue, r, entry);
+ free(r);
}
+ tv.tv_usec = 10000;
}
+ evtimer_add(&wp->resize_timer, &tv);
}
+
/* Check pane buffer size. */
static void
server_client_check_pane_buffer(struct window_pane *wp)
-/* $OpenBSD: tmux.h,v 1.1104 2021/06/10 07:28:45 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.1105 2021/06/10 07:33:41 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
struct screen *screen;
u_int prefix;
- TAILQ_ENTRY (window_mode_entry) entry;
+ TAILQ_ENTRY(window_mode_entry) entry;
};
/* Offsets into pane buffer. */
size_t used;
};
+/* Queued pane resize. */
+struct window_pane_resize {
+ u_int sx;
+ u_int sy;
+
+ u_int osx;
+ u_int osy;
+
+ TAILQ_ENTRY(window_pane_resize) entry;
+};
+TAILQ_HEAD(window_pane_resizes, window_pane_resize);
+
/* Child window structure. */
struct window_pane {
u_int id;
#define PANE_REDRAW 0x1
#define PANE_DROP 0x2
#define PANE_FOCUSED 0x4
-#define PANE_RESIZE 0x8
-#define PANE_RESIZEFORCE 0x10
+/* 0x8 unused */
+/* 0x10 unused */
#define PANE_FOCUSPUSH 0x20
#define PANE_INPUTOFF 0x40
#define PANE_CHANGED 0x80
#define PANE_STATUSDRAWN 0x400
#define PANE_EMPTY 0x800
#define PANE_STYLECHANGED 0x1000
-#define PANE_RESIZENOW 0x2000
int argc;
char **argv;
struct window_pane_offset offset;
size_t base_offset;
+ struct window_pane_resizes resize_queue;
struct event resize_timer;
- struct event force_timer;
struct input_ctx *ictx;
struct screen status_screen;
size_t status_size;
- TAILQ_HEAD (, window_mode_entry) modes;
+ TAILQ_HEAD(, window_mode_entry) modes;
char *searchstr;
int searchregex;
struct window_pane *window_add_pane(struct window *, struct window_pane *,
u_int, int);
void window_resize(struct window *, u_int, u_int, int, int);
-void window_pane_send_resize(struct window_pane *, int);
+void window_pane_send_resize(struct window_pane *, u_int, u_int);
int window_zoom(struct window_pane *);
int window_unzoom(struct window *);
int window_push_zoom(struct window *, int, int);
-/* $OpenBSD: window.c,v 1.271 2021/06/10 07:24:45 nicm Exp $ */
+/* $OpenBSD: window.c,v 1.272 2021/06/10 07:33:41 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
}
void
-window_pane_send_resize(struct window_pane *wp, int force)
+window_pane_send_resize(struct window_pane *wp, u_int sx, u_int sy)
{
struct window *w = wp->window;
struct winsize ws;
- u_int sy;
if (wp->fd == -1)
return;
- if (!force)
- sy = wp->sy;
- else if (wp->sy <= 1)
- sy = wp->sy + 1;
- else
- sy = wp->sy - 1;
- log_debug("%s: %%%u resize to %u,%u", __func__, wp->id, wp->sx, sy);
+ log_debug("%s: %%%u resize to %u,%u", __func__, wp->id, sx, sy);
memset(&ws, 0, sizeof ws);
- ws.ws_col = wp->sx;
+ ws.ws_col = sx;
ws.ws_row = sy;
ws.ws_xpixel = w->xpixel * ws.ws_col;
ws.ws_ypixel = w->ypixel * ws.ws_row;
wp->id = next_window_pane_id++;
RB_INSERT(window_pane_tree, &all_window_panes, wp);
- wp->argc = 0;
- wp->argv = NULL;
- wp->shell = NULL;
- wp->cwd = NULL;
-
wp->fd = -1;
- wp->event = NULL;
wp->fg = 8;
wp->bg = 8;
TAILQ_INIT(&wp->modes);
- wp->layout_cell = NULL;
-
- wp->xoff = 0;
- wp->yoff = 0;
+ TAILQ_INIT (&wp->resize_queue);
wp->sx = sx;
wp->sy = sy;
wp->pipe_fd = -1;
- wp->pipe_event = NULL;
screen_init(&wp->base, sx, sy, hlimit);
wp->screen = &wp->base;
static void
window_pane_destroy(struct window_pane *wp)
{
+ struct window_pane_resize *r;
+ struct window_pane_resize *r1;
+
window_pane_reset_mode_all(wp);
free(wp->searchstr);
if (event_initialized(&wp->resize_timer))
event_del(&wp->resize_timer);
- if (event_initialized(&wp->force_timer))
- event_del(&wp->force_timer);
+ TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) {
+ TAILQ_REMOVE(&wp->resize_queue, r, entry);
+ free(r);
+ }
RB_REMOVE(window_pane_tree, &all_window_panes, wp);
window_pane_resize(struct window_pane *wp, u_int sx, u_int sy)
{
struct window_mode_entry *wme;
+ struct window_pane_resize *r;
if (sx == wp->sx && sy == wp->sy)
return;
+
+ r = xmalloc (sizeof *r);
+ r->sx = sx;
+ r->sy = sy;
+ r->osx = wp->sx;
+ r->osy = wp->sy;
+ TAILQ_INSERT_TAIL (&wp->resize_queue, r, entry);
+
wp->sx = sx;
wp->sy = sy;
wme = TAILQ_FIRST(&wp->modes);
if (wme != NULL && wme->mode->resize != NULL)
wme->mode->resize(wme, sx, sy);
-
- /*
- * If the pane has already been resized, set the force flag and make
- * the application resize twice to force it to redraw.
- */
- if (wp->flags & PANE_RESIZE)
- wp->flags |= PANE_RESIZEFORCE;
- wp->flags |= PANE_RESIZE;
}
void