| File: | src/usr.bin/tmux/resize.c |
| Warning: | line 458, column 20 Access to field 'statuslines' results in a dereference of a null pointer (loaded from variable 's') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: resize.c,v 1.50 2022/02/17 09:58:47 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_MINIMUM1) | |||
| 32 | sx = WINDOW_MINIMUM1; | |||
| 33 | if (sx > WINDOW_MAXIMUM10000) | |||
| 34 | sx = WINDOW_MAXIMUM10000; | |||
| 35 | if (sy < WINDOW_MINIMUM1) | |||
| 36 | sy = WINDOW_MINIMUM1; | |||
| 37 | if (sy > WINDOW_MAXIMUM10000) | |||
| 38 | sy = WINDOW_MAXIMUM10000; | |||
| 39 | ||||
| 40 | /* If the window is zoomed, unzoom. */ | |||
| 41 | zoomed = w->flags & WINDOW_ZOOMED0x8; | |||
| 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 %ux%u; layout %ux%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 | notify_window("window-resized", w); | |||
| 65 | w->flags &= ~WINDOW_RESIZE0x20; | |||
| 66 | } | |||
| 67 | ||||
| 68 | static int | |||
| 69 | ignore_client_size(struct client *c) | |||
| 70 | { | |||
| 71 | struct client *loop; | |||
| 72 | ||||
| 73 | if (c->session == NULL((void *)0)) | |||
| 74 | return (1); | |||
| 75 | if (c->flags & CLIENT_NOSIZEFLAGS(0x200| 0x40| 0x4)) | |||
| 76 | return (1); | |||
| 77 | if (c->flags & CLIENT_IGNORESIZE0x20000) { | |||
| 78 | /* | |||
| 79 | * Ignore flagged clients if there are any attached clients | |||
| 80 | * that aren't flagged. | |||
| 81 | */ | |||
| 82 | TAILQ_FOREACH (loop, &clients, entry)for((loop) = ((&clients)->tqh_first); (loop) != ((void *)0); (loop) = ((loop)->entry.tqe_next)) { | |||
| 83 | if (loop->session == NULL((void *)0)) | |||
| 84 | continue; | |||
| 85 | if (loop->flags & CLIENT_NOSIZEFLAGS(0x200| 0x40| 0x4)) | |||
| 86 | continue; | |||
| 87 | if (~loop->flags & CLIENT_IGNORESIZE0x20000) | |||
| 88 | return (1); | |||
| 89 | } | |||
| 90 | } | |||
| 91 | if ((c->flags & CLIENT_CONTROL0x2000) && | |||
| 92 | (~c->flags & CLIENT_SIZECHANGED0x400000) && | |||
| 93 | (~c->flags & CLIENT_WINDOWSIZECHANGED0x400000000ULL)) | |||
| 94 | return (1); | |||
| 95 | return (0); | |||
| 96 | } | |||
| 97 | ||||
| 98 | static u_int | |||
| 99 | clients_with_window(struct window *w) | |||
| 100 | { | |||
| 101 | struct client *loop; | |||
| 102 | u_int n = 0; | |||
| 103 | ||||
| 104 | TAILQ_FOREACH(loop, &clients, entry)for((loop) = ((&clients)->tqh_first); (loop) != ((void *)0); (loop) = ((loop)->entry.tqe_next)) { | |||
| 105 | if (ignore_client_size(loop) || !session_has(loop->session, w)) | |||
| 106 | continue; | |||
| 107 | if (++n > 1) | |||
| 108 | break; | |||
| 109 | } | |||
| 110 | return (n); | |||
| 111 | } | |||
| 112 | ||||
| 113 | static int | |||
| 114 | clients_calculate_size(int type, int current, struct client *c, | |||
| 115 | struct session *s, struct window *w, int (*skip_client)(struct client *, | |||
| 116 | int, int, struct session *, struct window *), u_int *sx, u_int *sy, | |||
| 117 | u_int *xpixel, u_int *ypixel) | |||
| 118 | { | |||
| 119 | struct client *loop; | |||
| 120 | struct client_window *cw; | |||
| 121 | u_int cx, cy, n = 0; | |||
| 122 | ||||
| 123 | /* | |||
| 124 | * Start comparing with 0 for largest and UINT_MAX for smallest or | |||
| 125 | * latest. | |||
| 126 | */ | |||
| 127 | if (type == WINDOW_SIZE_LARGEST0) { | |||
| 128 | *sx = 0; | |||
| 129 | *sy = 0; | |||
| 130 | } else if (type == WINDOW_SIZE_MANUAL2) { | |||
| 131 | *sx = w->manual_sx; | |||
| 132 | *sy = w->manual_sy; | |||
| 133 | log_debug("%s: manual size %ux%u", __func__, *sx, *sy); | |||
| 134 | } else { | |||
| 135 | *sx = UINT_MAX0xffffffffU; | |||
| 136 | *sy = UINT_MAX0xffffffffU; | |||
| 137 | } | |||
| 138 | *xpixel = *ypixel = 0; | |||
| 139 | ||||
| 140 | /* | |||
| 141 | * For latest, count the number of clients with this window. We only | |||
| 142 | * care if there is more than one. | |||
| 143 | */ | |||
| 144 | if (type == WINDOW_SIZE_LATEST3 && w != NULL((void *)0)) | |||
| 145 | n = clients_with_window(w); | |||
| 146 | ||||
| 147 | /* Skip setting the size if manual */ | |||
| 148 | if (type == WINDOW_SIZE_MANUAL2) | |||
| 149 | goto skip; | |||
| 150 | ||||
| 151 | /* Loop over the clients and work out the size. */ | |||
| 152 | TAILQ_FOREACH(loop, &clients, entry)for((loop) = ((&clients)->tqh_first); (loop) != ((void *)0); (loop) = ((loop)->entry.tqe_next)) { | |||
| 153 | if (loop != c && ignore_client_size(loop)) { | |||
| 154 | log_debug("%s: ignoring %s (1)", __func__, loop->name); | |||
| 155 | continue; | |||
| 156 | } | |||
| 157 | if (loop != c && skip_client(loop, type, current, s, w)) { | |||
| 158 | log_debug("%s: skipping %s (1)", __func__, loop->name); | |||
| 159 | continue; | |||
| 160 | } | |||
| 161 | ||||
| 162 | /* | |||
| 163 | * If there are multiple clients attached, only accept the | |||
| 164 | * latest client; otherwise let the only client be chosen as | |||
| 165 | * for smallest. | |||
| 166 | */ | |||
| 167 | if (type == WINDOW_SIZE_LATEST3 && n > 1 && loop != w->latest) { | |||
| 168 | log_debug("%s: %s is not latest", __func__, loop->name); | |||
| 169 | continue; | |||
| 170 | } | |||
| 171 | ||||
| 172 | /* | |||
| 173 | * If the client has a per-window size, use this instead if it is | |||
| 174 | * smaller. | |||
| 175 | */ | |||
| 176 | if (w != NULL((void *)0)) | |||
| 177 | cw = server_client_get_client_window(loop, w->id); | |||
| 178 | else | |||
| 179 | cw = NULL((void *)0); | |||
| 180 | ||||
| 181 | /* Work out this client's size. */ | |||
| 182 | if (cw != NULL((void *)0) && cw->sx != 0 && cw->sy != 0) { | |||
| 183 | cx = cw->sx; | |||
| 184 | cy = cw->sy; | |||
| 185 | } else { | |||
| 186 | cx = loop->tty.sx; | |||
| 187 | cy = loop->tty.sy - status_line_size(loop); | |||
| 188 | } | |||
| 189 | ||||
| 190 | /* | |||
| 191 | * If it is larger or smaller than the best so far, update the | |||
| 192 | * new size. | |||
| 193 | */ | |||
| 194 | if (type == WINDOW_SIZE_LARGEST0) { | |||
| 195 | if (cx > *sx) | |||
| 196 | *sx = cx; | |||
| 197 | if (cy > *sy) | |||
| 198 | *sy = cy; | |||
| 199 | } else { | |||
| 200 | if (cx < *sx) | |||
| 201 | *sx = cx; | |||
| 202 | if (cy < *sy) | |||
| 203 | *sy = cy; | |||
| 204 | } | |||
| 205 | if (loop->tty.xpixel > *xpixel && loop->tty.ypixel > *ypixel) { | |||
| 206 | *xpixel = loop->tty.xpixel; | |||
| 207 | *ypixel = loop->tty.ypixel; | |||
| 208 | } | |||
| 209 | log_debug("%s: after %s (%ux%u), size is %ux%u", __func__, | |||
| 210 | loop->name, cx, cy, *sx, *sy); | |||
| 211 | } | |||
| 212 | if (*sx != UINT_MAX0xffffffffU && *sy != UINT_MAX0xffffffffU) | |||
| 213 | log_debug("%s: calculated size %ux%u", __func__, *sx, *sy); | |||
| 214 | else | |||
| 215 | log_debug("%s: no calculated size", __func__); | |||
| 216 | ||||
| 217 | skip: | |||
| 218 | /* | |||
| 219 | * Do not allow any size to be larger than the per-client window size | |||
| 220 | * if one exists. | |||
| 221 | */ | |||
| 222 | if (w != NULL((void *)0)) { | |||
| 223 | TAILQ_FOREACH(loop, &clients, entry)for((loop) = ((&clients)->tqh_first); (loop) != ((void *)0); (loop) = ((loop)->entry.tqe_next)) { | |||
| 224 | if (loop != c && ignore_client_size(loop)) | |||
| 225 | continue; | |||
| 226 | if (loop != c && skip_client(loop, type, current, s, w)) | |||
| 227 | continue; | |||
| 228 | ||||
| 229 | /* Look up per-window size if any. */ | |||
| 230 | if (~loop->flags & CLIENT_WINDOWSIZECHANGED0x400000000ULL) | |||
| 231 | continue; | |||
| 232 | cw = server_client_get_client_window(loop, w->id); | |||
| 233 | if (cw == NULL((void *)0)) | |||
| 234 | continue; | |||
| 235 | ||||
| 236 | /* Clamp the size. */ | |||
| 237 | log_debug("%s: %s size for @%u is %ux%u", __func__, | |||
| 238 | loop->name, w->id, cw->sx, cw->sy); | |||
| 239 | if (cw->sx != 0 && *sx > cw->sx) | |||
| 240 | *sx = cw->sx; | |||
| 241 | if (cw->sy != 0 && *sy > cw->sy) | |||
| 242 | *sy = cw->sy; | |||
| 243 | } | |||
| 244 | } | |||
| 245 | if (*sx != UINT_MAX0xffffffffU && *sy != UINT_MAX0xffffffffU) | |||
| 246 | log_debug("%s: calculated size %ux%u", __func__, *sx, *sy); | |||
| 247 | else | |||
| 248 | log_debug("%s: no calculated size", __func__); | |||
| 249 | ||||
| 250 | /* Return whether a suitable size was found. */ | |||
| 251 | if (type == WINDOW_SIZE_MANUAL2) { | |||
| 252 | log_debug("%s: type is manual", __func__); | |||
| 253 | return (1); | |||
| 254 | } | |||
| 255 | if (type == WINDOW_SIZE_LARGEST0) { | |||
| 256 | log_debug("%s: type is largest", __func__); | |||
| 257 | return (*sx != 0 && *sy != 0); | |||
| 258 | } | |||
| 259 | if (type == WINDOW_SIZE_LATEST3) | |||
| 260 | log_debug("%s: type is latest", __func__); | |||
| 261 | else | |||
| 262 | log_debug("%s: type is smallest", __func__); | |||
| 263 | return (*sx != UINT_MAX0xffffffffU && *sy != UINT_MAX0xffffffffU); | |||
| 264 | } | |||
| 265 | ||||
| 266 | static int | |||
| 267 | default_window_size_skip_client(struct client *loop, int type, | |||
| 268 | __unused__attribute__((__unused__)) int current, struct session *s, struct window *w) | |||
| 269 | { | |||
| 270 | /* | |||
| 271 | * Latest checks separately, so do not check here. Otherwise only | |||
| 272 | * include clients where the session contains the window or where the | |||
| 273 | * session is the given session. | |||
| 274 | */ | |||
| 275 | if (type == WINDOW_SIZE_LATEST3) | |||
| 276 | return (0); | |||
| 277 | if (w != NULL((void *)0) && !session_has(loop->session, w)) | |||
| 278 | return (1); | |||
| 279 | if (w == NULL((void *)0) && loop->session != s) | |||
| 280 | return (1); | |||
| 281 | return (0); | |||
| 282 | } | |||
| 283 | ||||
| 284 | void | |||
| 285 | default_window_size(struct client *c, struct session *s, struct window *w, | |||
| 286 | u_int *sx, u_int *sy, u_int *xpixel, u_int *ypixel, int type) | |||
| 287 | { | |||
| 288 | const char *value; | |||
| 289 | ||||
| 290 | /* Get type if not provided. */ | |||
| 291 | if (type == -1) | |||
| 292 | type = options_get_number(global_w_options, "window-size"); | |||
| 293 | ||||
| 294 | /* | |||
| 295 | * Latest clients can use the given client if suitable. If there is no | |||
| 296 | * client and no window, use the default size as for manual type. | |||
| 297 | */ | |||
| 298 | if (type == WINDOW_SIZE_LATEST3 && c != NULL((void *)0) && !ignore_client_size(c)) { | |||
| 299 | *sx = c->tty.sx; | |||
| 300 | *sy = c->tty.sy - status_line_size(c); | |||
| 301 | *xpixel = c->tty.xpixel; | |||
| 302 | *ypixel = c->tty.ypixel; | |||
| 303 | log_debug("%s: using %ux%u from %s", __func__, *sx, *sy, | |||
| 304 | c->name); | |||
| 305 | goto done; | |||
| 306 | } | |||
| 307 | ||||
| 308 | /* | |||
| 309 | * Ignore the given client if it is a control client - the creating | |||
| 310 | * client should only affect the size if it is not a control client. | |||
| 311 | */ | |||
| 312 | if (c != NULL((void *)0) && (c->flags & CLIENT_CONTROL0x2000)) | |||
| 313 | c = NULL((void *)0); | |||
| 314 | ||||
| 315 | /* | |||
| 316 | * Look for a client to base the size on. If none exists (or the type | |||
| 317 | * is manual), use the default-size option. | |||
| 318 | */ | |||
| 319 | if (!clients_calculate_size(type, 0, c, s, w, | |||
| 320 | default_window_size_skip_client, sx, sy, xpixel, ypixel)) { | |||
| 321 | value = options_get_string(s->options, "default-size"); | |||
| 322 | if (sscanf(value, "%ux%u", sx, sy) != 2) { | |||
| 323 | *sx = 80; | |||
| 324 | *sy = 24; | |||
| 325 | } | |||
| 326 | log_debug("%s: using %ux%u from default-size", __func__, *sx, | |||
| 327 | *sy); | |||
| 328 | } | |||
| 329 | ||||
| 330 | done: | |||
| 331 | /* Make sure the limits are enforced. */ | |||
| 332 | if (*sx < WINDOW_MINIMUM1) | |||
| 333 | *sx = WINDOW_MINIMUM1; | |||
| 334 | if (*sx > WINDOW_MAXIMUM10000) | |||
| 335 | *sx = WINDOW_MAXIMUM10000; | |||
| 336 | if (*sy < WINDOW_MINIMUM1) | |||
| 337 | *sy = WINDOW_MINIMUM1; | |||
| 338 | if (*sy > WINDOW_MAXIMUM10000) | |||
| 339 | *sy = WINDOW_MAXIMUM10000; | |||
| 340 | log_debug("%s: resulting size is %ux%u", __func__, *sx, *sy); | |||
| 341 | } | |||
| 342 | ||||
| 343 | static int | |||
| 344 | recalculate_size_skip_client(struct client *loop, __unused__attribute__((__unused__)) int type, | |||
| 345 | int current, __unused__attribute__((__unused__)) struct session *s, struct window *w) | |||
| 346 | { | |||
| 347 | /* | |||
| 348 | * If the current flag is set, then skip any client where this window | |||
| 349 | * is not the current window - this is used for aggressive-resize. | |||
| 350 | * Otherwise skip any session that doesn't contain the window. | |||
| 351 | */ | |||
| 352 | if (loop->session->curw == NULL((void *)0)) | |||
| 353 | return (1); | |||
| 354 | if (current) | |||
| 355 | return (loop->session->curw->window != w); | |||
| 356 | return (session_has(loop->session, w) == 0); | |||
| 357 | } | |||
| 358 | ||||
| 359 | void | |||
| 360 | recalculate_size(struct window *w, int now) | |||
| 361 | { | |||
| 362 | u_int sx, sy, xpixel = 0, ypixel = 0; | |||
| 363 | int type, current, changed; | |||
| 364 | ||||
| 365 | /* | |||
| 366 | * Do not attempt to resize windows which have no pane, they must be on | |||
| 367 | * the way to destruction. | |||
| 368 | */ | |||
| 369 | if (w->active == NULL((void *)0)) | |||
| 370 | return; | |||
| 371 | log_debug("%s: @%u is %ux%u", __func__, w->id, w->sx, w->sy); | |||
| 372 | ||||
| 373 | /* | |||
| 374 | * Type is manual, smallest, largest, latest. Current is the | |||
| 375 | * aggressive-resize option (do not resize based on clients where the | |||
| 376 | * window is not the current window). | |||
| 377 | */ | |||
| 378 | type = options_get_number(w->options, "window-size"); | |||
| 379 | current = options_get_number(w->options, "aggressive-resize"); | |||
| 380 | ||||
| 381 | /* Look for a suitable client and get the new size. */ | |||
| 382 | changed = clients_calculate_size(type, current, NULL((void *)0), NULL((void *)0), w, | |||
| 383 | recalculate_size_skip_client, &sx, &sy, &xpixel, &ypixel); | |||
| 384 | ||||
| 385 | /* | |||
| 386 | * Make sure the size has actually changed. If the window has already | |||
| 387 | * got a resize scheduled, then use the new size; otherwise the old. | |||
| 388 | */ | |||
| 389 | if (w->flags & WINDOW_RESIZE0x20) { | |||
| 390 | if (!now && changed && w->new_sx == sx && w->new_sy == sy) | |||
| 391 | changed = 0; | |||
| 392 | } else { | |||
| 393 | if (!now && changed && w->sx == sx && w->sy == sy) | |||
| 394 | changed = 0; | |||
| 395 | } | |||
| 396 | ||||
| 397 | /* | |||
| 398 | * If the size hasn't changed, update the window offset but not the | |||
| 399 | * size. | |||
| 400 | */ | |||
| 401 | if (!changed) { | |||
| 402 | log_debug("%s: @%u no size change", __func__, w->id); | |||
| 403 | tty_update_window_offset(w); | |||
| 404 | return; | |||
| 405 | } | |||
| 406 | ||||
| 407 | /* | |||
| 408 | * If the now flag is set or if the window is sized manually, change | |||
| 409 | * the size immediately. Otherwise set the flag and it will be done | |||
| 410 | * later. | |||
| 411 | */ | |||
| 412 | log_debug("%s: @%u new size %ux%u", __func__, w->id, sx, sy); | |||
| 413 | if (now || type == WINDOW_SIZE_MANUAL2) | |||
| 414 | resize_window(w, sx, sy, xpixel, ypixel); | |||
| 415 | else { | |||
| 416 | w->new_sx = sx; | |||
| 417 | w->new_sy = sy; | |||
| 418 | w->new_xpixel = xpixel; | |||
| 419 | w->new_ypixel = ypixel; | |||
| 420 | ||||
| 421 | w->flags |= WINDOW_RESIZE0x20; | |||
| 422 | tty_update_window_offset(w); | |||
| 423 | } | |||
| 424 | } | |||
| 425 | ||||
| 426 | void | |||
| 427 | recalculate_sizes(void) | |||
| 428 | { | |||
| 429 | recalculate_sizes_now(0); | |||
| ||||
| 430 | } | |||
| 431 | ||||
| 432 | void | |||
| 433 | recalculate_sizes_now(int now) | |||
| 434 | { | |||
| 435 | struct session *s; | |||
| 436 | struct client *c; | |||
| 437 | struct window *w; | |||
| 438 | ||||
| 439 | /* | |||
| 440 | * Clear attached count and update saved status line information for | |||
| 441 | * each session. | |||
| 442 | */ | |||
| 443 | RB_FOREACH(s, sessions, &sessions)for ((s) = sessions_RB_MINMAX(&sessions, -1); (s) != ((void *)0); (s) = sessions_RB_NEXT(s)) { | |||
| 444 | s->attached = 0; | |||
| 445 | status_update_cache(s); | |||
| 446 | } | |||
| 447 | ||||
| 448 | /* | |||
| 449 | * Increment attached count and check the status line size for each | |||
| 450 | * client. | |||
| 451 | */ | |||
| 452 | TAILQ_FOREACH(c, &clients, entry)for((c) = ((&clients)->tqh_first); (c) != ((void *)0); (c) = ((c)->entry.tqe_next)) { | |||
| 453 | s = c->session; | |||
| 454 | if (s != NULL((void *)0) && !(c->flags & CLIENT_UNATTACHEDFLAGS(0x200| 0x40| 0x4))) | |||
| 455 | s->attached++; | |||
| 456 | if (ignore_client_size(c)) | |||
| 457 | continue; | |||
| 458 | if (c->tty.sy <= s->statuslines || (c->flags & CLIENT_CONTROL0x2000)) | |||
| ||||
| 459 | c->flags |= CLIENT_STATUSOFF0x800000; | |||
| 460 | else | |||
| 461 | c->flags &= ~CLIENT_STATUSOFF0x800000; | |||
| 462 | } | |||
| 463 | ||||
| 464 | /* Walk each window and adjust the size. */ | |||
| 465 | RB_FOREACH(w, windows, &windows)for ((w) = windows_RB_MINMAX(&windows, -1); (w) != ((void *)0); (w) = windows_RB_NEXT(w)) | |||
| 466 | recalculate_size(w, now); | |||
| 467 | } |