1 /* $OpenBSD: resize.c,v 1.31 2019/04/17 14:43:49 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) 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); 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 session *s, struct window *w, u_int *sx, u_int *sy, 80 int type) 81 { 82 struct client *c; 83 u_int cx, cy; 84 const char *value; 85 86 if (type == -1) 87 type = options_get_number(global_w_options, "window-size"); 88 if (type == WINDOW_SIZE_MANUAL) 89 goto manual; 90 91 if (type == WINDOW_SIZE_LARGEST) { 92 *sx = *sy = 0; 93 TAILQ_FOREACH(c, &clients, entry) { 94 if (ignore_client_size(c)) 95 continue; 96 if (w != NULL && !session_has(c->session, w)) 97 continue; 98 if (w == NULL && c->session != s) 99 continue; 100 101 cx = c->tty.sx; 102 cy = c->tty.sy - status_line_size(c); 103 104 if (cx > *sx) 105 *sx = cx; 106 if (cy > *sy) 107 *sy = cy; 108 } 109 if (*sx == 0 || *sy == 0) 110 goto manual; 111 } else { 112 *sx = *sy = UINT_MAX; 113 TAILQ_FOREACH(c, &clients, entry) { 114 if (ignore_client_size(c)) 115 continue; 116 if (w != NULL && !session_has(c->session, w)) 117 continue; 118 if (w == NULL && c->session != s) 119 continue; 120 121 cx = c->tty.sx; 122 cy = c->tty.sy - status_line_size(c); 123 124 if (cx < *sx) 125 *sx = cx; 126 if (cy < *sy) 127 *sy = cy; 128 } 129 if (*sx == UINT_MAX || *sy == UINT_MAX) 130 goto manual; 131 } 132 goto done; 133 134 manual: 135 value = options_get_string(s->options, "default-size"); 136 if (sscanf(value, "%ux%u", sx, sy) != 2) { 137 *sx = 80; 138 *sy = 24; 139 } 140 141 done: 142 if (*sx < WINDOW_MINIMUM) 143 *sx = WINDOW_MINIMUM; 144 if (*sx > WINDOW_MAXIMUM) 145 *sx = WINDOW_MAXIMUM; 146 if (*sy < WINDOW_MINIMUM) 147 *sy = WINDOW_MINIMUM; 148 if (*sy > WINDOW_MAXIMUM) 149 *sy = WINDOW_MAXIMUM; 150 } 151 152 void 153 recalculate_sizes(void) 154 { 155 struct session *s; 156 struct client *c; 157 struct window *w; 158 u_int sx, sy, cx, cy; 159 int type, current, has, changed; 160 161 /* 162 * Clear attached count and update saved status line information for 163 * each session. 164 */ 165 RB_FOREACH(s, sessions, &sessions) { 166 s->attached = 0; 167 status_update_cache(s); 168 } 169 170 /* 171 * Increment attached count and check the status line size for each 172 * client. 173 */ 174 TAILQ_FOREACH(c, &clients, entry) { 175 if (ignore_client_size(c)) 176 continue; 177 if (c->tty.sy <= status_line_size(c)) 178 c->flags |= CLIENT_STATUSOFF; 179 else 180 c->flags &= ~CLIENT_STATUSOFF; 181 c->session->attached++; 182 } 183 184 /* Walk each window and adjust the size. */ 185 RB_FOREACH(w, windows, &windows) { 186 if (w->active == NULL) 187 continue; 188 log_debug("%s: @%u is %u,%u", __func__, w->id, w->sx, w->sy); 189 190 type = options_get_number(w->options, "window-size"); 191 if (type == WINDOW_SIZE_MANUAL) 192 continue; 193 current = options_get_number(w->options, "aggressive-resize"); 194 195 changed = 1; 196 if (type == WINDOW_SIZE_LARGEST) { 197 sx = sy = 0; 198 TAILQ_FOREACH(c, &clients, entry) { 199 if (ignore_client_size(c)) 200 continue; 201 s = c->session; 202 203 if (current) 204 has = (s->curw->window == w); 205 else 206 has = session_has(s, w); 207 if (!has) 208 continue; 209 210 cx = c->tty.sx; 211 cy = c->tty.sy - status_line_size(c); 212 213 if (cx > sx) 214 sx = cx; 215 if (cy > sy) 216 sy = cy; 217 } 218 if (sx == 0 || sy == 0) 219 changed = 0; 220 } else { 221 sx = sy = UINT_MAX; 222 TAILQ_FOREACH(c, &clients, entry) { 223 if (ignore_client_size(c)) 224 continue; 225 s = c->session; 226 227 if (current) 228 has = (s->curw->window == w); 229 else 230 has = session_has(s, w); 231 if (!has) 232 continue; 233 234 cx = c->tty.sx; 235 cy = c->tty.sy - status_line_size(c); 236 237 if (cx < sx) 238 sx = cx; 239 if (cy < sy) 240 sy = cy; 241 } 242 if (sx == UINT_MAX || sy == UINT_MAX) 243 changed = 0; 244 } 245 if (w->sx == sx && w->sy == sy) 246 changed = 0; 247 248 if (!changed) { 249 tty_update_window_offset(w); 250 continue; 251 } 252 log_debug("%s: @%u changed to %u,%u", __func__, w->id, sx, sy); 253 resize_window(w, sx, sy); 254 } 255 } 256