1*cd409aaeSnicm /* $OpenBSD: layout-set.c,v 1.32 2024/08/23 10:19:06 nicm Exp $ */ 2af9e4c5dSnicm 3af9e4c5dSnicm /* 498ca8272Snicm * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com> 5af9e4c5dSnicm * 6af9e4c5dSnicm * Permission to use, copy, modify, and distribute this software for any 7af9e4c5dSnicm * purpose with or without fee is hereby granted, provided that the above 8af9e4c5dSnicm * copyright notice and this permission notice appear in all copies. 9af9e4c5dSnicm * 10af9e4c5dSnicm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11af9e4c5dSnicm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12af9e4c5dSnicm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13af9e4c5dSnicm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14af9e4c5dSnicm * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15af9e4c5dSnicm * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16af9e4c5dSnicm * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17af9e4c5dSnicm */ 18af9e4c5dSnicm 19af9e4c5dSnicm #include <sys/types.h> 20af9e4c5dSnicm 21c6e6a0b3Snicm #include <stdlib.h> 22af9e4c5dSnicm #include <string.h> 23af9e4c5dSnicm 24af9e4c5dSnicm #include "tmux.h" 25af9e4c5dSnicm 26af9e4c5dSnicm /* 27bfcd10e2Snicm * Set window layouts - predefined methods to arrange windows. These are 28bfcd10e2Snicm * one-off and generate a layout tree. 29af9e4c5dSnicm */ 30af9e4c5dSnicm 319883b791Snicm static void layout_set_even_h(struct window *); 329883b791Snicm static void layout_set_even_v(struct window *); 339883b791Snicm static void layout_set_main_h(struct window *); 3414aabaa7Snicm static void layout_set_main_h_mirrored(struct window *); 359883b791Snicm static void layout_set_main_v(struct window *); 3614aabaa7Snicm static void layout_set_main_v_mirrored(struct window *); 379883b791Snicm static void layout_set_tiled(struct window *); 38af9e4c5dSnicm 39c97fab4eSnicm static const struct { 40af9e4c5dSnicm const char *name; 41af9e4c5dSnicm void (*arrange)(struct window *); 42af9e4c5dSnicm } layout_sets[] = { 43af9e4c5dSnicm { "even-horizontal", layout_set_even_h }, 44af9e4c5dSnicm { "even-vertical", layout_set_even_v }, 45af9e4c5dSnicm { "main-horizontal", layout_set_main_h }, 4614aabaa7Snicm { "main-horizontal-mirrored", layout_set_main_h_mirrored }, 47af9e4c5dSnicm { "main-vertical", layout_set_main_v }, 4814aabaa7Snicm { "main-vertical-mirrored", layout_set_main_v_mirrored }, 49fcae69d1Snicm { "tiled", layout_set_tiled }, 50af9e4c5dSnicm }; 51af9e4c5dSnicm 52af9e4c5dSnicm int 53af9e4c5dSnicm layout_set_lookup(const char *name) 54af9e4c5dSnicm { 55af9e4c5dSnicm u_int i; 56af9e4c5dSnicm int matched = -1; 57af9e4c5dSnicm 58af9e4c5dSnicm for (i = 0; i < nitems(layout_sets); i++) { 59*cd409aaeSnicm if (strcmp(layout_sets[i].name, name) == 0) 60*cd409aaeSnicm return (i); 61*cd409aaeSnicm } 62*cd409aaeSnicm for (i = 0; i < nitems(layout_sets); i++) { 63af9e4c5dSnicm if (strncmp(layout_sets[i].name, name, strlen(name)) == 0) { 64af9e4c5dSnicm if (matched != -1) /* ambiguous */ 65af9e4c5dSnicm return (-1); 66af9e4c5dSnicm matched = i; 67af9e4c5dSnicm } 68af9e4c5dSnicm } 69af9e4c5dSnicm 70af9e4c5dSnicm return (matched); 71af9e4c5dSnicm } 72af9e4c5dSnicm 73af9e4c5dSnicm u_int 74af9e4c5dSnicm layout_set_select(struct window *w, u_int layout) 75af9e4c5dSnicm { 76af9e4c5dSnicm if (layout > nitems(layout_sets) - 1) 77af9e4c5dSnicm layout = nitems(layout_sets) - 1; 78af9e4c5dSnicm 79af9e4c5dSnicm if (layout_sets[layout].arrange != NULL) 80af9e4c5dSnicm layout_sets[layout].arrange(w); 81af9e4c5dSnicm 82ba17146dSnicm w->lastlayout = layout; 83af9e4c5dSnicm return (layout); 84af9e4c5dSnicm } 85af9e4c5dSnicm 86af9e4c5dSnicm u_int 87af9e4c5dSnicm layout_set_next(struct window *w) 88af9e4c5dSnicm { 89ba17146dSnicm u_int layout; 90ba17146dSnicm 91ba17146dSnicm if (w->lastlayout == -1) 92ba17146dSnicm layout = 0; 93ba17146dSnicm else { 94ba17146dSnicm layout = w->lastlayout + 1; 95ba17146dSnicm if (layout > nitems(layout_sets) - 1) 96ba17146dSnicm layout = 0; 97ba17146dSnicm } 98af9e4c5dSnicm 99af9e4c5dSnicm if (layout_sets[layout].arrange != NULL) 100af9e4c5dSnicm layout_sets[layout].arrange(w); 101ba17146dSnicm w->lastlayout = layout; 102af9e4c5dSnicm return (layout); 103af9e4c5dSnicm } 104af9e4c5dSnicm 105af9e4c5dSnicm u_int 106af9e4c5dSnicm layout_set_previous(struct window *w) 107af9e4c5dSnicm { 108ba17146dSnicm u_int layout; 109ba17146dSnicm 110ba17146dSnicm if (w->lastlayout == -1) 111ba17146dSnicm layout = nitems(layout_sets) - 1; 112ba17146dSnicm else { 113ba17146dSnicm layout = w->lastlayout; 114ba17146dSnicm if (layout == 0) 115ba17146dSnicm layout = nitems(layout_sets) - 1; 116ba17146dSnicm else 117ba17146dSnicm layout--; 118ba17146dSnicm } 119af9e4c5dSnicm 120af9e4c5dSnicm if (layout_sets[layout].arrange != NULL) 121af9e4c5dSnicm layout_sets[layout].arrange(w); 122ba17146dSnicm w->lastlayout = layout; 123af9e4c5dSnicm return (layout); 124af9e4c5dSnicm } 125af9e4c5dSnicm 1269883b791Snicm static void 127967ee5b9Snicm layout_set_even(struct window *w, enum layout_type type) 128af9e4c5dSnicm { 129af9e4c5dSnicm struct window_pane *wp; 130af9e4c5dSnicm struct layout_cell *lc, *lcnew; 131d4ddf7e1Snicm u_int n, sx, sy; 132af9e4c5dSnicm 133af9e4c5dSnicm layout_print_cell(w->layout_root, __func__, 1); 134af9e4c5dSnicm 135af9e4c5dSnicm /* Get number of panes. */ 136af9e4c5dSnicm n = window_count_panes(w); 137af9e4c5dSnicm if (n <= 1) 138af9e4c5dSnicm return; 139af9e4c5dSnicm 140af9e4c5dSnicm /* Free the old root and construct a new. */ 141af9e4c5dSnicm layout_free(w); 142af9e4c5dSnicm lc = w->layout_root = layout_create_cell(NULL); 143d4ddf7e1Snicm if (type == LAYOUT_LEFTRIGHT) { 144d4ddf7e1Snicm sx = (n * (PANE_MINIMUM + 1)) - 1; 145d4ddf7e1Snicm if (sx < w->sx) 146d4ddf7e1Snicm sx = w->sx; 147d4ddf7e1Snicm sy = w->sy; 148d4ddf7e1Snicm } else { 149d4ddf7e1Snicm sy = (n * (PANE_MINIMUM + 1)) - 1; 150d4ddf7e1Snicm if (sy < w->sy) 151d4ddf7e1Snicm sy = w->sy; 152d4ddf7e1Snicm sx = w->sx; 153d4ddf7e1Snicm } 154d4ddf7e1Snicm layout_set_size(lc, sx, sy, 0, 0); 155967ee5b9Snicm layout_make_node(lc, type); 156af9e4c5dSnicm 157af9e4c5dSnicm /* Build new leaf cells. */ 158af9e4c5dSnicm TAILQ_FOREACH(wp, &w->panes, entry) { 159af9e4c5dSnicm lcnew = layout_create_cell(lc); 160af9e4c5dSnicm layout_make_leaf(lcnew, wp); 1618135e028Snicm lcnew->sx = w->sx; 1628135e028Snicm lcnew->sy = w->sy; 163af9e4c5dSnicm TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry); 164af9e4c5dSnicm } 165af9e4c5dSnicm 166967ee5b9Snicm /* Spread out cells. */ 167967ee5b9Snicm layout_spread_cell(w, lc); 168af9e4c5dSnicm 169af9e4c5dSnicm /* Fix cell offsets. */ 17042fbd26aSnicm layout_fix_offsets(w); 171baddd6b2Snicm layout_fix_panes(w, NULL); 172af9e4c5dSnicm 173af9e4c5dSnicm layout_print_cell(w->layout_root, __func__, 1); 174af9e4c5dSnicm 1754a8b0ea5Snicm window_resize(w, lc->sx, lc->sy, -1, -1); 1764d154873Snicm notify_window("window-layout-changed", w); 177af9e4c5dSnicm server_redraw_window(w); 178af9e4c5dSnicm } 179af9e4c5dSnicm 1809883b791Snicm static void 181967ee5b9Snicm layout_set_even_h(struct window *w) 182967ee5b9Snicm { 183967ee5b9Snicm layout_set_even(w, LAYOUT_LEFTRIGHT); 184967ee5b9Snicm } 185967ee5b9Snicm 186967ee5b9Snicm static void 187af9e4c5dSnicm layout_set_even_v(struct window *w) 188af9e4c5dSnicm { 189967ee5b9Snicm layout_set_even(w, LAYOUT_TOPBOTTOM); 190af9e4c5dSnicm } 191af9e4c5dSnicm 1929883b791Snicm static void 193af9e4c5dSnicm layout_set_main_h(struct window *w) 194af9e4c5dSnicm { 195af9e4c5dSnicm struct window_pane *wp; 19606f48543Snicm struct layout_cell *lc, *lcmain, *lcother, *lcchild; 197439fb663Snicm u_int n, mainh, otherh, sx, sy; 198c6e6a0b3Snicm char *cause; 199c6e6a0b3Snicm const char *s; 200af9e4c5dSnicm 201af9e4c5dSnicm layout_print_cell(w->layout_root, __func__, 1); 202af9e4c5dSnicm 203af9e4c5dSnicm /* Get number of panes. */ 204af9e4c5dSnicm n = window_count_panes(w); 205af9e4c5dSnicm if (n <= 1) 206af9e4c5dSnicm return; 207af9e4c5dSnicm n--; /* take off main pane */ 208af9e4c5dSnicm 209439fb663Snicm /* Find available height - take off one line for the border. */ 210439fb663Snicm sy = w->sy - 1; 211439fb663Snicm 212c6e6a0b3Snicm /* Get the main pane height. */ 213c6e6a0b3Snicm s = options_get_string(w->options, "main-pane-height"); 214c6e6a0b3Snicm mainh = args_string_percentage(s, 0, sy, sy, &cause); 215c6e6a0b3Snicm if (cause != NULL) { 216c6e6a0b3Snicm mainh = 24; 217c6e6a0b3Snicm free(cause); 218c6e6a0b3Snicm } 219c6e6a0b3Snicm 220c6e6a0b3Snicm /* Work out the other pane height. */ 221439fb663Snicm if (mainh + PANE_MINIMUM >= sy) { 222439fb663Snicm if (sy <= PANE_MINIMUM + PANE_MINIMUM) 22306f48543Snicm mainh = PANE_MINIMUM; 224af9e4c5dSnicm else 225439fb663Snicm mainh = sy - PANE_MINIMUM; 22606f48543Snicm otherh = PANE_MINIMUM; 22706f48543Snicm } else { 228c6e6a0b3Snicm s = options_get_string(w->options, "other-pane-height"); 229c6e6a0b3Snicm otherh = args_string_percentage(s, 0, sy, sy, &cause); 230c6e6a0b3Snicm if (cause != NULL || otherh == 0) { 231439fb663Snicm otherh = sy - mainh; 232c6e6a0b3Snicm free(cause); 233c6e6a0b3Snicm } else if (otherh > sy || sy - otherh < mainh) 234439fb663Snicm otherh = sy - mainh; 23506f48543Snicm else 236439fb663Snicm mainh = sy - otherh; 23706f48543Snicm } 23806f48543Snicm 23910d8425bSnicm /* Work out what width is needed. */ 24006f48543Snicm sx = (n * (PANE_MINIMUM + 1)) - 1; 24106f48543Snicm if (sx < w->sx) 24206f48543Snicm sx = w->sx; 243af9e4c5dSnicm 244af9e4c5dSnicm /* Free old tree and create a new root. */ 245af9e4c5dSnicm layout_free(w); 246af9e4c5dSnicm lc = w->layout_root = layout_create_cell(NULL); 247439fb663Snicm layout_set_size(lc, sx, mainh + otherh + 1, 0, 0); 248af9e4c5dSnicm layout_make_node(lc, LAYOUT_TOPBOTTOM); 249af9e4c5dSnicm 250af9e4c5dSnicm /* Create the main pane. */ 251af9e4c5dSnicm lcmain = layout_create_cell(lc); 25206f48543Snicm layout_set_size(lcmain, sx, mainh, 0, 0); 253af9e4c5dSnicm layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes)); 254af9e4c5dSnicm TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry); 255af9e4c5dSnicm 25606f48543Snicm /* Create the other pane. */ 25706f48543Snicm lcother = layout_create_cell(lc); 25806f48543Snicm layout_set_size(lcother, sx, otherh, 0, 0); 25910d8425bSnicm if (n == 1) { 26010d8425bSnicm wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry); 26110d8425bSnicm layout_make_leaf(lcother, wp); 26210d8425bSnicm TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); 26310d8425bSnicm } else { 26406f48543Snicm layout_make_node(lcother, LAYOUT_LEFTRIGHT); 26506f48543Snicm TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); 266af9e4c5dSnicm 26706f48543Snicm /* Add the remaining panes as children. */ 26806f48543Snicm TAILQ_FOREACH(wp, &w->panes, entry) { 26906f48543Snicm if (wp == TAILQ_FIRST(&w->panes)) 270af9e4c5dSnicm continue; 27110d8425bSnicm lcchild = layout_create_cell(lcother); 27206f48543Snicm layout_set_size(lcchild, PANE_MINIMUM, otherh, 0, 0); 273af9e4c5dSnicm layout_make_leaf(lcchild, wp); 27406f48543Snicm TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry); 275af9e4c5dSnicm } 27606f48543Snicm layout_spread_cell(w, lcother); 27710d8425bSnicm } 278af9e4c5dSnicm 279af9e4c5dSnicm /* Fix cell offsets. */ 28042fbd26aSnicm layout_fix_offsets(w); 281baddd6b2Snicm layout_fix_panes(w, NULL); 282af9e4c5dSnicm 283af9e4c5dSnicm layout_print_cell(w->layout_root, __func__, 1); 284af9e4c5dSnicm 2854a8b0ea5Snicm window_resize(w, lc->sx, lc->sy, -1, -1); 2864d154873Snicm notify_window("window-layout-changed", w); 287af9e4c5dSnicm server_redraw_window(w); 288af9e4c5dSnicm } 289af9e4c5dSnicm 2909883b791Snicm static void 29114aabaa7Snicm layout_set_main_h_mirrored(struct window *w) 29214aabaa7Snicm { 29314aabaa7Snicm struct window_pane *wp; 29414aabaa7Snicm struct layout_cell *lc, *lcmain, *lcother, *lcchild; 29514aabaa7Snicm u_int n, mainh, otherh, sx, sy; 29614aabaa7Snicm char *cause; 29714aabaa7Snicm const char *s; 29814aabaa7Snicm 29914aabaa7Snicm layout_print_cell(w->layout_root, __func__, 1); 30014aabaa7Snicm 30114aabaa7Snicm /* Get number of panes. */ 30214aabaa7Snicm n = window_count_panes(w); 30314aabaa7Snicm if (n <= 1) 30414aabaa7Snicm return; 30514aabaa7Snicm n--; /* take off main pane */ 30614aabaa7Snicm 30714aabaa7Snicm /* Find available height - take off one line for the border. */ 30814aabaa7Snicm sy = w->sy - 1; 30914aabaa7Snicm 31014aabaa7Snicm /* Get the main pane height. */ 31114aabaa7Snicm s = options_get_string(w->options, "main-pane-height"); 31214aabaa7Snicm mainh = args_string_percentage(s, 0, sy, sy, &cause); 31314aabaa7Snicm if (cause != NULL) { 31414aabaa7Snicm mainh = 24; 31514aabaa7Snicm free(cause); 31614aabaa7Snicm } 31714aabaa7Snicm 31814aabaa7Snicm /* Work out the other pane height. */ 31914aabaa7Snicm if (mainh + PANE_MINIMUM >= sy) { 32014aabaa7Snicm if (sy <= PANE_MINIMUM + PANE_MINIMUM) 32114aabaa7Snicm mainh = PANE_MINIMUM; 32214aabaa7Snicm else 32314aabaa7Snicm mainh = sy - PANE_MINIMUM; 32414aabaa7Snicm otherh = PANE_MINIMUM; 32514aabaa7Snicm } else { 32614aabaa7Snicm s = options_get_string(w->options, "other-pane-height"); 32714aabaa7Snicm otherh = args_string_percentage(s, 0, sy, sy, &cause); 32814aabaa7Snicm if (cause != NULL || otherh == 0) { 32914aabaa7Snicm otherh = sy - mainh; 33014aabaa7Snicm free(cause); 33114aabaa7Snicm } else if (otherh > sy || sy - otherh < mainh) 33214aabaa7Snicm otherh = sy - mainh; 33314aabaa7Snicm else 33414aabaa7Snicm mainh = sy - otherh; 33514aabaa7Snicm } 33614aabaa7Snicm 33714aabaa7Snicm /* Work out what width is needed. */ 33814aabaa7Snicm sx = (n * (PANE_MINIMUM + 1)) - 1; 33914aabaa7Snicm if (sx < w->sx) 34014aabaa7Snicm sx = w->sx; 34114aabaa7Snicm 34214aabaa7Snicm /* Free old tree and create a new root. */ 34314aabaa7Snicm layout_free(w); 34414aabaa7Snicm lc = w->layout_root = layout_create_cell(NULL); 34514aabaa7Snicm layout_set_size(lc, sx, mainh + otherh + 1, 0, 0); 34614aabaa7Snicm layout_make_node(lc, LAYOUT_TOPBOTTOM); 34714aabaa7Snicm 34814aabaa7Snicm /* Create the other pane. */ 34914aabaa7Snicm lcother = layout_create_cell(lc); 35014aabaa7Snicm layout_set_size(lcother, sx, otherh, 0, 0); 35114aabaa7Snicm if (n == 1) { 35214aabaa7Snicm wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry); 35314aabaa7Snicm layout_make_leaf(lcother, wp); 35414aabaa7Snicm TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); 35514aabaa7Snicm } else { 35614aabaa7Snicm layout_make_node(lcother, LAYOUT_LEFTRIGHT); 35714aabaa7Snicm TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); 35814aabaa7Snicm 35914aabaa7Snicm /* Add the remaining panes as children. */ 36014aabaa7Snicm TAILQ_FOREACH(wp, &w->panes, entry) { 36114aabaa7Snicm if (wp == TAILQ_FIRST(&w->panes)) 36214aabaa7Snicm continue; 36314aabaa7Snicm lcchild = layout_create_cell(lcother); 36414aabaa7Snicm layout_set_size(lcchild, PANE_MINIMUM, otherh, 0, 0); 36514aabaa7Snicm layout_make_leaf(lcchild, wp); 36614aabaa7Snicm TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry); 36714aabaa7Snicm } 36814aabaa7Snicm layout_spread_cell(w, lcother); 36914aabaa7Snicm } 37014aabaa7Snicm 37114aabaa7Snicm /* Create the main pane. */ 37214aabaa7Snicm lcmain = layout_create_cell(lc); 37314aabaa7Snicm layout_set_size(lcmain, sx, mainh, 0, 0); 37414aabaa7Snicm layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes)); 37514aabaa7Snicm TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry); 37614aabaa7Snicm 37714aabaa7Snicm /* Fix cell offsets. */ 37814aabaa7Snicm layout_fix_offsets(w); 37914aabaa7Snicm layout_fix_panes(w, NULL); 38014aabaa7Snicm 38114aabaa7Snicm layout_print_cell(w->layout_root, __func__, 1); 38214aabaa7Snicm 38314aabaa7Snicm window_resize(w, lc->sx, lc->sy, -1, -1); 38414aabaa7Snicm notify_window("window-layout-changed", w); 38514aabaa7Snicm server_redraw_window(w); 38614aabaa7Snicm } 38714aabaa7Snicm 38814aabaa7Snicm static void 389af9e4c5dSnicm layout_set_main_v(struct window *w) 390af9e4c5dSnicm { 391af9e4c5dSnicm struct window_pane *wp; 39206f48543Snicm struct layout_cell *lc, *lcmain, *lcother, *lcchild; 393439fb663Snicm u_int n, mainw, otherw, sx, sy; 394c6e6a0b3Snicm char *cause; 395c6e6a0b3Snicm const char *s; 396af9e4c5dSnicm 397af9e4c5dSnicm layout_print_cell(w->layout_root, __func__, 1); 398af9e4c5dSnicm 399af9e4c5dSnicm /* Get number of panes. */ 400af9e4c5dSnicm n = window_count_panes(w); 401af9e4c5dSnicm if (n <= 1) 402af9e4c5dSnicm return; 403af9e4c5dSnicm n--; /* take off main pane */ 404af9e4c5dSnicm 405439fb663Snicm /* Find available width - take off one line for the border. */ 406439fb663Snicm sx = w->sx - 1; 407439fb663Snicm 408c6e6a0b3Snicm /* Get the main pane width. */ 409c6e6a0b3Snicm s = options_get_string(w->options, "main-pane-width"); 410c6e6a0b3Snicm mainw = args_string_percentage(s, 0, sx, sx, &cause); 411c6e6a0b3Snicm if (cause != NULL) { 412c6e6a0b3Snicm mainw = 80; 413c6e6a0b3Snicm free(cause); 414c6e6a0b3Snicm } 415c6e6a0b3Snicm 416c6e6a0b3Snicm /* Work out the other pane width. */ 417439fb663Snicm if (mainw + PANE_MINIMUM >= sx) { 418439fb663Snicm if (sx <= PANE_MINIMUM + PANE_MINIMUM) 41906f48543Snicm mainw = PANE_MINIMUM; 420af9e4c5dSnicm else 421439fb663Snicm mainw = sx - PANE_MINIMUM; 42206f48543Snicm otherw = PANE_MINIMUM; 42306f48543Snicm } else { 424c6e6a0b3Snicm s = options_get_string(w->options, "other-pane-width"); 425c6e6a0b3Snicm otherw = args_string_percentage(s, 0, sx, sx, &cause); 426c6e6a0b3Snicm if (cause != NULL || otherw == 0) { 427439fb663Snicm otherw = sx - mainw; 428c6e6a0b3Snicm free(cause); 429c6e6a0b3Snicm } else if (otherw > sx || sx - otherw < mainw) 430439fb663Snicm otherw = sx - mainw; 43106f48543Snicm else 432439fb663Snicm mainw = sx - otherw; 43306f48543Snicm } 43406f48543Snicm 43506f48543Snicm /* Work out what height is needed. */ 43606f48543Snicm sy = (n * (PANE_MINIMUM + 1)) - 1; 43706f48543Snicm if (sy < w->sy) 43806f48543Snicm sy = w->sy; 439af9e4c5dSnicm 440af9e4c5dSnicm /* Free old tree and create a new root. */ 441af9e4c5dSnicm layout_free(w); 442af9e4c5dSnicm lc = w->layout_root = layout_create_cell(NULL); 443439fb663Snicm layout_set_size(lc, mainw + otherw + 1, sy, 0, 0); 444af9e4c5dSnicm layout_make_node(lc, LAYOUT_LEFTRIGHT); 445af9e4c5dSnicm 446af9e4c5dSnicm /* Create the main pane. */ 447af9e4c5dSnicm lcmain = layout_create_cell(lc); 44806f48543Snicm layout_set_size(lcmain, mainw, sy, 0, 0); 449af9e4c5dSnicm layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes)); 450af9e4c5dSnicm TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry); 451af9e4c5dSnicm 45206f48543Snicm /* Create the other pane. */ 45306f48543Snicm lcother = layout_create_cell(lc); 45406f48543Snicm layout_set_size(lcother, otherw, sy, 0, 0); 45510d8425bSnicm if (n == 1) { 45610d8425bSnicm wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry); 45710d8425bSnicm layout_make_leaf(lcother, wp); 45810d8425bSnicm TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); 45910d8425bSnicm } else { 46006f48543Snicm layout_make_node(lcother, LAYOUT_TOPBOTTOM); 46106f48543Snicm TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); 462af9e4c5dSnicm 46306f48543Snicm /* Add the remaining panes as children. */ 46406f48543Snicm TAILQ_FOREACH(wp, &w->panes, entry) { 46506f48543Snicm if (wp == TAILQ_FIRST(&w->panes)) 466af9e4c5dSnicm continue; 46710d8425bSnicm lcchild = layout_create_cell(lcother); 46806f48543Snicm layout_set_size(lcchild, otherw, PANE_MINIMUM, 0, 0); 469af9e4c5dSnicm layout_make_leaf(lcchild, wp); 47006f48543Snicm TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry); 471af9e4c5dSnicm } 47206f48543Snicm layout_spread_cell(w, lcother); 47310d8425bSnicm } 474af9e4c5dSnicm 475af9e4c5dSnicm /* Fix cell offsets. */ 47642fbd26aSnicm layout_fix_offsets(w); 477baddd6b2Snicm layout_fix_panes(w, NULL); 478af9e4c5dSnicm 479af9e4c5dSnicm layout_print_cell(w->layout_root, __func__, 1); 480af9e4c5dSnicm 4814a8b0ea5Snicm window_resize(w, lc->sx, lc->sy, -1, -1); 4824d154873Snicm notify_window("window-layout-changed", w); 483af9e4c5dSnicm server_redraw_window(w); 484af9e4c5dSnicm } 485fcae69d1Snicm 48614aabaa7Snicm static void 48714aabaa7Snicm layout_set_main_v_mirrored(struct window *w) 48814aabaa7Snicm { 48914aabaa7Snicm struct window_pane *wp; 49014aabaa7Snicm struct layout_cell *lc, *lcmain, *lcother, *lcchild; 49114aabaa7Snicm u_int n, mainw, otherw, sx, sy; 49214aabaa7Snicm char *cause; 49314aabaa7Snicm const char *s; 49414aabaa7Snicm 49514aabaa7Snicm layout_print_cell(w->layout_root, __func__, 1); 49614aabaa7Snicm 49714aabaa7Snicm /* Get number of panes. */ 49814aabaa7Snicm n = window_count_panes(w); 49914aabaa7Snicm if (n <= 1) 50014aabaa7Snicm return; 50114aabaa7Snicm n--; /* take off main pane */ 50214aabaa7Snicm 50314aabaa7Snicm /* Find available width - take off one line for the border. */ 50414aabaa7Snicm sx = w->sx - 1; 50514aabaa7Snicm 50614aabaa7Snicm /* Get the main pane width. */ 50714aabaa7Snicm s = options_get_string(w->options, "main-pane-width"); 50814aabaa7Snicm mainw = args_string_percentage(s, 0, sx, sx, &cause); 50914aabaa7Snicm if (cause != NULL) { 51014aabaa7Snicm mainw = 80; 51114aabaa7Snicm free(cause); 51214aabaa7Snicm } 51314aabaa7Snicm 51414aabaa7Snicm /* Work out the other pane width. */ 51514aabaa7Snicm if (mainw + PANE_MINIMUM >= sx) { 51614aabaa7Snicm if (sx <= PANE_MINIMUM + PANE_MINIMUM) 51714aabaa7Snicm mainw = PANE_MINIMUM; 51814aabaa7Snicm else 51914aabaa7Snicm mainw = sx - PANE_MINIMUM; 52014aabaa7Snicm otherw = PANE_MINIMUM; 52114aabaa7Snicm } else { 52214aabaa7Snicm s = options_get_string(w->options, "other-pane-width"); 52314aabaa7Snicm otherw = args_string_percentage(s, 0, sx, sx, &cause); 52414aabaa7Snicm if (cause != NULL || otherw == 0) { 52514aabaa7Snicm otherw = sx - mainw; 52614aabaa7Snicm free(cause); 52714aabaa7Snicm } else if (otherw > sx || sx - otherw < mainw) 52814aabaa7Snicm otherw = sx - mainw; 52914aabaa7Snicm else 53014aabaa7Snicm mainw = sx - otherw; 53114aabaa7Snicm } 53214aabaa7Snicm 53314aabaa7Snicm /* Work out what height is needed. */ 53414aabaa7Snicm sy = (n * (PANE_MINIMUM + 1)) - 1; 53514aabaa7Snicm if (sy < w->sy) 53614aabaa7Snicm sy = w->sy; 53714aabaa7Snicm 53814aabaa7Snicm /* Free old tree and create a new root. */ 53914aabaa7Snicm layout_free(w); 54014aabaa7Snicm lc = w->layout_root = layout_create_cell(NULL); 54114aabaa7Snicm layout_set_size(lc, mainw + otherw + 1, sy, 0, 0); 54214aabaa7Snicm layout_make_node(lc, LAYOUT_LEFTRIGHT); 54314aabaa7Snicm 54414aabaa7Snicm /* Create the other pane. */ 54514aabaa7Snicm lcother = layout_create_cell(lc); 54614aabaa7Snicm layout_set_size(lcother, otherw, sy, 0, 0); 54714aabaa7Snicm if (n == 1) { 54814aabaa7Snicm wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry); 54914aabaa7Snicm layout_make_leaf(lcother, wp); 55014aabaa7Snicm TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); 55114aabaa7Snicm } else { 55214aabaa7Snicm layout_make_node(lcother, LAYOUT_TOPBOTTOM); 55314aabaa7Snicm TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); 55414aabaa7Snicm 55514aabaa7Snicm /* Add the remaining panes as children. */ 55614aabaa7Snicm TAILQ_FOREACH(wp, &w->panes, entry) { 55714aabaa7Snicm if (wp == TAILQ_FIRST(&w->panes)) 55814aabaa7Snicm continue; 55914aabaa7Snicm lcchild = layout_create_cell(lcother); 56014aabaa7Snicm layout_set_size(lcchild, otherw, PANE_MINIMUM, 0, 0); 56114aabaa7Snicm layout_make_leaf(lcchild, wp); 56214aabaa7Snicm TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry); 56314aabaa7Snicm } 56414aabaa7Snicm layout_spread_cell(w, lcother); 56514aabaa7Snicm } 56614aabaa7Snicm 56714aabaa7Snicm /* Create the main pane. */ 56814aabaa7Snicm lcmain = layout_create_cell(lc); 56914aabaa7Snicm layout_set_size(lcmain, mainw, sy, 0, 0); 57014aabaa7Snicm layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes)); 57114aabaa7Snicm TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry); 57214aabaa7Snicm 57314aabaa7Snicm /* Fix cell offsets. */ 57414aabaa7Snicm layout_fix_offsets(w); 57514aabaa7Snicm layout_fix_panes(w, NULL); 57614aabaa7Snicm 57714aabaa7Snicm layout_print_cell(w->layout_root, __func__, 1); 57814aabaa7Snicm 57914aabaa7Snicm window_resize(w, lc->sx, lc->sy, -1, -1); 58014aabaa7Snicm notify_window("window-layout-changed", w); 58114aabaa7Snicm server_redraw_window(w); 58214aabaa7Snicm } 58314aabaa7Snicm 584fcae69d1Snicm void 585fcae69d1Snicm layout_set_tiled(struct window *w) 586fcae69d1Snicm { 587fcae69d1Snicm struct window_pane *wp; 588fcae69d1Snicm struct layout_cell *lc, *lcrow, *lcchild; 589d4ddf7e1Snicm u_int n, width, height, used, sx, sy; 590fcae69d1Snicm u_int i, j, columns, rows; 591fcae69d1Snicm 592fcae69d1Snicm layout_print_cell(w->layout_root, __func__, 1); 593fcae69d1Snicm 594fcae69d1Snicm /* Get number of panes. */ 595fcae69d1Snicm n = window_count_panes(w); 596fcae69d1Snicm if (n <= 1) 597fcae69d1Snicm return; 598fcae69d1Snicm 599fcae69d1Snicm /* How many rows and columns are wanted? */ 600fcae69d1Snicm rows = columns = 1; 601fcae69d1Snicm while (rows * columns < n) { 602fcae69d1Snicm rows++; 603fcae69d1Snicm if (rows * columns < n) 604fcae69d1Snicm columns++; 605fcae69d1Snicm } 606fcae69d1Snicm 607fcae69d1Snicm /* What width and height should they be? */ 608b2c857acSnicm width = (w->sx - (columns - 1)) / columns; 609b2c857acSnicm if (width < PANE_MINIMUM) 610b2c857acSnicm width = PANE_MINIMUM; 611b2c857acSnicm height = (w->sy - (rows - 1)) / rows; 612b2c857acSnicm if (height < PANE_MINIMUM) 613b2c857acSnicm height = PANE_MINIMUM; 614fcae69d1Snicm 615fcae69d1Snicm /* Free old tree and create a new root. */ 616fcae69d1Snicm layout_free(w); 617fcae69d1Snicm lc = w->layout_root = layout_create_cell(NULL); 618d4ddf7e1Snicm sx = ((width + 1) * columns) - 1; 619d4ddf7e1Snicm if (sx < w->sx) 620d4ddf7e1Snicm sx = w->sx; 621d4ddf7e1Snicm sy = ((height + 1) * rows) - 1; 622d4ddf7e1Snicm if (sy < w->sy) 623d4ddf7e1Snicm sy = w->sy; 624d4ddf7e1Snicm layout_set_size(lc, sx, sy, 0, 0); 625fcae69d1Snicm layout_make_node(lc, LAYOUT_TOPBOTTOM); 626fcae69d1Snicm 627fcae69d1Snicm /* Create a grid of the cells. */ 628fcae69d1Snicm wp = TAILQ_FIRST(&w->panes); 629fcae69d1Snicm for (j = 0; j < rows; j++) { 630fcae69d1Snicm /* If this is the last cell, all done. */ 631fcae69d1Snicm if (wp == NULL) 632fcae69d1Snicm break; 633fcae69d1Snicm 634fcae69d1Snicm /* Create the new row. */ 635fcae69d1Snicm lcrow = layout_create_cell(lc); 636b2c857acSnicm layout_set_size(lcrow, w->sx, height, 0, 0); 637fcae69d1Snicm TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry); 638fcae69d1Snicm 639fcae69d1Snicm /* If only one column, just use the row directly. */ 640e09b5663Snicm if (n - (j * columns) == 1 || columns == 1) { 641fcae69d1Snicm layout_make_leaf(lcrow, wp); 642fcae69d1Snicm wp = TAILQ_NEXT(wp, entry); 643fcae69d1Snicm continue; 644fcae69d1Snicm } 645fcae69d1Snicm 646fcae69d1Snicm /* Add in the columns. */ 647fcae69d1Snicm layout_make_node(lcrow, LAYOUT_LEFTRIGHT); 648fcae69d1Snicm for (i = 0; i < columns; i++) { 649fcae69d1Snicm /* Create and add a pane cell. */ 650fcae69d1Snicm lcchild = layout_create_cell(lcrow); 651b2c857acSnicm layout_set_size(lcchild, width, height, 0, 0); 652fcae69d1Snicm layout_make_leaf(lcchild, wp); 653fcae69d1Snicm TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry); 654fcae69d1Snicm 655fcae69d1Snicm /* Move to the next cell. */ 656fcae69d1Snicm if ((wp = TAILQ_NEXT(wp, entry)) == NULL) 657fcae69d1Snicm break; 658fcae69d1Snicm } 659fcae69d1Snicm 660fcae69d1Snicm /* 661fcae69d1Snicm * Adjust the row and columns to fit the full width if 662fcae69d1Snicm * necessary. 663fcae69d1Snicm */ 664fcae69d1Snicm if (i == columns) 665fcae69d1Snicm i--; 666b2c857acSnicm used = ((i + 1) * (width + 1)) - 1; 667fcae69d1Snicm if (w->sx <= used) 668fcae69d1Snicm continue; 669fcae69d1Snicm lcchild = TAILQ_LAST(&lcrow->cells, layout_cells); 67007b91187Snicm layout_resize_adjust(w, lcchild, LAYOUT_LEFTRIGHT, 67107b91187Snicm w->sx - used); 672fcae69d1Snicm } 673fcae69d1Snicm 674fcae69d1Snicm /* Adjust the last row height to fit if necessary. */ 675b2c857acSnicm used = (rows * height) + rows - 1; 676fcae69d1Snicm if (w->sy > used) { 677fcae69d1Snicm lcrow = TAILQ_LAST(&lc->cells, layout_cells); 67807b91187Snicm layout_resize_adjust(w, lcrow, LAYOUT_TOPBOTTOM, 67907b91187Snicm w->sy - used); 680fcae69d1Snicm } 681fcae69d1Snicm 682fcae69d1Snicm /* Fix cell offsets. */ 68342fbd26aSnicm layout_fix_offsets(w); 684baddd6b2Snicm layout_fix_panes(w, NULL); 685fcae69d1Snicm 686fcae69d1Snicm layout_print_cell(w->layout_root, __func__, 1); 687fcae69d1Snicm 6884a8b0ea5Snicm window_resize(w, lc->sx, lc->sy, -1, -1); 6894d154873Snicm notify_window("window-layout-changed", w); 690fcae69d1Snicm server_redraw_window(w); 691fcae69d1Snicm } 692