Annotation of src/usr.bin/tmux/resize.c, Revision 1.39
1.39 ! nicm 1: /* $OpenBSD: resize.c,v 1.38 2020/01/28 13:23:24 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: {
1.38 nicm 69: struct client *loop;
70:
1.29 nicm 71: if (c->session == NULL)
72: return (1);
73: if (c->flags & CLIENT_NOSIZEFLAGS)
74: return (1);
1.39 ! nicm 75: if (c->flags & CLIENT_IGNORESIZE) {
1.38 nicm 76: /*
1.39 ! nicm 77: * Ignore flagged clients if there are any attached clients
! 78: * that aren't flagged.
1.38 nicm 79: */
80: TAILQ_FOREACH (loop, &clients, entry) {
81: if (loop->session == NULL)
82: continue;
83: if (loop->flags & CLIENT_NOSIZEFLAGS)
84: continue;
1.39 ! nicm 85: if (~loop->flags & CLIENT_IGNORESIZE)
1.38 nicm 86: return (1);
87: }
88: }
1.29 nicm 89: if ((c->flags & CLIENT_CONTROL) && (~c->flags & CLIENT_SIZECHANGED))
90: return (1);
91: return (0);
92: }
93:
1.1 nicm 94: void
1.34 nicm 95: default_window_size(struct client *c, struct session *s, struct window *w,
1.35 nicm 96: u_int *sx, u_int *sy, u_int *xpixel, u_int *ypixel, int type)
1.1 nicm 97: {
1.34 nicm 98: struct client *loop;
1.36 nicm 99: u_int cx, cy, n;
1.27 nicm 100: const char *value;
101:
102: if (type == -1)
103: type = options_get_number(global_w_options, "window-size");
1.34 nicm 104: switch (type) {
105: case WINDOW_SIZE_LARGEST:
1.27 nicm 106: *sx = *sy = 0;
1.35 nicm 107: *xpixel = *ypixel = 0;
1.34 nicm 108: TAILQ_FOREACH(loop, &clients, entry) {
109: if (ignore_client_size(loop))
1.27 nicm 110: continue;
1.34 nicm 111: if (w != NULL && !session_has(loop->session, w))
1.27 nicm 112: continue;
1.34 nicm 113: if (w == NULL && loop->session != s)
1.27 nicm 114: continue;
115:
1.34 nicm 116: cx = loop->tty.sx;
117: cy = loop->tty.sy - status_line_size(loop);
1.9 nicm 118:
1.27 nicm 119: if (cx > *sx)
120: *sx = cx;
121: if (cy > *sy)
122: *sy = cy;
1.35 nicm 123:
124: if (loop->tty.xpixel > *xpixel &&
125: loop->tty.ypixel > *ypixel) {
126: *xpixel = loop->tty.xpixel;
127: *ypixel = loop->tty.ypixel;
128: }
1.27 nicm 129: }
130: if (*sx == 0 || *sy == 0)
131: goto manual;
1.34 nicm 132: break;
133: case WINDOW_SIZE_SMALLEST:
1.27 nicm 134: *sx = *sy = UINT_MAX;
1.35 nicm 135: *xpixel = *ypixel = 0;
1.34 nicm 136: TAILQ_FOREACH(loop, &clients, entry) {
137: if (ignore_client_size(loop))
1.1 nicm 138: continue;
1.34 nicm 139: if (w != NULL && !session_has(loop->session, w))
1.27 nicm 140: continue;
1.34 nicm 141: if (w == NULL && loop->session != s)
1.27 nicm 142: continue;
143:
1.34 nicm 144: cx = loop->tty.sx;
145: cy = loop->tty.sy - status_line_size(loop);
1.27 nicm 146:
147: if (cx < *sx)
148: *sx = cx;
149: if (cy < *sy)
150: *sy = cy;
1.35 nicm 151:
152: if (loop->tty.xpixel > *xpixel &&
153: loop->tty.ypixel > *ypixel) {
154: *xpixel = loop->tty.xpixel;
155: *ypixel = loop->tty.ypixel;
156: }
1.1 nicm 157: }
1.27 nicm 158: if (*sx == UINT_MAX || *sy == UINT_MAX)
159: goto manual;
1.34 nicm 160: break;
161: case WINDOW_SIZE_LATEST:
162: if (c != NULL && !ignore_client_size(c)) {
163: *sx = c->tty.sx;
164: *sy = c->tty.sy - status_line_size(c);
1.35 nicm 165: *xpixel = c->tty.xpixel;
166: *ypixel = c->tty.ypixel;
1.34 nicm 167: } else {
1.36 nicm 168: if (w == NULL)
169: goto manual;
170: n = 0;
171: TAILQ_FOREACH(loop, &clients, entry) {
172: if (!ignore_client_size(loop) &&
173: session_has(loop->session, w)) {
174: if (++n > 1)
175: break;
176: }
177: }
1.34 nicm 178: *sx = *sy = UINT_MAX;
1.35 nicm 179: *xpixel = *ypixel = 0;
1.34 nicm 180: TAILQ_FOREACH(loop, &clients, entry) {
181: if (ignore_client_size(loop))
182: continue;
1.36 nicm 183: if (n > 1 && loop != w->latest)
1.34 nicm 184: continue;
185: s = loop->session;
186:
187: cx = loop->tty.sx;
188: cy = loop->tty.sy - status_line_size(loop);
189:
190: if (cx < *sx)
191: *sx = cx;
192: if (cy < *sy)
193: *sy = cy;
1.35 nicm 194:
195: if (loop->tty.xpixel > *xpixel &&
196: loop->tty.ypixel > *ypixel) {
197: *xpixel = loop->tty.xpixel;
198: *ypixel = loop->tty.ypixel;
199: }
1.34 nicm 200: }
201: if (*sx == UINT_MAX || *sy == UINT_MAX)
202: goto manual;
203: }
204: break;
205: case WINDOW_SIZE_MANUAL:
206: goto manual;
1.27 nicm 207: }
208: goto done;
209:
210: manual:
211: value = options_get_string(s->options, "default-size");
212: if (sscanf(value, "%ux%u", sx, sy) != 2) {
213: *sx = 80;
214: *sy = 24;
215: }
216:
217: done:
218: if (*sx < WINDOW_MINIMUM)
219: *sx = WINDOW_MINIMUM;
220: if (*sx > WINDOW_MAXIMUM)
221: *sx = WINDOW_MAXIMUM;
222: if (*sy < WINDOW_MINIMUM)
223: *sy = WINDOW_MINIMUM;
224: if (*sy > WINDOW_MAXIMUM)
225: *sy = WINDOW_MAXIMUM;
226: }
1.1 nicm 227:
1.27 nicm 228: void
1.33 nicm 229: recalculate_size(struct window *w)
230: {
231: struct session *s;
232: struct client *c;
1.36 nicm 233: u_int sx, sy, cx, cy, xpixel = 0, ypixel = 0, n;
1.33 nicm 234: int type, current, has, changed;
235:
236: if (w->active == NULL)
237: return;
238: log_debug("%s: @%u is %u,%u", __func__, w->id, w->sx, w->sy);
239:
240: type = options_get_number(w->options, "window-size");
241: current = options_get_number(w->options, "aggressive-resize");
242:
243: changed = 1;
244: switch (type) {
245: case WINDOW_SIZE_LARGEST:
246: sx = sy = 0;
247: TAILQ_FOREACH(c, &clients, entry) {
248: if (ignore_client_size(c))
249: continue;
250: s = c->session;
251:
252: if (current)
253: has = (s->curw->window == w);
254: else
255: has = session_has(s, w);
256: if (!has)
257: continue;
258:
259: cx = c->tty.sx;
260: cy = c->tty.sy - status_line_size(c);
261:
262: if (cx > sx)
263: sx = cx;
264: if (cy > sy)
265: sy = cy;
1.35 nicm 266:
267: if (c->tty.xpixel > xpixel && c->tty.ypixel > ypixel) {
268: xpixel = c->tty.xpixel;
269: ypixel = c->tty.ypixel;
270: }
1.33 nicm 271: }
272: if (sx == 0 || sy == 0)
273: changed = 0;
274: break;
275: case WINDOW_SIZE_SMALLEST:
276: sx = sy = UINT_MAX;
277: TAILQ_FOREACH(c, &clients, entry) {
278: if (ignore_client_size(c))
279: continue;
280: s = c->session;
281:
282: if (current)
283: has = (s->curw->window == w);
284: else
285: has = session_has(s, w);
286: if (!has)
287: continue;
288:
289: cx = c->tty.sx;
290: cy = c->tty.sy - status_line_size(c);
291:
292: if (cx < sx)
293: sx = cx;
294: if (cy < sy)
295: sy = cy;
1.35 nicm 296:
297: if (c->tty.xpixel > xpixel && c->tty.ypixel > ypixel) {
298: xpixel = c->tty.xpixel;
299: ypixel = c->tty.ypixel;
300: }
1.33 nicm 301: }
302: if (sx == UINT_MAX || sy == UINT_MAX)
303: changed = 0;
304: break;
305: case WINDOW_SIZE_LATEST:
1.36 nicm 306: n = 0;
307: TAILQ_FOREACH(c, &clients, entry) {
308: if (!ignore_client_size(c) &&
309: session_has(c->session, w)) {
310: if (++n > 1)
311: break;
312: }
313: }
1.33 nicm 314: sx = sy = UINT_MAX;
315: TAILQ_FOREACH(c, &clients, entry) {
316: if (ignore_client_size(c))
317: continue;
1.36 nicm 318: if (n > 1 && c != w->latest)
1.33 nicm 319: continue;
320: s = c->session;
321:
322: if (current)
323: has = (s->curw->window == w);
324: else
325: has = session_has(s, w);
326: if (!has)
327: continue;
328:
329: cx = c->tty.sx;
330: cy = c->tty.sy - status_line_size(c);
331:
332: if (cx < sx)
333: sx = cx;
334: if (cy < sy)
335: sy = cy;
1.35 nicm 336:
337: if (c->tty.xpixel > xpixel && c->tty.ypixel > ypixel) {
338: xpixel = c->tty.xpixel;
339: ypixel = c->tty.ypixel;
340: }
1.33 nicm 341: }
342: if (sx == UINT_MAX || sy == UINT_MAX)
343: changed = 0;
344: break;
345: case WINDOW_SIZE_MANUAL:
346: changed = 0;
347: break;
348: }
349: if (changed && w->sx == sx && w->sy == sy)
350: changed = 0;
351:
352: if (!changed) {
353: tty_update_window_offset(w);
354: return;
355: }
1.35 nicm 356: log_debug("%s: @%u changed to %u,%u (%ux%u)", __func__, w->id, sx, sy,
357: xpixel, ypixel);
358: resize_window(w, sx, sy, xpixel, ypixel);
1.33 nicm 359: }
360:
361: void
1.27 nicm 362: recalculate_sizes(void)
363: {
364: struct session *s;
365: struct client *c;
366: struct window *w;
367:
368: /*
369: * Clear attached count and update saved status line information for
370: * each session.
371: */
372: RB_FOREACH(s, sessions, &sessions) {
373: s->attached = 0;
1.30 nicm 374: status_update_cache(s);
1.27 nicm 375: }
1.9 nicm 376:
1.27 nicm 377: /*
378: * Increment attached count and check the status line size for each
379: * client.
380: */
381: TAILQ_FOREACH(c, &clients, entry) {
1.37 nicm 382: s = c->session;
383: if (s != NULL && !(c->flags & CLIENT_UNATTACHEDFLAGS))
384: s->attached++;
1.29 nicm 385: if (ignore_client_size(c))
1.27 nicm 386: continue;
1.32 nicm 387: if (c->tty.sy <= s->statuslines || (c->flags & CLIENT_CONTROL))
1.27 nicm 388: c->flags |= CLIENT_STATUSOFF;
389: else
390: c->flags &= ~CLIENT_STATUSOFF;
1.1 nicm 391: }
392:
1.27 nicm 393: /* Walk each window and adjust the size. */
1.33 nicm 394: RB_FOREACH(w, windows, &windows)
395: recalculate_size(w);
1.1 nicm 396: }