Annotation of src/usr.bin/tmux/resize.c, Revision 1.36
1.36 ! nicm 1: /* $OpenBSD: resize.c,v 1.35 2019/11/28 09:45:16 nicm Exp $ */
1.1 nicm 2:
3: /*
1.19 nicm 4: * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
1.1 nicm 5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15: * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/types.h>
20:
21: #include <string.h>
22:
23: #include "tmux.h"
24:
1.27 nicm 25: void
1.35 nicm 26: resize_window(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel)
1.27 nicm 27: {
28: int zoomed;
29:
30: /* Check size limits. */
31: if (sx < WINDOW_MINIMUM)
32: sx = WINDOW_MINIMUM;
33: if (sx > WINDOW_MAXIMUM)
34: sx = WINDOW_MAXIMUM;
35: if (sy < WINDOW_MINIMUM)
36: sy = WINDOW_MINIMUM;
37: if (sy > WINDOW_MAXIMUM)
38: sy = WINDOW_MAXIMUM;
39:
40: /* If the window is zoomed, unzoom. */
41: zoomed = w->flags & WINDOW_ZOOMED;
42: if (zoomed)
43: window_unzoom(w);
44:
45: /* Resize the layout first. */
46: layout_resize(w, sx, sy);
47:
48: /* Resize the window, it can be no smaller than the layout. */
49: if (sx < w->layout_root->sx)
50: sx = w->layout_root->sx;
51: if (sy < w->layout_root->sy)
52: sy = w->layout_root->sy;
1.35 nicm 53: window_resize(w, sx, sy, xpixel, ypixel);
1.31 nicm 54: log_debug("%s: @%u resized to %u,%u; layout %u,%u", __func__, w->id,
55: sx, sy, w->layout_root->sx, w->layout_root->sy);
1.27 nicm 56:
57: /* Restore the window zoom state. */
58: if (zoomed)
59: window_zoom(w->active);
60:
61: tty_update_window_offset(w);
62: server_redraw_window(w);
63: notify_window("window-layout-changed", w);
64: }
1.1 nicm 65:
1.29 nicm 66: static int
67: ignore_client_size(struct client *c)
68: {
69: if (c->session == NULL)
70: return (1);
71: if (c->flags & CLIENT_NOSIZEFLAGS)
72: return (1);
73: if ((c->flags & CLIENT_CONTROL) && (~c->flags & CLIENT_SIZECHANGED))
74: return (1);
75: return (0);
76: }
77:
1.1 nicm 78: void
1.34 nicm 79: default_window_size(struct client *c, struct session *s, struct window *w,
1.35 nicm 80: u_int *sx, u_int *sy, u_int *xpixel, u_int *ypixel, int type)
1.1 nicm 81: {
1.34 nicm 82: struct client *loop;
1.36 ! nicm 83: u_int cx, cy, n;
1.27 nicm 84: const char *value;
85:
86: if (type == -1)
87: type = options_get_number(global_w_options, "window-size");
1.34 nicm 88: switch (type) {
89: case WINDOW_SIZE_LARGEST:
1.27 nicm 90: *sx = *sy = 0;
1.35 nicm 91: *xpixel = *ypixel = 0;
1.34 nicm 92: TAILQ_FOREACH(loop, &clients, entry) {
93: if (ignore_client_size(loop))
1.27 nicm 94: continue;
1.34 nicm 95: if (w != NULL && !session_has(loop->session, w))
1.27 nicm 96: continue;
1.34 nicm 97: if (w == NULL && loop->session != s)
1.27 nicm 98: continue;
99:
1.34 nicm 100: cx = loop->tty.sx;
101: cy = loop->tty.sy - status_line_size(loop);
1.9 nicm 102:
1.27 nicm 103: if (cx > *sx)
104: *sx = cx;
105: if (cy > *sy)
106: *sy = cy;
1.35 nicm 107:
108: if (loop->tty.xpixel > *xpixel &&
109: loop->tty.ypixel > *ypixel) {
110: *xpixel = loop->tty.xpixel;
111: *ypixel = loop->tty.ypixel;
112: }
1.27 nicm 113: }
114: if (*sx == 0 || *sy == 0)
115: goto manual;
1.34 nicm 116: break;
117: case WINDOW_SIZE_SMALLEST:
1.27 nicm 118: *sx = *sy = UINT_MAX;
1.35 nicm 119: *xpixel = *ypixel = 0;
1.34 nicm 120: TAILQ_FOREACH(loop, &clients, entry) {
121: if (ignore_client_size(loop))
1.1 nicm 122: continue;
1.34 nicm 123: if (w != NULL && !session_has(loop->session, w))
1.27 nicm 124: continue;
1.34 nicm 125: if (w == NULL && loop->session != s)
1.27 nicm 126: continue;
127:
1.34 nicm 128: cx = loop->tty.sx;
129: cy = loop->tty.sy - status_line_size(loop);
1.27 nicm 130:
131: if (cx < *sx)
132: *sx = cx;
133: if (cy < *sy)
134: *sy = cy;
1.35 nicm 135:
136: if (loop->tty.xpixel > *xpixel &&
137: loop->tty.ypixel > *ypixel) {
138: *xpixel = loop->tty.xpixel;
139: *ypixel = loop->tty.ypixel;
140: }
1.1 nicm 141: }
1.27 nicm 142: if (*sx == UINT_MAX || *sy == UINT_MAX)
143: goto manual;
1.34 nicm 144: break;
145: case WINDOW_SIZE_LATEST:
146: if (c != NULL && !ignore_client_size(c)) {
147: *sx = c->tty.sx;
148: *sy = c->tty.sy - status_line_size(c);
1.35 nicm 149: *xpixel = c->tty.xpixel;
150: *ypixel = c->tty.ypixel;
1.34 nicm 151: } else {
1.36 ! nicm 152: if (w == NULL)
! 153: goto manual;
! 154: n = 0;
! 155: TAILQ_FOREACH(loop, &clients, entry) {
! 156: if (!ignore_client_size(loop) &&
! 157: session_has(loop->session, w)) {
! 158: if (++n > 1)
! 159: break;
! 160: }
! 161: }
1.34 nicm 162: *sx = *sy = UINT_MAX;
1.35 nicm 163: *xpixel = *ypixel = 0;
1.34 nicm 164: TAILQ_FOREACH(loop, &clients, entry) {
165: if (ignore_client_size(loop))
166: continue;
1.36 ! nicm 167: if (n > 1 && loop != w->latest)
1.34 nicm 168: continue;
169: s = loop->session;
170:
171: cx = loop->tty.sx;
172: cy = loop->tty.sy - status_line_size(loop);
173:
174: if (cx < *sx)
175: *sx = cx;
176: if (cy < *sy)
177: *sy = cy;
1.35 nicm 178:
179: if (loop->tty.xpixel > *xpixel &&
180: loop->tty.ypixel > *ypixel) {
181: *xpixel = loop->tty.xpixel;
182: *ypixel = loop->tty.ypixel;
183: }
1.34 nicm 184: }
185: if (*sx == UINT_MAX || *sy == UINT_MAX)
186: goto manual;
187: }
188: break;
189: case WINDOW_SIZE_MANUAL:
190: goto manual;
1.27 nicm 191: }
192: goto done;
193:
194: manual:
195: value = options_get_string(s->options, "default-size");
196: if (sscanf(value, "%ux%u", sx, sy) != 2) {
197: *sx = 80;
198: *sy = 24;
199: }
200:
201: done:
202: if (*sx < WINDOW_MINIMUM)
203: *sx = WINDOW_MINIMUM;
204: if (*sx > WINDOW_MAXIMUM)
205: *sx = WINDOW_MAXIMUM;
206: if (*sy < WINDOW_MINIMUM)
207: *sy = WINDOW_MINIMUM;
208: if (*sy > WINDOW_MAXIMUM)
209: *sy = WINDOW_MAXIMUM;
210: }
1.1 nicm 211:
1.27 nicm 212: void
1.33 nicm 213: recalculate_size(struct window *w)
214: {
215: struct session *s;
216: struct client *c;
1.36 ! nicm 217: u_int sx, sy, cx, cy, xpixel = 0, ypixel = 0, n;
1.33 nicm 218: int type, current, has, changed;
219:
220: if (w->active == NULL)
221: return;
222: log_debug("%s: @%u is %u,%u", __func__, w->id, w->sx, w->sy);
223:
224: type = options_get_number(w->options, "window-size");
225: current = options_get_number(w->options, "aggressive-resize");
226:
227: changed = 1;
228: switch (type) {
229: case WINDOW_SIZE_LARGEST:
230: sx = sy = 0;
231: TAILQ_FOREACH(c, &clients, entry) {
232: if (ignore_client_size(c))
233: continue;
234: s = c->session;
235:
236: if (current)
237: has = (s->curw->window == w);
238: else
239: has = session_has(s, w);
240: if (!has)
241: continue;
242:
243: cx = c->tty.sx;
244: cy = c->tty.sy - status_line_size(c);
245:
246: if (cx > sx)
247: sx = cx;
248: if (cy > sy)
249: sy = cy;
1.35 nicm 250:
251: if (c->tty.xpixel > xpixel && c->tty.ypixel > ypixel) {
252: xpixel = c->tty.xpixel;
253: ypixel = c->tty.ypixel;
254: }
1.33 nicm 255: }
256: if (sx == 0 || sy == 0)
257: changed = 0;
258: break;
259: case WINDOW_SIZE_SMALLEST:
260: sx = sy = UINT_MAX;
261: TAILQ_FOREACH(c, &clients, entry) {
262: if (ignore_client_size(c))
263: continue;
264: s = c->session;
265:
266: if (current)
267: has = (s->curw->window == w);
268: else
269: has = session_has(s, w);
270: if (!has)
271: continue;
272:
273: cx = c->tty.sx;
274: cy = c->tty.sy - status_line_size(c);
275:
276: if (cx < sx)
277: sx = cx;
278: if (cy < sy)
279: sy = cy;
1.35 nicm 280:
281: if (c->tty.xpixel > xpixel && c->tty.ypixel > ypixel) {
282: xpixel = c->tty.xpixel;
283: ypixel = c->tty.ypixel;
284: }
1.33 nicm 285: }
286: if (sx == UINT_MAX || sy == UINT_MAX)
287: changed = 0;
288: break;
289: case WINDOW_SIZE_LATEST:
1.36 ! nicm 290: n = 0;
! 291: TAILQ_FOREACH(c, &clients, entry) {
! 292: if (!ignore_client_size(c) &&
! 293: session_has(c->session, w)) {
! 294: if (++n > 1)
! 295: break;
! 296: }
! 297: }
1.33 nicm 298: sx = sy = UINT_MAX;
299: TAILQ_FOREACH(c, &clients, entry) {
300: if (ignore_client_size(c))
301: continue;
1.36 ! nicm 302: if (n > 1 && c != w->latest)
1.33 nicm 303: continue;
304: s = c->session;
305:
306: if (current)
307: has = (s->curw->window == w);
308: else
309: has = session_has(s, w);
310: if (!has)
311: continue;
312:
313: cx = c->tty.sx;
314: cy = c->tty.sy - status_line_size(c);
315:
316: if (cx < sx)
317: sx = cx;
318: if (cy < sy)
319: sy = cy;
1.35 nicm 320:
321: if (c->tty.xpixel > xpixel && c->tty.ypixel > ypixel) {
322: xpixel = c->tty.xpixel;
323: ypixel = c->tty.ypixel;
324: }
1.33 nicm 325: }
326: if (sx == UINT_MAX || sy == UINT_MAX)
327: changed = 0;
328: break;
329: case WINDOW_SIZE_MANUAL:
330: changed = 0;
331: break;
332: }
333: if (changed && w->sx == sx && w->sy == sy)
334: changed = 0;
335:
336: if (!changed) {
337: tty_update_window_offset(w);
338: return;
339: }
1.35 nicm 340: log_debug("%s: @%u changed to %u,%u (%ux%u)", __func__, w->id, sx, sy,
341: xpixel, ypixel);
342: resize_window(w, sx, sy, xpixel, ypixel);
1.33 nicm 343: }
344:
345: void
1.27 nicm 346: recalculate_sizes(void)
347: {
348: struct session *s;
349: struct client *c;
350: struct window *w;
351:
352: /*
353: * Clear attached count and update saved status line information for
354: * each session.
355: */
356: RB_FOREACH(s, sessions, &sessions) {
357: s->attached = 0;
1.30 nicm 358: status_update_cache(s);
1.27 nicm 359: }
1.9 nicm 360:
1.27 nicm 361: /*
362: * Increment attached count and check the status line size for each
363: * client.
364: */
365: TAILQ_FOREACH(c, &clients, entry) {
1.29 nicm 366: if (ignore_client_size(c))
1.27 nicm 367: continue;
1.32 nicm 368: s = c->session;
369: if (c->tty.sy <= s->statuslines || (c->flags & CLIENT_CONTROL))
1.27 nicm 370: c->flags |= CLIENT_STATUSOFF;
371: else
372: c->flags &= ~CLIENT_STATUSOFF;
1.32 nicm 373: s->attached++;
1.1 nicm 374: }
375:
1.27 nicm 376: /* Walk each window and adjust the size. */
1.33 nicm 377: RB_FOREACH(w, windows, &windows)
378: recalculate_size(w);
1.1 nicm 379: }