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