diff options
Diffstat (limited to 'server-client.c')
-rw-r--r-- | server-client.c | 142 |
1 files changed, 84 insertions, 58 deletions
diff --git a/server-client.c b/server-client.c index f44631c9..2cfd8838 100644 --- a/server-client.c +++ b/server-client.c @@ -42,6 +42,7 @@ static void server_client_set_title(struct client *); static void server_client_reset_state(struct client *); static int server_client_assume_paste(struct session *); static void server_client_clear_overlay(struct client *); +static void server_client_resize_event(int, short, void *); static void server_client_dispatch(struct imsg *, void *); static void server_client_dispatch_command(struct client *, struct imsg *); @@ -540,7 +541,8 @@ have_event: where = STATUS_RIGHT; break; case STYLE_RANGE_WINDOW: - wl = winlink_find_by_index(&s->windows, sr->argument); + wl = winlink_find_by_index(&s->windows, + sr->argument); if (wl == NULL) return (KEYC_UNKNOWN); m->w = wl->window->id; @@ -993,6 +995,24 @@ server_client_assume_paste(struct session *s) return (0); } +/* Has the latest client changed? */ +static void +server_client_update_latest(struct client *c) +{ + struct window *w; + + if (c->session == NULL) + return; + w = c->session->curw->window; + + if (w->latest == c) + return; + w->latest = c; + + if (options_get_number(w->options, "window-size") == WINDOW_SIZE_LATEST) + recalculate_size(w); +} + /* * Handle data key input from client. This owns and can modify the key event it * is given and is responsible for freeing it. @@ -1189,6 +1209,8 @@ forward_key: window_pane_key(wp, c, s, wl, key, m); out: + if (s != NULL) + server_client_update_latest(c); free(event); return (CMD_RETURN_NORMAL); } @@ -1245,7 +1267,7 @@ server_client_loop(void) struct window_pane *wp; struct winlink *wl; struct session *s; - int focus; + int focus, attached, resize; TAILQ_FOREACH(c, &clients, entry) { server_client_check_exit(c); @@ -1258,19 +1280,33 @@ server_client_loop(void) /* * Any windows will have been redrawn as part of clients, so clear * their flags now. Also check pane focus and resize. + * + * As an optimization, panes in windows that are in an attached session + * but not the current window are not resized (this reduces the amount + * of work needed when, for example, resizing an X terminal a + * lot). Windows in no attached session are resized immediately since + * that is likely to have come from a command like split-window and be + * what the user wanted. */ focus = options_get_number(global_options, "focus-events"); RB_FOREACH(w, windows, &windows) { + attached = resize = 0; TAILQ_FOREACH(wl, &w->winlinks, wentry) { s = wl->session; - if (s->attached != 0 && s->curw == wl) + if (s->attached != 0) + attached = 1; + if (s->attached != 0 && s->curw == wl) { + resize = 1; break; + } } + if (!attached) + resize = 1; TAILQ_FOREACH(wp, &w->panes, entry) { if (wp->fd != -1) { if (focus) server_client_check_focus(wp); - if (wl != NULL) + if (resize) server_client_check_resize(wp); } wp->flags &= ~PANE_REDRAW; @@ -1284,7 +1320,6 @@ static int server_client_resize_force(struct window_pane *wp) { struct timeval tv = { .tv_usec = 100000 }; - struct winsize ws; /* * If we are resizing to the same size as when we entered the loop @@ -1305,86 +1340,76 @@ server_client_resize_force(struct window_pane *wp) wp->sy <= 1) return (0); - memset(&ws, 0, sizeof ws); - ws.ws_col = wp->sx; - ws.ws_row = wp->sy - 1; - if (wp->fd != -1 && ioctl(wp->fd, TIOCSWINSZ, &ws) == -1) -#ifdef __sun - if (errno != EINVAL && errno != ENXIO) -#endif - fatal("ioctl failed"); log_debug("%s: %%%u forcing resize", __func__, wp->id); + window_pane_send_resize(wp, -1); evtimer_add(&wp->resize_timer, &tv); wp->flags |= PANE_RESIZEFORCE; return (1); } +/* Resize a pane. */ +static void +server_client_resize_pane(struct window_pane *wp) +{ + log_debug("%s: %%%u resize to %u,%u", __func__, wp->id, wp->sx, wp->sy); + window_pane_send_resize(wp, 0); + + wp->flags &= ~PANE_RESIZE; + + wp->osx = wp->sx; + wp->osy = wp->sy; +} + +/* Start the resize timer. */ +static void +server_client_start_resize_timer(struct window_pane *wp) +{ + struct timeval tv = { .tv_usec = 250000 }; + + if (!evtimer_pending(&wp->resize_timer, NULL)) + evtimer_add(&wp->resize_timer, &tv); +} + /* Resize timer event. */ static void server_client_resize_event(__unused int fd, __unused short events, void *data) { struct window_pane *wp = data; - struct winsize ws; evtimer_del(&wp->resize_timer); - if (!(wp->flags & PANE_RESIZE)) + if (~wp->flags & PANE_RESIZE) return; - if (server_client_resize_force(wp)) - return; - - memset(&ws, 0, sizeof ws); - ws.ws_col = wp->sx; - ws.ws_row = wp->sy; - if (wp->fd != -1 && ioctl(wp->fd, TIOCSWINSZ, &ws) == -1) -#ifdef __sun - /* - * Some versions of Solaris apparently can return an error when - * resizing; don't know why this happens, can't reproduce on - * other platforms and ignoring it doesn't seem to cause any - * issues. - */ - if (errno != EINVAL && errno != ENXIO) -#endif - 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; + log_debug("%s: %%%u timer fired (was%s resized)", __func__, wp->id, + (wp->flags & PANE_RESIZED) ? "" : " not"); + + if (wp->saved_grid == NULL && (wp->flags & PANE_RESIZED)) { + log_debug("%s: %%%u deferring timer", __func__, wp->id); + server_client_start_resize_timer(wp); + } else if (!server_client_resize_force(wp)) { + log_debug("%s: %%%u resizing pane", __func__, wp->id); + server_client_resize_pane(wp); + } + wp->flags &= ~PANE_RESIZED; } /* Check if pane should be resized. */ static void server_client_check_resize(struct window_pane *wp) { - struct timeval tv = { .tv_usec = 250000 }; - - if (!(wp->flags & PANE_RESIZE)) + 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); - /* - * The first resize should happen immediately, so if the timer is not - * running, do it now. - */ - if (!evtimer_pending(&wp->resize_timer, NULL)) - server_client_resize_event(-1, 0, wp); - - /* - * If the pane is in the alternate screen, let the timer expire and - * resize to give the application a chance to redraw. If not, keep - * pushing the timer back. - */ - if (wp->saved_grid != NULL && evtimer_pending(&wp->resize_timer, NULL)) - return; - evtimer_del(&wp->resize_timer); - evtimer_add(&wp->resize_timer, &tv); + if (!evtimer_pending(&wp->resize_timer, NULL)) { + log_debug("%s: %%%u starting timer", __func__, wp->id); + server_client_resize_pane(wp); + server_client_start_resize_timer(wp); + } else + log_debug("%s: %%%u timer running", __func__, wp->id); } /* Check whether pane should be focused. */ @@ -1734,6 +1759,7 @@ server_client_dispatch(struct imsg *imsg, void *arg) if (c->flags & CLIENT_CONTROL) break; + server_client_update_latest(c); server_client_clear_overlay(c); tty_resize(&c->tty); recalculate_sizes(); |