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