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
layout_set_lookup(const char * name)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
layout_set_select(struct window * w,u_int layout)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
layout_set_next(struct window * w)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
layout_set_previous(struct window * w)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
layout_set_even(struct window * w,enum layout_type type)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
layout_set_even_h(struct window * w)181967ee5b9Snicm layout_set_even_h(struct window *w)
182967ee5b9Snicm {
183967ee5b9Snicm layout_set_even(w, LAYOUT_LEFTRIGHT);
184967ee5b9Snicm }
185967ee5b9Snicm
186967ee5b9Snicm static void
layout_set_even_v(struct window * w)187af9e4c5dSnicm layout_set_even_v(struct window *w)
188af9e4c5dSnicm {
189967ee5b9Snicm layout_set_even(w, LAYOUT_TOPBOTTOM);
190af9e4c5dSnicm }
191af9e4c5dSnicm
1929883b791Snicm static void
layout_set_main_h(struct window * w)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
layout_set_main_h_mirrored(struct window * w)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
layout_set_main_v(struct window * w)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
layout_set_main_v_mirrored(struct window * w)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
layout_set_tiled(struct window * w)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