summaryrefslogtreecommitdiffstats
path: root/resize.c
diff options
context:
space:
mode:
Diffstat (limited to 'resize.c')
-rw-r--r--resize.c310
1 files changed, 197 insertions, 113 deletions
diff --git a/resize.c b/resize.c
index 1c9694da..fef8feeb 100644
--- a/resize.c
+++ b/resize.c
@@ -22,144 +22,228 @@
#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 (c->flags & CLIENT_NOSIZEFLAGS)
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 && !session_has(c->session, w))
+ continue;
+ if (w == NULL && c->session != s)
+ continue;
+
+ cx = c->tty.sx;
+ cy = c->tty.sy - status_line_size(c);
+
+ 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 {
+ *sx = *sy = UINT_MAX;
+ TAILQ_FOREACH(c, &clients, entry) {
+ if (c->session == NULL)
+ continue;
+ if (c->flags & CLIENT_NOSIZEFLAGS)
+ 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 - status_line_size(c);
- 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 <= status_line_size(c))
+ 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 - status_line_size(c);
+
+ if (cx > sx)
+ sx = cx;
+ if (cy > sy)
+ sy = cy;
+ }
+ if (sx == 0 || sy == 0)
+ changed = 0;
+ } else {
+ 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 - status_line_size(c);
+
+ 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);
}
}