mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 01:34:18 +00:00 
			
		
		
		
	Change resize timers and flags into one timer and a queue to fix problems with
vim when resized multiple times. GitHub issue 2677.
This commit is contained in:
		
							
								
								
									
										113
									
								
								server-client.c
									
									
									
									
									
								
							
							
						
						
									
										113
									
								
								server-client.c
									
									
									
									
									
								
							@@ -1447,84 +1447,79 @@ server_client_resize_timer(__unused int fd, __unused short events, void *data)
 | 
			
		||||
	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)
 | 
			
		||||
{
 | 
			
		||||
	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 (TAILQ_EMPTY(&wp->resize_queue))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
 | 
			
		||||
	if (~wp->flags & PANE_RESIZE)
 | 
			
		||||
	if (evtimer_pending(&wp->resize_timer, NULL))
 | 
			
		||||
		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);
 | 
			
		||||
		return;
 | 
			
		||||
	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.
 | 
			
		||||
	 * 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.
 | 
			
		||||
	 */
 | 
			
		||||
		log_debug("%s: resizing %%%u now", __func__, wp->id);
 | 
			
		||||
		window_pane_send_resize(wp, 0);
 | 
			
		||||
		wp->flags &= ~PANE_RESIZE;
 | 
			
		||||
	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)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										21
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								tmux.h
									
									
									
									
									
								
							@@ -927,6 +927,18 @@ struct window_pane_offset {
 | 
			
		||||
	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;
 | 
			
		||||
@@ -951,8 +963,8 @@ struct window_pane {
 | 
			
		||||
#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
 | 
			
		||||
@@ -961,7 +973,6 @@ struct window_pane {
 | 
			
		||||
#define PANE_STATUSDRAWN 0x400
 | 
			
		||||
#define PANE_EMPTY 0x800
 | 
			
		||||
#define PANE_STYLECHANGED 0x1000
 | 
			
		||||
#define PANE_RESIZENOW 0x2000
 | 
			
		||||
 | 
			
		||||
	int		 argc;
 | 
			
		||||
	char	       **argv;
 | 
			
		||||
@@ -978,8 +989,8 @@ struct window_pane {
 | 
			
		||||
	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;
 | 
			
		||||
 | 
			
		||||
@@ -2756,7 +2767,7 @@ void		 window_redraw_active_switch(struct window *,
 | 
			
		||||
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);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										51
									
								
								window.c
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								window.c
									
									
									
									
									
								
							@@ -425,25 +425,18 @@ window_resize(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
@@ -867,29 +860,19 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
 | 
			
		||||
	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;
 | 
			
		||||
@@ -905,6 +888,9 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
@@ -929,8 +915,10 @@ window_pane_destroy(struct window_pane *wp)
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
 | 
			
		||||
@@ -999,9 +987,18 @@ void
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
@@ -1011,14 +1008,6 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int 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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user