15494e770Schristos /* $OpenBSD$ */ 2698d5317Sjmmv 3698d5317Sjmmv /* 4ed4e6cd4Schristos * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com> 5698d5317Sjmmv * 6698d5317Sjmmv * Permission to use, copy, modify, and distribute this software for any 7698d5317Sjmmv * purpose with or without fee is hereby granted, provided that the above 8698d5317Sjmmv * copyright notice and this permission notice appear in all copies. 9698d5317Sjmmv * 10698d5317Sjmmv * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11698d5317Sjmmv * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12698d5317Sjmmv * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13698d5317Sjmmv * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14698d5317Sjmmv * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15698d5317Sjmmv * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16698d5317Sjmmv * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17698d5317Sjmmv */ 18698d5317Sjmmv 19698d5317Sjmmv #include <sys/types.h> 20698d5317Sjmmv 219fb66d81Schristos #include <stdlib.h> 22698d5317Sjmmv #include <string.h> 23698d5317Sjmmv 24698d5317Sjmmv #include "tmux.h" 25698d5317Sjmmv 26698d5317Sjmmv /* 275494e770Schristos * Set window layouts - predefined methods to arrange windows. These are 285494e770Schristos * one-off and generate a layout tree. 29698d5317Sjmmv */ 30698d5317Sjmmv 314e179ddaSchristos static void layout_set_even_h(struct window *); 324e179ddaSchristos static void layout_set_even_v(struct window *); 334e179ddaSchristos static void layout_set_main_h(struct window *); 34*f8cf1a91Swiz static void layout_set_main_h_mirrored(struct window *); 354e179ddaSchristos static void layout_set_main_v(struct window *); 36*f8cf1a91Swiz static void layout_set_main_v_mirrored(struct window *); 374e179ddaSchristos static void layout_set_tiled(struct window *); 38698d5317Sjmmv 394e179ddaSchristos static const struct { 40698d5317Sjmmv const char *name; 41698d5317Sjmmv void (*arrange)(struct window *); 42698d5317Sjmmv } layout_sets[] = { 43698d5317Sjmmv { "even-horizontal", layout_set_even_h }, 44698d5317Sjmmv { "even-vertical", layout_set_even_v }, 45698d5317Sjmmv { "main-horizontal", layout_set_main_h }, 46*f8cf1a91Swiz { "main-horizontal-mirrored", layout_set_main_h_mirrored }, 47698d5317Sjmmv { "main-vertical", layout_set_main_v }, 48*f8cf1a91Swiz { "main-vertical-mirrored", layout_set_main_v_mirrored }, 49698d5317Sjmmv { "tiled", layout_set_tiled }, 50698d5317Sjmmv }; 51698d5317Sjmmv 52698d5317Sjmmv int 53698d5317Sjmmv layout_set_lookup(const char *name) 54698d5317Sjmmv { 55698d5317Sjmmv u_int i; 56698d5317Sjmmv int matched = -1; 57698d5317Sjmmv 58698d5317Sjmmv for (i = 0; i < nitems(layout_sets); i++) { 59*f8cf1a91Swiz if (strcmp(layout_sets[i].name, name) == 0) 60*f8cf1a91Swiz return (i); 61*f8cf1a91Swiz } 62*f8cf1a91Swiz for (i = 0; i < nitems(layout_sets); i++) { 63698d5317Sjmmv if (strncmp(layout_sets[i].name, name, strlen(name)) == 0) { 64698d5317Sjmmv if (matched != -1) /* ambiguous */ 65698d5317Sjmmv return (-1); 66698d5317Sjmmv matched = i; 67698d5317Sjmmv } 68698d5317Sjmmv } 69698d5317Sjmmv 70698d5317Sjmmv return (matched); 71698d5317Sjmmv } 72698d5317Sjmmv 73698d5317Sjmmv u_int 74698d5317Sjmmv layout_set_select(struct window *w, u_int layout) 75698d5317Sjmmv { 76698d5317Sjmmv if (layout > nitems(layout_sets) - 1) 77698d5317Sjmmv layout = nitems(layout_sets) - 1; 78698d5317Sjmmv 79698d5317Sjmmv if (layout_sets[layout].arrange != NULL) 80698d5317Sjmmv layout_sets[layout].arrange(w); 81698d5317Sjmmv 82698d5317Sjmmv w->lastlayout = layout; 83698d5317Sjmmv return (layout); 84698d5317Sjmmv } 85698d5317Sjmmv 86698d5317Sjmmv u_int 87698d5317Sjmmv layout_set_next(struct window *w) 88698d5317Sjmmv { 89698d5317Sjmmv u_int layout; 90698d5317Sjmmv 91698d5317Sjmmv if (w->lastlayout == -1) 92698d5317Sjmmv layout = 0; 93698d5317Sjmmv else { 94698d5317Sjmmv layout = w->lastlayout + 1; 95698d5317Sjmmv if (layout > nitems(layout_sets) - 1) 96698d5317Sjmmv layout = 0; 97698d5317Sjmmv } 98698d5317Sjmmv 99698d5317Sjmmv if (layout_sets[layout].arrange != NULL) 100698d5317Sjmmv layout_sets[layout].arrange(w); 101698d5317Sjmmv w->lastlayout = layout; 102698d5317Sjmmv return (layout); 103698d5317Sjmmv } 104698d5317Sjmmv 105698d5317Sjmmv u_int 106698d5317Sjmmv layout_set_previous(struct window *w) 107698d5317Sjmmv { 108698d5317Sjmmv u_int layout; 109698d5317Sjmmv 110698d5317Sjmmv if (w->lastlayout == -1) 111698d5317Sjmmv layout = nitems(layout_sets) - 1; 112698d5317Sjmmv else { 113698d5317Sjmmv layout = w->lastlayout; 114698d5317Sjmmv if (layout == 0) 115698d5317Sjmmv layout = nitems(layout_sets) - 1; 116698d5317Sjmmv else 117698d5317Sjmmv layout--; 118698d5317Sjmmv } 119698d5317Sjmmv 120698d5317Sjmmv if (layout_sets[layout].arrange != NULL) 121698d5317Sjmmv layout_sets[layout].arrange(w); 122698d5317Sjmmv w->lastlayout = layout; 123698d5317Sjmmv return (layout); 124698d5317Sjmmv } 125698d5317Sjmmv 1264e179ddaSchristos static void 1278f3b9483Schristos layout_set_even(struct window *w, enum layout_type type) 128698d5317Sjmmv { 129698d5317Sjmmv struct window_pane *wp; 130698d5317Sjmmv struct layout_cell *lc, *lcnew; 131ef36e747Schristos u_int n, sx, sy; 132698d5317Sjmmv 133698d5317Sjmmv layout_print_cell(w->layout_root, __func__, 1); 134698d5317Sjmmv 135698d5317Sjmmv /* Get number of panes. */ 136698d5317Sjmmv n = window_count_panes(w); 137698d5317Sjmmv if (n <= 1) 138698d5317Sjmmv return; 139698d5317Sjmmv 140698d5317Sjmmv /* Free the old root and construct a new. */ 141698d5317Sjmmv layout_free(w); 142698d5317Sjmmv lc = w->layout_root = layout_create_cell(NULL); 143ef36e747Schristos if (type == LAYOUT_LEFTRIGHT) { 144ef36e747Schristos sx = (n * (PANE_MINIMUM + 1)) - 1; 145ef36e747Schristos if (sx < w->sx) 146ef36e747Schristos sx = w->sx; 147ef36e747Schristos sy = w->sy; 148ef36e747Schristos } else { 149ef36e747Schristos sy = (n * (PANE_MINIMUM + 1)) - 1; 150ef36e747Schristos if (sy < w->sy) 151ef36e747Schristos sy = w->sy; 152ef36e747Schristos sx = w->sx; 153ef36e747Schristos } 154ef36e747Schristos layout_set_size(lc, sx, sy, 0, 0); 1558f3b9483Schristos layout_make_node(lc, type); 156698d5317Sjmmv 157698d5317Sjmmv /* Build new leaf cells. */ 158698d5317Sjmmv TAILQ_FOREACH(wp, &w->panes, entry) { 159698d5317Sjmmv lcnew = layout_create_cell(lc); 160698d5317Sjmmv layout_make_leaf(lcnew, wp); 1618f3b9483Schristos lcnew->sx = w->sx; 1628f3b9483Schristos lcnew->sy = w->sy; 163698d5317Sjmmv TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry); 164698d5317Sjmmv } 165698d5317Sjmmv 1668f3b9483Schristos /* Spread out cells. */ 1678f3b9483Schristos layout_spread_cell(w, lc); 168698d5317Sjmmv 169698d5317Sjmmv /* Fix cell offsets. */ 1706483eba0Schristos layout_fix_offsets(w); 1719fb66d81Schristos layout_fix_panes(w, NULL); 172698d5317Sjmmv 173698d5317Sjmmv layout_print_cell(w->layout_root, __func__, 1); 174698d5317Sjmmv 175aa83ff61Schristos window_resize(w, lc->sx, lc->sy, -1, -1); 176c9ad075bSchristos notify_window("window-layout-changed", w); 177698d5317Sjmmv server_redraw_window(w); 178698d5317Sjmmv } 179698d5317Sjmmv 1804e179ddaSchristos static void 1818f3b9483Schristos layout_set_even_h(struct window *w) 1828f3b9483Schristos { 1838f3b9483Schristos layout_set_even(w, LAYOUT_LEFTRIGHT); 1848f3b9483Schristos } 1858f3b9483Schristos 1868f3b9483Schristos static void 187698d5317Sjmmv layout_set_even_v(struct window *w) 188698d5317Sjmmv { 1898f3b9483Schristos layout_set_even(w, LAYOUT_TOPBOTTOM); 190698d5317Sjmmv } 191698d5317Sjmmv 1924e179ddaSchristos static void 193698d5317Sjmmv layout_set_main_h(struct window *w) 194698d5317Sjmmv { 195698d5317Sjmmv struct window_pane *wp; 196ef36e747Schristos struct layout_cell *lc, *lcmain, *lcother, *lcchild; 1976483eba0Schristos u_int n, mainh, otherh, sx, sy; 1989fb66d81Schristos char *cause; 1999fb66d81Schristos const char *s; 200698d5317Sjmmv 201698d5317Sjmmv layout_print_cell(w->layout_root, __func__, 1); 202698d5317Sjmmv 203698d5317Sjmmv /* Get number of panes. */ 204698d5317Sjmmv n = window_count_panes(w); 205698d5317Sjmmv if (n <= 1) 206698d5317Sjmmv return; 207698d5317Sjmmv n--; /* take off main pane */ 208698d5317Sjmmv 2096483eba0Schristos /* Find available height - take off one line for the border. */ 2106483eba0Schristos sy = w->sy - 1; 2116483eba0Schristos 2129fb66d81Schristos /* Get the main pane height. */ 2139fb66d81Schristos s = options_get_string(w->options, "main-pane-height"); 2149fb66d81Schristos mainh = args_string_percentage(s, 0, sy, sy, &cause); 2159fb66d81Schristos if (cause != NULL) { 2169fb66d81Schristos mainh = 24; 2179fb66d81Schristos free(cause); 2189fb66d81Schristos } 2199fb66d81Schristos 2209fb66d81Schristos /* Work out the other pane height. */ 2216483eba0Schristos if (mainh + PANE_MINIMUM >= sy) { 2226483eba0Schristos if (sy <= PANE_MINIMUM + PANE_MINIMUM) 223ef36e747Schristos mainh = PANE_MINIMUM; 224698d5317Sjmmv else 2256483eba0Schristos mainh = sy - PANE_MINIMUM; 226ef36e747Schristos otherh = PANE_MINIMUM; 227ef36e747Schristos } else { 2289fb66d81Schristos s = options_get_string(w->options, "other-pane-height"); 2299fb66d81Schristos otherh = args_string_percentage(s, 0, sy, sy, &cause); 2309fb66d81Schristos if (cause != NULL || otherh == 0) { 2316483eba0Schristos otherh = sy - mainh; 2329fb66d81Schristos free(cause); 2339fb66d81Schristos } else if (otherh > sy || sy - otherh < mainh) 2346483eba0Schristos otherh = sy - mainh; 235ef36e747Schristos else 2366483eba0Schristos mainh = sy - otherh; 237ef36e747Schristos } 238ef36e747Schristos 239ef36e747Schristos /* Work out what width is needed. */ 240ef36e747Schristos sx = (n * (PANE_MINIMUM + 1)) - 1; 241ef36e747Schristos if (sx < w->sx) 242ef36e747Schristos sx = w->sx; 243698d5317Sjmmv 244698d5317Sjmmv /* Free old tree and create a new root. */ 245698d5317Sjmmv layout_free(w); 246698d5317Sjmmv lc = w->layout_root = layout_create_cell(NULL); 2476483eba0Schristos layout_set_size(lc, sx, mainh + otherh + 1, 0, 0); 248698d5317Sjmmv layout_make_node(lc, LAYOUT_TOPBOTTOM); 249698d5317Sjmmv 250698d5317Sjmmv /* Create the main pane. */ 251698d5317Sjmmv lcmain = layout_create_cell(lc); 252ef36e747Schristos layout_set_size(lcmain, sx, mainh, 0, 0); 253698d5317Sjmmv layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes)); 254698d5317Sjmmv TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry); 255698d5317Sjmmv 256ef36e747Schristos /* Create the other pane. */ 257ef36e747Schristos lcother = layout_create_cell(lc); 258ef36e747Schristos layout_set_size(lcother, sx, otherh, 0, 0); 259ef36e747Schristos if (n == 1) { 260698d5317Sjmmv wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry); 261ef36e747Schristos layout_make_leaf(lcother, wp); 262ef36e747Schristos TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); 263ef36e747Schristos } else { 264ef36e747Schristos layout_make_node(lcother, LAYOUT_LEFTRIGHT); 265ef36e747Schristos TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); 266698d5317Sjmmv 267ef36e747Schristos /* Add the remaining panes as children. */ 268ef36e747Schristos TAILQ_FOREACH(wp, &w->panes, entry) { 269ef36e747Schristos if (wp == TAILQ_FIRST(&w->panes)) 270698d5317Sjmmv continue; 271ef36e747Schristos lcchild = layout_create_cell(lcother); 272ef36e747Schristos layout_set_size(lcchild, PANE_MINIMUM, otherh, 0, 0); 273698d5317Sjmmv layout_make_leaf(lcchild, wp); 274ef36e747Schristos TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry); 275698d5317Sjmmv } 276ef36e747Schristos layout_spread_cell(w, lcother); 277698d5317Sjmmv } 278698d5317Sjmmv 279698d5317Sjmmv /* Fix cell offsets. */ 2806483eba0Schristos layout_fix_offsets(w); 2819fb66d81Schristos layout_fix_panes(w, NULL); 282698d5317Sjmmv 283698d5317Sjmmv layout_print_cell(w->layout_root, __func__, 1); 284698d5317Sjmmv 285aa83ff61Schristos window_resize(w, lc->sx, lc->sy, -1, -1); 286c9ad075bSchristos notify_window("window-layout-changed", w); 287698d5317Sjmmv server_redraw_window(w); 288698d5317Sjmmv } 289698d5317Sjmmv 2904e179ddaSchristos static void 291*f8cf1a91Swiz layout_set_main_h_mirrored(struct window *w) 292*f8cf1a91Swiz { 293*f8cf1a91Swiz struct window_pane *wp; 294*f8cf1a91Swiz struct layout_cell *lc, *lcmain, *lcother, *lcchild; 295*f8cf1a91Swiz u_int n, mainh, otherh, sx, sy; 296*f8cf1a91Swiz char *cause; 297*f8cf1a91Swiz const char *s; 298*f8cf1a91Swiz 299*f8cf1a91Swiz layout_print_cell(w->layout_root, __func__, 1); 300*f8cf1a91Swiz 301*f8cf1a91Swiz /* Get number of panes. */ 302*f8cf1a91Swiz n = window_count_panes(w); 303*f8cf1a91Swiz if (n <= 1) 304*f8cf1a91Swiz return; 305*f8cf1a91Swiz n--; /* take off main pane */ 306*f8cf1a91Swiz 307*f8cf1a91Swiz /* Find available height - take off one line for the border. */ 308*f8cf1a91Swiz sy = w->sy - 1; 309*f8cf1a91Swiz 310*f8cf1a91Swiz /* Get the main pane height. */ 311*f8cf1a91Swiz s = options_get_string(w->options, "main-pane-height"); 312*f8cf1a91Swiz mainh = args_string_percentage(s, 0, sy, sy, &cause); 313*f8cf1a91Swiz if (cause != NULL) { 314*f8cf1a91Swiz mainh = 24; 315*f8cf1a91Swiz free(cause); 316*f8cf1a91Swiz } 317*f8cf1a91Swiz 318*f8cf1a91Swiz /* Work out the other pane height. */ 319*f8cf1a91Swiz if (mainh + PANE_MINIMUM >= sy) { 320*f8cf1a91Swiz if (sy <= PANE_MINIMUM + PANE_MINIMUM) 321*f8cf1a91Swiz mainh = PANE_MINIMUM; 322*f8cf1a91Swiz else 323*f8cf1a91Swiz mainh = sy - PANE_MINIMUM; 324*f8cf1a91Swiz otherh = PANE_MINIMUM; 325*f8cf1a91Swiz } else { 326*f8cf1a91Swiz s = options_get_string(w->options, "other-pane-height"); 327*f8cf1a91Swiz otherh = args_string_percentage(s, 0, sy, sy, &cause); 328*f8cf1a91Swiz if (cause != NULL || otherh == 0) { 329*f8cf1a91Swiz otherh = sy - mainh; 330*f8cf1a91Swiz free(cause); 331*f8cf1a91Swiz } else if (otherh > sy || sy - otherh < mainh) 332*f8cf1a91Swiz otherh = sy - mainh; 333*f8cf1a91Swiz else 334*f8cf1a91Swiz mainh = sy - otherh; 335*f8cf1a91Swiz } 336*f8cf1a91Swiz 337*f8cf1a91Swiz /* Work out what width is needed. */ 338*f8cf1a91Swiz sx = (n * (PANE_MINIMUM + 1)) - 1; 339*f8cf1a91Swiz if (sx < w->sx) 340*f8cf1a91Swiz sx = w->sx; 341*f8cf1a91Swiz 342*f8cf1a91Swiz /* Free old tree and create a new root. */ 343*f8cf1a91Swiz layout_free(w); 344*f8cf1a91Swiz lc = w->layout_root = layout_create_cell(NULL); 345*f8cf1a91Swiz layout_set_size(lc, sx, mainh + otherh + 1, 0, 0); 346*f8cf1a91Swiz layout_make_node(lc, LAYOUT_TOPBOTTOM); 347*f8cf1a91Swiz 348*f8cf1a91Swiz /* Create the other pane. */ 349*f8cf1a91Swiz lcother = layout_create_cell(lc); 350*f8cf1a91Swiz layout_set_size(lcother, sx, otherh, 0, 0); 351*f8cf1a91Swiz if (n == 1) { 352*f8cf1a91Swiz wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry); 353*f8cf1a91Swiz layout_make_leaf(lcother, wp); 354*f8cf1a91Swiz TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); 355*f8cf1a91Swiz } else { 356*f8cf1a91Swiz layout_make_node(lcother, LAYOUT_LEFTRIGHT); 357*f8cf1a91Swiz TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); 358*f8cf1a91Swiz 359*f8cf1a91Swiz /* Add the remaining panes as children. */ 360*f8cf1a91Swiz TAILQ_FOREACH(wp, &w->panes, entry) { 361*f8cf1a91Swiz if (wp == TAILQ_FIRST(&w->panes)) 362*f8cf1a91Swiz continue; 363*f8cf1a91Swiz lcchild = layout_create_cell(lcother); 364*f8cf1a91Swiz layout_set_size(lcchild, PANE_MINIMUM, otherh, 0, 0); 365*f8cf1a91Swiz layout_make_leaf(lcchild, wp); 366*f8cf1a91Swiz TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry); 367*f8cf1a91Swiz } 368*f8cf1a91Swiz layout_spread_cell(w, lcother); 369*f8cf1a91Swiz } 370*f8cf1a91Swiz 371*f8cf1a91Swiz /* Create the main pane. */ 372*f8cf1a91Swiz lcmain = layout_create_cell(lc); 373*f8cf1a91Swiz layout_set_size(lcmain, sx, mainh, 0, 0); 374*f8cf1a91Swiz layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes)); 375*f8cf1a91Swiz TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry); 376*f8cf1a91Swiz 377*f8cf1a91Swiz /* Fix cell offsets. */ 378*f8cf1a91Swiz layout_fix_offsets(w); 379*f8cf1a91Swiz layout_fix_panes(w, NULL); 380*f8cf1a91Swiz 381*f8cf1a91Swiz layout_print_cell(w->layout_root, __func__, 1); 382*f8cf1a91Swiz 383*f8cf1a91Swiz window_resize(w, lc->sx, lc->sy, -1, -1); 384*f8cf1a91Swiz notify_window("window-layout-changed", w); 385*f8cf1a91Swiz server_redraw_window(w); 386*f8cf1a91Swiz } 387*f8cf1a91Swiz 388*f8cf1a91Swiz static void 389698d5317Sjmmv layout_set_main_v(struct window *w) 390698d5317Sjmmv { 391698d5317Sjmmv struct window_pane *wp; 392ef36e747Schristos struct layout_cell *lc, *lcmain, *lcother, *lcchild; 3936483eba0Schristos u_int n, mainw, otherw, sx, sy; 3949fb66d81Schristos char *cause; 3959fb66d81Schristos const char *s; 396698d5317Sjmmv 397698d5317Sjmmv layout_print_cell(w->layout_root, __func__, 1); 398698d5317Sjmmv 399698d5317Sjmmv /* Get number of panes. */ 400698d5317Sjmmv n = window_count_panes(w); 401698d5317Sjmmv if (n <= 1) 402698d5317Sjmmv return; 403698d5317Sjmmv n--; /* take off main pane */ 404698d5317Sjmmv 4056483eba0Schristos /* Find available width - take off one line for the border. */ 4066483eba0Schristos sx = w->sx - 1; 4076483eba0Schristos 4089fb66d81Schristos /* Get the main pane width. */ 4099fb66d81Schristos s = options_get_string(w->options, "main-pane-width"); 4109fb66d81Schristos mainw = args_string_percentage(s, 0, sx, sx, &cause); 4119fb66d81Schristos if (cause != NULL) { 4129fb66d81Schristos mainw = 80; 4139fb66d81Schristos free(cause); 4149fb66d81Schristos } 4159fb66d81Schristos 4169fb66d81Schristos /* Work out the other pane width. */ 4176483eba0Schristos if (mainw + PANE_MINIMUM >= sx) { 4186483eba0Schristos if (sx <= PANE_MINIMUM + PANE_MINIMUM) 419ef36e747Schristos mainw = PANE_MINIMUM; 420698d5317Sjmmv else 4216483eba0Schristos mainw = sx - PANE_MINIMUM; 422ef36e747Schristos otherw = PANE_MINIMUM; 423ef36e747Schristos } else { 4249fb66d81Schristos s = options_get_string(w->options, "other-pane-width"); 4259fb66d81Schristos otherw = args_string_percentage(s, 0, sx, sx, &cause); 4269fb66d81Schristos if (cause != NULL || otherw == 0) { 4276483eba0Schristos otherw = sx - mainw; 4289fb66d81Schristos free(cause); 4299fb66d81Schristos } else if (otherw > sx || sx - otherw < mainw) 4306483eba0Schristos otherw = sx - mainw; 431ef36e747Schristos else 4326483eba0Schristos mainw = sx - otherw; 433ef36e747Schristos } 434ef36e747Schristos 435ef36e747Schristos /* Work out what height is needed. */ 436ef36e747Schristos sy = (n * (PANE_MINIMUM + 1)) - 1; 437ef36e747Schristos if (sy < w->sy) 438ef36e747Schristos sy = w->sy; 439698d5317Sjmmv 440698d5317Sjmmv /* Free old tree and create a new root. */ 441698d5317Sjmmv layout_free(w); 442698d5317Sjmmv lc = w->layout_root = layout_create_cell(NULL); 4436483eba0Schristos layout_set_size(lc, mainw + otherw + 1, sy, 0, 0); 444698d5317Sjmmv layout_make_node(lc, LAYOUT_LEFTRIGHT); 445698d5317Sjmmv 446698d5317Sjmmv /* Create the main pane. */ 447698d5317Sjmmv lcmain = layout_create_cell(lc); 448ef36e747Schristos layout_set_size(lcmain, mainw, sy, 0, 0); 449698d5317Sjmmv layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes)); 450698d5317Sjmmv TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry); 451698d5317Sjmmv 452ef36e747Schristos /* Create the other pane. */ 453ef36e747Schristos lcother = layout_create_cell(lc); 454ef36e747Schristos layout_set_size(lcother, otherw, sy, 0, 0); 455ef36e747Schristos if (n == 1) { 456698d5317Sjmmv wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry); 457ef36e747Schristos layout_make_leaf(lcother, wp); 458ef36e747Schristos TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); 459ef36e747Schristos } else { 460ef36e747Schristos layout_make_node(lcother, LAYOUT_TOPBOTTOM); 461ef36e747Schristos TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); 462698d5317Sjmmv 463ef36e747Schristos /* Add the remaining panes as children. */ 464ef36e747Schristos TAILQ_FOREACH(wp, &w->panes, entry) { 465ef36e747Schristos if (wp == TAILQ_FIRST(&w->panes)) 466698d5317Sjmmv continue; 467ef36e747Schristos lcchild = layout_create_cell(lcother); 468ef36e747Schristos layout_set_size(lcchild, otherw, PANE_MINIMUM, 0, 0); 469698d5317Sjmmv layout_make_leaf(lcchild, wp); 470ef36e747Schristos TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry); 471698d5317Sjmmv } 472ef36e747Schristos layout_spread_cell(w, lcother); 473698d5317Sjmmv } 474698d5317Sjmmv 475698d5317Sjmmv /* Fix cell offsets. */ 4766483eba0Schristos layout_fix_offsets(w); 4779fb66d81Schristos layout_fix_panes(w, NULL); 478698d5317Sjmmv 479698d5317Sjmmv layout_print_cell(w->layout_root, __func__, 1); 480698d5317Sjmmv 481aa83ff61Schristos window_resize(w, lc->sx, lc->sy, -1, -1); 482c9ad075bSchristos notify_window("window-layout-changed", w); 483698d5317Sjmmv server_redraw_window(w); 484698d5317Sjmmv } 485698d5317Sjmmv 486*f8cf1a91Swiz static void 487*f8cf1a91Swiz layout_set_main_v_mirrored(struct window *w) 488*f8cf1a91Swiz { 489*f8cf1a91Swiz struct window_pane *wp; 490*f8cf1a91Swiz struct layout_cell *lc, *lcmain, *lcother, *lcchild; 491*f8cf1a91Swiz u_int n, mainw, otherw, sx, sy; 492*f8cf1a91Swiz char *cause; 493*f8cf1a91Swiz const char *s; 494*f8cf1a91Swiz 495*f8cf1a91Swiz layout_print_cell(w->layout_root, __func__, 1); 496*f8cf1a91Swiz 497*f8cf1a91Swiz /* Get number of panes. */ 498*f8cf1a91Swiz n = window_count_panes(w); 499*f8cf1a91Swiz if (n <= 1) 500*f8cf1a91Swiz return; 501*f8cf1a91Swiz n--; /* take off main pane */ 502*f8cf1a91Swiz 503*f8cf1a91Swiz /* Find available width - take off one line for the border. */ 504*f8cf1a91Swiz sx = w->sx - 1; 505*f8cf1a91Swiz 506*f8cf1a91Swiz /* Get the main pane width. */ 507*f8cf1a91Swiz s = options_get_string(w->options, "main-pane-width"); 508*f8cf1a91Swiz mainw = args_string_percentage(s, 0, sx, sx, &cause); 509*f8cf1a91Swiz if (cause != NULL) { 510*f8cf1a91Swiz mainw = 80; 511*f8cf1a91Swiz free(cause); 512*f8cf1a91Swiz } 513*f8cf1a91Swiz 514*f8cf1a91Swiz /* Work out the other pane width. */ 515*f8cf1a91Swiz if (mainw + PANE_MINIMUM >= sx) { 516*f8cf1a91Swiz if (sx <= PANE_MINIMUM + PANE_MINIMUM) 517*f8cf1a91Swiz mainw = PANE_MINIMUM; 518*f8cf1a91Swiz else 519*f8cf1a91Swiz mainw = sx - PANE_MINIMUM; 520*f8cf1a91Swiz otherw = PANE_MINIMUM; 521*f8cf1a91Swiz } else { 522*f8cf1a91Swiz s = options_get_string(w->options, "other-pane-width"); 523*f8cf1a91Swiz otherw = args_string_percentage(s, 0, sx, sx, &cause); 524*f8cf1a91Swiz if (cause != NULL || otherw == 0) { 525*f8cf1a91Swiz otherw = sx - mainw; 526*f8cf1a91Swiz free(cause); 527*f8cf1a91Swiz } else if (otherw > sx || sx - otherw < mainw) 528*f8cf1a91Swiz otherw = sx - mainw; 529*f8cf1a91Swiz else 530*f8cf1a91Swiz mainw = sx - otherw; 531*f8cf1a91Swiz } 532*f8cf1a91Swiz 533*f8cf1a91Swiz /* Work out what height is needed. */ 534*f8cf1a91Swiz sy = (n * (PANE_MINIMUM + 1)) - 1; 535*f8cf1a91Swiz if (sy < w->sy) 536*f8cf1a91Swiz sy = w->sy; 537*f8cf1a91Swiz 538*f8cf1a91Swiz /* Free old tree and create a new root. */ 539*f8cf1a91Swiz layout_free(w); 540*f8cf1a91Swiz lc = w->layout_root = layout_create_cell(NULL); 541*f8cf1a91Swiz layout_set_size(lc, mainw + otherw + 1, sy, 0, 0); 542*f8cf1a91Swiz layout_make_node(lc, LAYOUT_LEFTRIGHT); 543*f8cf1a91Swiz 544*f8cf1a91Swiz /* Create the other pane. */ 545*f8cf1a91Swiz lcother = layout_create_cell(lc); 546*f8cf1a91Swiz layout_set_size(lcother, otherw, sy, 0, 0); 547*f8cf1a91Swiz if (n == 1) { 548*f8cf1a91Swiz wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry); 549*f8cf1a91Swiz layout_make_leaf(lcother, wp); 550*f8cf1a91Swiz TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); 551*f8cf1a91Swiz } else { 552*f8cf1a91Swiz layout_make_node(lcother, LAYOUT_TOPBOTTOM); 553*f8cf1a91Swiz TAILQ_INSERT_TAIL(&lc->cells, lcother, entry); 554*f8cf1a91Swiz 555*f8cf1a91Swiz /* Add the remaining panes as children. */ 556*f8cf1a91Swiz TAILQ_FOREACH(wp, &w->panes, entry) { 557*f8cf1a91Swiz if (wp == TAILQ_FIRST(&w->panes)) 558*f8cf1a91Swiz continue; 559*f8cf1a91Swiz lcchild = layout_create_cell(lcother); 560*f8cf1a91Swiz layout_set_size(lcchild, otherw, PANE_MINIMUM, 0, 0); 561*f8cf1a91Swiz layout_make_leaf(lcchild, wp); 562*f8cf1a91Swiz TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry); 563*f8cf1a91Swiz } 564*f8cf1a91Swiz layout_spread_cell(w, lcother); 565*f8cf1a91Swiz } 566*f8cf1a91Swiz 567*f8cf1a91Swiz /* Create the main pane. */ 568*f8cf1a91Swiz lcmain = layout_create_cell(lc); 569*f8cf1a91Swiz layout_set_size(lcmain, mainw, sy, 0, 0); 570*f8cf1a91Swiz layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes)); 571*f8cf1a91Swiz TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry); 572*f8cf1a91Swiz 573*f8cf1a91Swiz /* Fix cell offsets. */ 574*f8cf1a91Swiz layout_fix_offsets(w); 575*f8cf1a91Swiz layout_fix_panes(w, NULL); 576*f8cf1a91Swiz 577*f8cf1a91Swiz layout_print_cell(w->layout_root, __func__, 1); 578*f8cf1a91Swiz 579*f8cf1a91Swiz window_resize(w, lc->sx, lc->sy, -1, -1); 580*f8cf1a91Swiz notify_window("window-layout-changed", w); 581*f8cf1a91Swiz server_redraw_window(w); 582*f8cf1a91Swiz } 583*f8cf1a91Swiz 584698d5317Sjmmv void 585698d5317Sjmmv layout_set_tiled(struct window *w) 586698d5317Sjmmv { 587698d5317Sjmmv struct window_pane *wp; 588698d5317Sjmmv struct layout_cell *lc, *lcrow, *lcchild; 589ef36e747Schristos u_int n, width, height, used, sx, sy; 590698d5317Sjmmv u_int i, j, columns, rows; 591698d5317Sjmmv 592698d5317Sjmmv layout_print_cell(w->layout_root, __func__, 1); 593698d5317Sjmmv 594698d5317Sjmmv /* Get number of panes. */ 595698d5317Sjmmv n = window_count_panes(w); 596698d5317Sjmmv if (n <= 1) 597698d5317Sjmmv return; 598698d5317Sjmmv 599698d5317Sjmmv /* How many rows and columns are wanted? */ 600698d5317Sjmmv rows = columns = 1; 601698d5317Sjmmv while (rows * columns < n) { 602698d5317Sjmmv rows++; 603698d5317Sjmmv if (rows * columns < n) 604698d5317Sjmmv columns++; 605698d5317Sjmmv } 606698d5317Sjmmv 607698d5317Sjmmv /* What width and height should they be? */ 608698d5317Sjmmv width = (w->sx - (columns - 1)) / columns; 609698d5317Sjmmv if (width < PANE_MINIMUM) 610698d5317Sjmmv width = PANE_MINIMUM; 611698d5317Sjmmv height = (w->sy - (rows - 1)) / rows; 612698d5317Sjmmv if (height < PANE_MINIMUM) 613698d5317Sjmmv height = PANE_MINIMUM; 614698d5317Sjmmv 615698d5317Sjmmv /* Free old tree and create a new root. */ 616698d5317Sjmmv layout_free(w); 617698d5317Sjmmv lc = w->layout_root = layout_create_cell(NULL); 618ef36e747Schristos sx = ((width + 1) * columns) - 1; 619ef36e747Schristos if (sx < w->sx) 620ef36e747Schristos sx = w->sx; 621ef36e747Schristos sy = ((height + 1) * rows) - 1; 622ef36e747Schristos if (sy < w->sy) 623ef36e747Schristos sy = w->sy; 624ef36e747Schristos layout_set_size(lc, sx, sy, 0, 0); 625698d5317Sjmmv layout_make_node(lc, LAYOUT_TOPBOTTOM); 626698d5317Sjmmv 627698d5317Sjmmv /* Create a grid of the cells. */ 628698d5317Sjmmv wp = TAILQ_FIRST(&w->panes); 629698d5317Sjmmv for (j = 0; j < rows; j++) { 630698d5317Sjmmv /* If this is the last cell, all done. */ 631698d5317Sjmmv if (wp == NULL) 632698d5317Sjmmv break; 633698d5317Sjmmv 634698d5317Sjmmv /* Create the new row. */ 635698d5317Sjmmv lcrow = layout_create_cell(lc); 636698d5317Sjmmv layout_set_size(lcrow, w->sx, height, 0, 0); 637698d5317Sjmmv TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry); 638698d5317Sjmmv 639698d5317Sjmmv /* If only one column, just use the row directly. */ 640d530c4d0Sjmmv if (n - (j * columns) == 1 || columns == 1) { 641698d5317Sjmmv layout_make_leaf(lcrow, wp); 642698d5317Sjmmv wp = TAILQ_NEXT(wp, entry); 643698d5317Sjmmv continue; 644698d5317Sjmmv } 645698d5317Sjmmv 646698d5317Sjmmv /* Add in the columns. */ 647698d5317Sjmmv layout_make_node(lcrow, LAYOUT_LEFTRIGHT); 648698d5317Sjmmv for (i = 0; i < columns; i++) { 649698d5317Sjmmv /* Create and add a pane cell. */ 650698d5317Sjmmv lcchild = layout_create_cell(lcrow); 651698d5317Sjmmv layout_set_size(lcchild, width, height, 0, 0); 652698d5317Sjmmv layout_make_leaf(lcchild, wp); 653698d5317Sjmmv TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry); 654698d5317Sjmmv 655698d5317Sjmmv /* Move to the next cell. */ 656698d5317Sjmmv if ((wp = TAILQ_NEXT(wp, entry)) == NULL) 657698d5317Sjmmv break; 658698d5317Sjmmv } 659698d5317Sjmmv 660698d5317Sjmmv /* 661698d5317Sjmmv * Adjust the row and columns to fit the full width if 662698d5317Sjmmv * necessary. 663698d5317Sjmmv */ 664698d5317Sjmmv if (i == columns) 665698d5317Sjmmv i--; 666698d5317Sjmmv used = ((i + 1) * (width + 1)) - 1; 667698d5317Sjmmv if (w->sx <= used) 668698d5317Sjmmv continue; 669698d5317Sjmmv lcchild = TAILQ_LAST(&lcrow->cells, layout_cells); 6704e179ddaSchristos layout_resize_adjust(w, lcchild, LAYOUT_LEFTRIGHT, 6714e179ddaSchristos w->sx - used); 672698d5317Sjmmv } 673698d5317Sjmmv 674698d5317Sjmmv /* Adjust the last row height to fit if necessary. */ 675698d5317Sjmmv used = (rows * height) + rows - 1; 676698d5317Sjmmv if (w->sy > used) { 677698d5317Sjmmv lcrow = TAILQ_LAST(&lc->cells, layout_cells); 6784e179ddaSchristos layout_resize_adjust(w, lcrow, LAYOUT_TOPBOTTOM, 6794e179ddaSchristos w->sy - used); 680698d5317Sjmmv } 681698d5317Sjmmv 682698d5317Sjmmv /* Fix cell offsets. */ 6836483eba0Schristos layout_fix_offsets(w); 6849fb66d81Schristos layout_fix_panes(w, NULL); 685698d5317Sjmmv 686698d5317Sjmmv layout_print_cell(w->layout_root, __func__, 1); 687698d5317Sjmmv 688aa83ff61Schristos window_resize(w, lc->sx, lc->sy, -1, -1); 689c9ad075bSchristos notify_window("window-layout-changed", w); 690698d5317Sjmmv server_redraw_window(w); 691698d5317Sjmmv } 692