1 /* $OpenBSD: resize.c,v 1.36 2019/11/29 16:04:07 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> 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 25 void 26 resize_window(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel) 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; 53 window_resize(w, sx, sy, xpixel, ypixel); 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); 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 } 65 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 78 void 79 default_window_size(struct client *c, struct session *s, struct window *w, 80 u_int *sx, u_int *sy, u_int *xpixel, u_int *ypixel, int type) 81 { 82 struct client *loop; 83 u_int cx, cy, n; 84 const char *value; 85 86 if (type == -1) 87 type = options_get_number(global_w_options, "window-size"); 88 switch (type) { 89 case WINDOW_SIZE_LARGEST: 90 *sx = *sy = 0; 91 *xpixel = *ypixel = 0; 92 TAILQ_FOREACH(loop, &clients, entry) { 93 if (ignore_client_size(loop)) 94 continue; 95 if (w != NULL && !session_has(loop->session, w)) 96 continue; 97 if (w == NULL && loop->session != s) 98 continue; 99 100 cx = loop->tty.sx; 101 cy = loop->tty.sy - status_line_size(loop); 102 103 if (cx > *sx) 104 *sx = cx; 105 if (cy > *sy) 106 *sy = cy; 107 108 if (loop->tty.xpixel > *xpixel && 109 loop->tty.ypixel > *ypixel) { 110 *xpixel = loop->tty.xpixel; 111 *ypixel = loop->tty.ypixel; 112 } 113 } 114 if (*sx == 0 || *sy == 0) 115 goto manual; 116 break; 117 case WINDOW_SIZE_SMALLEST: 118 *sx = *sy = UINT_MAX; 119 *xpixel = *ypixel = 0; 120 TAILQ_FOREACH(loop, &clients, entry) { 121 if (ignore_client_size(loop)) 122 continue; 123 if (w != NULL && !session_has(loop->session, w)) 124 continue; 125 if (w == NULL && loop->session != s) 126 continue; 127 128 cx = loop->tty.sx; 129 cy = loop->tty.sy - status_line_size(loop); 130 131 if (cx < *sx) 132 *sx = cx; 133 if (cy < *sy) 134 *sy = cy; 135 136 if (loop->tty.xpixel > *xpixel && 137 loop->tty.ypixel > *ypixel) { 138 *xpixel = loop->tty.xpixel; 139 *ypixel = loop->tty.ypixel; 140 } 141 } 142 if (*sx == UINT_MAX || *sy == UINT_MAX) 143 goto manual; 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); 149 *xpixel = c->tty.xpixel; 150 *ypixel = c->tty.ypixel; 151 } else { 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 } 162 *sx = *sy = UINT_MAX; 163 *xpixel = *ypixel = 0; 164 TAILQ_FOREACH(loop, &clients, entry) { 165 if (ignore_client_size(loop)) 166 continue; 167 if (n > 1 && loop != w->latest) 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; 178 179 if (loop->tty.xpixel > *xpixel && 180 loop->tty.ypixel > *ypixel) { 181 *xpixel = loop->tty.xpixel; 182 *ypixel = loop->tty.ypixel; 183 } 184 } 185 if (*sx == UINT_MAX || *sy == UINT_MAX) 186 goto manual; 187 } 188 break; 189 case WINDOW_SIZE_MANUAL: 190 goto manual; 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 } 211 212 void 213 recalculate_size(struct window *w) 214 { 215 struct session *s; 216 struct client *c; 217 u_int sx, sy, cx, cy, xpixel = 0, ypixel = 0, n; 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; 250 251 if (c->tty.xpixel > xpixel && c->tty.ypixel > ypixel) { 252 xpixel = c->tty.xpixel; 253 ypixel = c->tty.ypixel; 254 } 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; 280 281 if (c->tty.xpixel > xpixel && c->tty.ypixel > ypixel) { 282 xpixel = c->tty.xpixel; 283 ypixel = c->tty.ypixel; 284 } 285 } 286 if (sx == UINT_MAX || sy == UINT_MAX) 287 changed = 0; 288 break; 289 case WINDOW_SIZE_LATEST: 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 } 298 sx = sy = UINT_MAX; 299 TAILQ_FOREACH(c, &clients, entry) { 300 if (ignore_client_size(c)) 301 continue; 302 if (n > 1 && c != w->latest) 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; 320 321 if (c->tty.xpixel > xpixel && c->tty.ypixel > ypixel) { 322 xpixel = c->tty.xpixel; 323 ypixel = c->tty.ypixel; 324 } 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 } 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); 343 } 344 345 void 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; 358 status_update_cache(s); 359 } 360 361 /* 362 * Increment attached count and check the status line size for each 363 * client. 364 */ 365 TAILQ_FOREACH(c, &clients, entry) { 366 if (ignore_client_size(c)) 367 continue; 368 s = c->session; 369 if (c->tty.sy <= s->statuslines || (c->flags & CLIENT_CONTROL)) 370 c->flags |= CLIENT_STATUSOFF; 371 else 372 c->flags &= ~CLIENT_STATUSOFF; 373 s->attached++; 374 } 375 376 /* Walk each window and adjust the size. */ 377 RB_FOREACH(w, windows, &windows) 378 recalculate_size(w); 379 } 380