diff options
Diffstat (limited to 'resize.c')
-rw-r--r-- | resize.c | 306 |
1 files changed, 193 insertions, 113 deletions
@@ -22,144 +22,224 @@ #include "tmux.h" -/* - * Recalculate window and session sizes. - * - * Every session has the size of the smallest client it is attached to and - * every window the size of the smallest session it is attached to. - * - * So, when a client is resized or a session attached to or detached from a - * client, the window sizes must be recalculated. For each session, find the - * smallest client it is attached to, and resize it to that size. Then for - * every window, find the smallest session it is attached to, resize it to that - * size and clear and redraw every client with it as the current window. - * - * This is quite inefficient - better/additional data structures are needed - * to make it better. - */ +void +resize_window(struct window *w, u_int sx, u_int sy) +{ + int zoomed; + + /* Check size limits. */ + if (sx < WINDOW_MINIMUM) + sx = WINDOW_MINIMUM; + if (sx > WINDOW_MAXIMUM) + sx = WINDOW_MAXIMUM; + if (sy < WINDOW_MINIMUM) + sy = WINDOW_MINIMUM; + if (sy > WINDOW_MAXIMUM) + sy = WINDOW_MAXIMUM; + + /* If the window is zoomed, unzoom. */ + zoomed = w->flags & WINDOW_ZOOMED; + if (zoomed) + window_unzoom(w); + + /* Resize the layout first. */ + layout_resize(w, sx, sy); + + /* Resize the window, it can be no smaller than the layout. */ + if (sx < w->layout_root->sx) + sx = w->layout_root->sx; + if (sy < w->layout_root->sy) + sy = w->layout_root->sy; + window_resize(w, sx, sy); + + /* Restore the window zoom state. */ + if (zoomed) + window_zoom(w->active); + + tty_update_window_offset(w); + server_redraw_window(w); + notify_window("window-layout-changed", w); +} void -recalculate_sizes(void) +default_window_size(struct session *s, struct window *w, u_int *sx, u_int *sy, + int type) { - struct session *s; - struct client *c; - struct window *w; - struct window_pane *wp; - u_int ssx, ssy, has, limit, lines; - int flag, is_zoomed, forced; + struct client *c; + u_int cx, cy; + const char *value; - RB_FOREACH(s, sessions, &sessions) { - lines = status_line_size(s); + if (type == -1) + type = options_get_number(global_w_options, "window-size"); + if (type == WINDOW_SIZE_MANUAL) + goto manual; - s->attached = 0; - ssx = ssy = UINT_MAX; + if (type == WINDOW_SIZE_LARGEST) { + *sx = *sy = 0; TAILQ_FOREACH(c, &clients, entry) { - if (c->flags & CLIENT_SUSPENDED) + if (c->session == NULL) continue; - if ((c->flags & (CLIENT_CONTROL|CLIENT_SIZECHANGED)) == - CLIENT_CONTROL) + if (w != NULL && !session_has(c->session, w)) continue; - if (c->session == s) { - if (c->tty.sx < ssx) - ssx = c->tty.sx; - c->flags &= ~CLIENT_STATUSOFF; - if (lines != 0 && lines + PANE_MINIMUM > c->tty.sy) - c->flags |= CLIENT_STATUSOFF; - if ((~c->flags & CLIENT_STATUSOFF) && - !(c->flags & CLIENT_CONTROL) && - c->tty.sy > lines && - c->tty.sy - lines < ssy) - ssy = c->tty.sy - lines; - else if (c->tty.sy < ssy) - ssy = c->tty.sy; - s->attached++; - } + if (w == NULL && c->session != s) + continue; + + cx = c->tty.sx; + cy = c->tty.sy - tty_status_lines(&c->tty); + + if (cx > *sx) + *sx = cx; + if (cy > *sy) + *sy = cy; } - if (ssx == UINT_MAX || ssy == UINT_MAX) - continue; + if (*sx == 0 || *sy == 0) + goto manual; + } else if (type == WINDOW_SIZE_SMALLEST) { + *sx = *sy = UINT_MAX; + TAILQ_FOREACH(c, &clients, entry) { + if (c->session == NULL) + continue; + if (w != NULL && !session_has(c->session, w)) + continue; + if (w == NULL && c->session != s) + continue; - if (lines != 0 && ssy == 0) - ssy = lines; + cx = c->tty.sx; + cy = c->tty.sy - tty_status_lines(&c->tty); - if (s->sx == ssx && s->sy == ssy) - continue; + if (cx < *sx) + *sx = cx; + if (cy < *sy) + *sy = cy; + } + if (*sx == UINT_MAX || *sy == UINT_MAX) + goto manual; + } + goto done; - log_debug("session $%u size %u,%u (was %u,%u)", s->id, ssx, ssy, - s->sx, s->sy); +manual: + value = options_get_string(s->options, "default-size"); + if (sscanf(value, "%ux%u", sx, sy) != 2) { + *sx = 80; + *sy = 24; + } - s->sx = ssx; - s->sy = ssy; +done: + if (*sx < WINDOW_MINIMUM) + *sx = WINDOW_MINIMUM; + if (*sx > WINDOW_MAXIMUM) + *sx = WINDOW_MAXIMUM; + if (*sy < WINDOW_MINIMUM) + *sy = WINDOW_MINIMUM; + if (*sy > WINDOW_MAXIMUM) + *sy = WINDOW_MAXIMUM; +} +void +recalculate_sizes(void) +{ + struct session *s; + struct client *c; + struct window *w; + u_int sx, sy, cx, cy; + int flags, type, current, has, changed; + + /* + * Clear attached count and update saved status line information for + * each session. + */ + RB_FOREACH(s, sessions, &sessions) { + s->attached = 0; status_update_saved(s); } + /* + * Increment attached count and check the status line size for each + * client. + */ + TAILQ_FOREACH(c, &clients, entry) { + if ((s = c->session) == NULL) + continue; + + flags = c->flags; + if (flags & CLIENT_SUSPENDED) + continue; + if ((flags & CLIENT_CONTROL) && (~flags & CLIENT_SIZECHANGED)) + continue; + + if (c->tty.sy <= tty_status_lines(&c->tty)) + c->flags |= CLIENT_STATUSOFF; + else + c->flags &= ~CLIENT_STATUSOFF; + + s->attached++; + } + + /* Walk each window and adjust the size. */ RB_FOREACH(w, windows, &windows) { if (w->active == NULL) continue; - flag = options_get_number(w->options, "aggressive-resize"); + log_debug("%s: @%u is %u,%u", __func__, w->id, w->sx, w->sy); - ssx = ssy = UINT_MAX; - RB_FOREACH(s, sessions, &sessions) { - if (s->attached == 0) - continue; - if (flag) - has = s->curw->window == w; - else - has = session_has(s, w); - if (has) { - if (s->sx < ssx) - ssx = s->sx; - if (s->sy < ssy) - ssy = s->sy; - } - } - if (ssx == UINT_MAX || ssy == UINT_MAX) + type = options_get_number(w->options, "window-size"); + if (type == WINDOW_SIZE_MANUAL) continue; - - forced = 0; - limit = options_get_number(w->options, "force-width"); - if (limit >= PANE_MINIMUM && ssx > limit) { - ssx = limit; - forced |= WINDOW_FORCEWIDTH; - } - limit = options_get_number(w->options, "force-height"); - if (limit >= PANE_MINIMUM && ssy > limit) { - ssy = limit; - forced |= WINDOW_FORCEHEIGHT; + current = !options_get_number(w->options, "aggressive-resize"); + + changed = 1; + if (type == WINDOW_SIZE_LARGEST) { + sx = sy = 0; + TAILQ_FOREACH(c, &clients, entry) { + if ((s = c->session) == NULL) + continue; + if (current) + has = (s->curw->window == w); + else + has = session_has(s, w); + if (!has) + continue; + + cx = c->tty.sx; + cy = c->tty.sy - tty_status_lines(&c->tty); + + if (cx > sx) + sx = cx; + if (cy > sy) + sy = cy; + } + if (sx == 0 || sy == 0) + changed = 0; + } else if (type == WINDOW_SIZE_SMALLEST) { + sx = sy = UINT_MAX; + TAILQ_FOREACH(c, &clients, entry) { + if ((s = c->session) == NULL) + continue; + if (current) + has = (s->curw->window == w); + else + has = session_has(s, w); + if (!has) + continue; + + cx = c->tty.sx; + cy = c->tty.sy - tty_status_lines(&c->tty); + + if (cx < sx) + sx = cx; + if (cy < sy) + sy = cy; + } + if (sx == UINT_MAX || sy == UINT_MAX) + changed = 0; } + if (w->sx == sx && w->sy == sy) + changed = 0; - if (w->sx == ssx && w->sy == ssy) + if (!changed) { + tty_update_window_offset(w); continue; - log_debug("window @%u size %u,%u (was %u,%u)", w->id, ssx, ssy, - w->sx, w->sy); - - w->flags &= ~(WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT); - w->flags |= forced; - - is_zoomed = w->flags & WINDOW_ZOOMED; - if (is_zoomed) - window_unzoom(w); - layout_resize(w, ssx, ssy); - window_resize(w, ssx, ssy); - if (is_zoomed && window_pane_visible(w->active)) - window_zoom(w->active); - - /* - * If the current pane is now not visible, move to the next - * that is. - */ - wp = w->active; - while (!window_pane_visible(w->active)) { - w->active = TAILQ_PREV(w->active, window_panes, entry); - if (w->active == NULL) - w->active = TAILQ_LAST(&w->panes, window_panes); - if (w->active == wp) - break; } - if (w->active == w->last) - w->last = NULL; - - server_redraw_window(w); - notify_window("window-layout-changed", w); + log_debug("%s: @%u changed to %u,%u", __func__, w->id, sx, sy); + resize_window(w, sx, sy); } } |