4 * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
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.
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.
19 #include <sys/types.h>
26 * Set window layouts - predefined methods to arrange windows. These are one-off
27 * and generate a layout tree.
30 void layout_set_even_h(struct window
*);
31 void layout_set_even_v(struct window
*);
32 void layout_set_main_h(struct window
*);
33 void layout_set_main_v(struct window
*);
34 void layout_set_tiled(struct window
*);
38 void (*arrange
)(struct window
*);
40 { "even-horizontal", layout_set_even_h
},
41 { "even-vertical", layout_set_even_v
},
42 { "main-horizontal", layout_set_main_h
},
43 { "main-vertical", layout_set_main_v
},
44 { "tiled", layout_set_tiled
},
48 layout_set_name(u_int layout
)
50 return (layout_sets
[layout
].name
);
54 layout_set_lookup(const char *name
)
59 for (i
= 0; i
< nitems(layout_sets
); i
++) {
60 if (strncmp(layout_sets
[i
].name
, name
, strlen(name
)) == 0) {
61 if (matched
!= -1) /* ambiguous */
71 layout_set_select(struct window
*w
, u_int layout
)
73 if (layout
> nitems(layout_sets
) - 1)
74 layout
= nitems(layout_sets
) - 1;
76 if (layout_sets
[layout
].arrange
!= NULL
)
77 layout_sets
[layout
].arrange(w
);
79 w
->lastlayout
= layout
;
84 layout_set_next(struct window
*w
)
88 if (w
->lastlayout
== -1)
91 layout
= w
->lastlayout
+ 1;
92 if (layout
> nitems(layout_sets
) - 1)
96 if (layout_sets
[layout
].arrange
!= NULL
)
97 layout_sets
[layout
].arrange(w
);
98 w
->lastlayout
= layout
;
103 layout_set_previous(struct window
*w
)
107 if (w
->lastlayout
== -1)
108 layout
= nitems(layout_sets
) - 1;
110 layout
= w
->lastlayout
;
112 layout
= nitems(layout_sets
) - 1;
117 if (layout_sets
[layout
].arrange
!= NULL
)
118 layout_sets
[layout
].arrange(w
);
119 w
->lastlayout
= layout
;
124 layout_set_even_h(struct window
*w
)
126 struct window_pane
*wp
;
127 struct layout_cell
*lc
, *lcnew
;
128 u_int i
, n
, width
, xoff
;
130 layout_print_cell(w
->layout_root
, __func__
, 1);
132 /* Get number of panes. */
133 n
= window_count_panes(w
);
137 /* How many can we fit? */
138 width
= (w
->sx
- (n
- 1)) / n
;
139 if (width
< PANE_MINIMUM
)
140 width
= PANE_MINIMUM
;
142 /* Free the old root and construct a new. */
144 lc
= w
->layout_root
= layout_create_cell(NULL
);
145 layout_set_size(lc
, w
->sx
, w
->sy
, 0, 0);
146 layout_make_node(lc
, LAYOUT_LEFTRIGHT
);
148 /* Build new leaf cells. */
150 TAILQ_FOREACH(wp
, &w
->panes
, entry
) {
151 /* Create child cell. */
152 lcnew
= layout_create_cell(lc
);
153 layout_set_size(lcnew
, width
, w
->sy
, xoff
, 0);
154 layout_make_leaf(lcnew
, wp
);
155 TAILQ_INSERT_TAIL(&lc
->cells
, lcnew
, entry
);
161 /* Allocate any remaining space. */
162 if (w
->sx
> xoff
- 1) {
163 lc
= TAILQ_LAST(&lc
->cells
, layout_cells
);
164 layout_resize_adjust(lc
, LAYOUT_LEFTRIGHT
, w
->sx
- (xoff
- 1));
167 /* Fix cell offsets. */
168 layout_fix_offsets(lc
);
169 layout_fix_panes(w
, w
->sx
, w
->sy
);
171 layout_print_cell(w
->layout_root
, __func__
, 1);
173 server_redraw_window(w
);
177 layout_set_even_v(struct window
*w
)
179 struct window_pane
*wp
;
180 struct layout_cell
*lc
, *lcnew
;
181 u_int i
, n
, height
, yoff
;
183 layout_print_cell(w
->layout_root
, __func__
, 1);
185 /* Get number of panes. */
186 n
= window_count_panes(w
);
190 /* How many can we fit? */
191 height
= (w
->sy
- (n
- 1)) / n
;
192 if (height
< PANE_MINIMUM
)
193 height
= PANE_MINIMUM
;
195 /* Free the old root and construct a new. */
197 lc
= w
->layout_root
= layout_create_cell(NULL
);
198 layout_set_size(lc
, w
->sx
, w
->sy
, 0, 0);
199 layout_make_node(lc
, LAYOUT_TOPBOTTOM
);
201 /* Build new leaf cells. */
203 TAILQ_FOREACH(wp
, &w
->panes
, entry
) {
204 /* Create child cell. */
205 lcnew
= layout_create_cell(lc
);
206 layout_set_size(lcnew
, w
->sx
, height
, 0, yoff
);
207 layout_make_leaf(lcnew
, wp
);
208 TAILQ_INSERT_TAIL(&lc
->cells
, lcnew
, entry
);
214 /* Allocate any remaining space. */
215 if (w
->sy
> yoff
- 1) {
216 lc
= TAILQ_LAST(&lc
->cells
, layout_cells
);
217 layout_resize_adjust(lc
, LAYOUT_TOPBOTTOM
, w
->sy
- (yoff
- 1));
220 /* Fix cell offsets. */
221 layout_fix_offsets(lc
);
222 layout_fix_panes(w
, w
->sx
, w
->sy
);
224 layout_print_cell(w
->layout_root
, __func__
, 1);
226 server_redraw_window(w
);
230 layout_set_main_h(struct window
*w
)
232 struct window_pane
*wp
;
233 struct layout_cell
*lc
, *lcmain
, *lcrow
, *lcchild
;
234 u_int n
, mainheight
, otherheight
, width
, height
;
235 u_int used
, i
, j
, columns
, rows
, totalrows
;
237 layout_print_cell(w
->layout_root
, __func__
, 1);
239 /* Get number of panes. */
240 n
= window_count_panes(w
);
243 n
--; /* take off main pane */
245 /* How many rows and columns will be needed, not counting main? */
246 columns
= (w
->sx
+ 1) / (PANE_MINIMUM
+ 1); /* maximum columns */
249 rows
= 1 + (n
- 1) / columns
;
250 columns
= 1 + (n
- 1) / rows
;
251 width
= (w
->sx
- (n
- 1)) / columns
;
253 /* Get the main pane height and add one for separator line. */
254 mainheight
= options_get_number(&w
->options
, "main-pane-height") + 1;
256 /* Get the optional other pane height and add one for separator line. */
257 otherheight
= options_get_number(&w
->options
, "other-pane-height") + 1;
260 * If an other pane height was specified, honour it so long as it
261 * doesn't shrink the main height to less than the main-pane-height
263 if (otherheight
> 1 && w
->sy
- otherheight
> mainheight
)
264 mainheight
= w
->sy
- otherheight
;
265 if (mainheight
< PANE_MINIMUM
+ 1)
266 mainheight
= PANE_MINIMUM
+ 1;
268 /* Try and make everything fit. */
269 totalrows
= rows
* (PANE_MINIMUM
+ 1) - 1;
270 if (mainheight
+ totalrows
> w
->sy
) {
271 if (totalrows
+ PANE_MINIMUM
+ 1 > w
->sy
)
272 mainheight
= PANE_MINIMUM
+ 2;
274 mainheight
= w
->sy
- totalrows
;
275 height
= PANE_MINIMUM
;
277 height
= (w
->sy
- mainheight
- (rows
- 1)) / rows
;
279 /* Free old tree and create a new root. */
281 lc
= w
->layout_root
= layout_create_cell(NULL
);
282 layout_set_size(lc
, w
->sx
, mainheight
+ rows
* (height
+ 1) - 1, 0, 0);
283 layout_make_node(lc
, LAYOUT_TOPBOTTOM
);
285 /* Create the main pane. */
286 lcmain
= layout_create_cell(lc
);
287 layout_set_size(lcmain
, w
->sx
, mainheight
- 1, 0, 0);
288 layout_make_leaf(lcmain
, TAILQ_FIRST(&w
->panes
));
289 TAILQ_INSERT_TAIL(&lc
->cells
, lcmain
, entry
);
291 /* Create a grid of the remaining cells. */
292 wp
= TAILQ_NEXT(TAILQ_FIRST(&w
->panes
), entry
);
293 for (j
= 0; j
< rows
; j
++) {
294 /* If this is the last cell, all done. */
298 /* Create the new row. */
299 lcrow
= layout_create_cell(lc
);
300 layout_set_size(lcrow
, w
->sx
, height
, 0, 0);
301 TAILQ_INSERT_TAIL(&lc
->cells
, lcrow
, entry
);
303 /* If only one column, just use the row directly. */
305 layout_make_leaf(lcrow
, wp
);
306 wp
= TAILQ_NEXT(wp
, entry
);
310 /* Add in the columns. */
311 layout_make_node(lcrow
, LAYOUT_LEFTRIGHT
);
312 for (i
= 0; i
< columns
; i
++) {
313 /* Create and add a pane cell. */
314 lcchild
= layout_create_cell(lcrow
);
315 layout_set_size(lcchild
, width
, height
, 0, 0);
316 layout_make_leaf(lcchild
, wp
);
317 TAILQ_INSERT_TAIL(&lcrow
->cells
, lcchild
, entry
);
319 /* Move to the next cell. */
320 if ((wp
= TAILQ_NEXT(wp
, entry
)) == NULL
)
324 /* Adjust the row to fit the full width if necessary. */
327 used
= ((i
+ 1) * (width
+ 1)) - 1;
330 lcchild
= TAILQ_LAST(&lcrow
->cells
, layout_cells
);
331 layout_resize_adjust(lcchild
, LAYOUT_LEFTRIGHT
, w
->sx
- used
);
334 /* Adjust the last row height to fit if necessary. */
335 used
= mainheight
+ (rows
* height
) + rows
- 1;
337 lcrow
= TAILQ_LAST(&lc
->cells
, layout_cells
);
338 layout_resize_adjust(lcrow
, LAYOUT_TOPBOTTOM
, w
->sy
- used
);
341 /* Fix cell offsets. */
342 layout_fix_offsets(lc
);
343 layout_fix_panes(w
, w
->sx
, w
->sy
);
345 layout_print_cell(w
->layout_root
, __func__
, 1);
347 server_redraw_window(w
);
351 layout_set_main_v(struct window
*w
)
353 struct window_pane
*wp
;
354 struct layout_cell
*lc
, *lcmain
, *lccolumn
, *lcchild
;
355 u_int n
, mainwidth
, otherwidth
, width
, height
;
356 u_int used
, i
, j
, columns
, rows
, totalcolumns
;
358 layout_print_cell(w
->layout_root
, __func__
, 1);
360 /* Get number of panes. */
361 n
= window_count_panes(w
);
364 n
--; /* take off main pane */
366 /* How many rows and columns will be needed, not counting main? */
367 rows
= (w
->sy
+ 1) / (PANE_MINIMUM
+ 1); /* maximum rows */
370 columns
= 1 + (n
- 1) / rows
;
371 rows
= 1 + (n
- 1) / columns
;
372 height
= (w
->sy
- (n
- 1)) / rows
;
374 /* Get the main pane width and add one for separator line. */
375 mainwidth
= options_get_number(&w
->options
, "main-pane-width") + 1;
377 /* Get the optional other pane width and add one for separator line. */
378 otherwidth
= options_get_number(&w
->options
, "other-pane-width") + 1;
381 * If an other pane width was specified, honour it so long as it
382 * doesn't shrink the main width to less than the main-pane-width
384 if (otherwidth
> 1 && w
->sx
- otherwidth
> mainwidth
)
385 mainwidth
= w
->sx
- otherwidth
;
386 if (mainwidth
< PANE_MINIMUM
+ 1)
387 mainwidth
= PANE_MINIMUM
+ 1;
389 /* Try and make everything fit. */
390 totalcolumns
= columns
* (PANE_MINIMUM
+ 1) - 1;
391 if (mainwidth
+ totalcolumns
> w
->sx
) {
392 if (totalcolumns
+ PANE_MINIMUM
+ 1 > w
->sx
)
393 mainwidth
= PANE_MINIMUM
+ 2;
395 mainwidth
= w
->sx
- totalcolumns
;
396 width
= PANE_MINIMUM
;
398 width
= (w
->sx
- mainwidth
- (columns
- 1)) / columns
;
400 /* Free old tree and create a new root. */
402 lc
= w
->layout_root
= layout_create_cell(NULL
);
403 layout_set_size(lc
, mainwidth
+ columns
* (width
+ 1) - 1, w
->sy
, 0, 0);
404 layout_make_node(lc
, LAYOUT_LEFTRIGHT
);
406 /* Create the main pane. */
407 lcmain
= layout_create_cell(lc
);
408 layout_set_size(lcmain
, mainwidth
- 1, w
->sy
, 0, 0);
409 layout_make_leaf(lcmain
, TAILQ_FIRST(&w
->panes
));
410 TAILQ_INSERT_TAIL(&lc
->cells
, lcmain
, entry
);
412 /* Create a grid of the remaining cells. */
413 wp
= TAILQ_NEXT(TAILQ_FIRST(&w
->panes
), entry
);
414 for (j
= 0; j
< columns
; j
++) {
415 /* If this is the last cell, all done. */
419 /* Create the new column. */
420 lccolumn
= layout_create_cell(lc
);
421 layout_set_size(lccolumn
, width
, w
->sy
, 0, 0);
422 TAILQ_INSERT_TAIL(&lc
->cells
, lccolumn
, entry
);
424 /* If only one row, just use the row directly. */
426 layout_make_leaf(lccolumn
, wp
);
427 wp
= TAILQ_NEXT(wp
, entry
);
431 /* Add in the rows. */
432 layout_make_node(lccolumn
, LAYOUT_TOPBOTTOM
);
433 for (i
= 0; i
< rows
; i
++) {
434 /* Create and add a pane cell. */
435 lcchild
= layout_create_cell(lccolumn
);
436 layout_set_size(lcchild
, width
, height
, 0, 0);
437 layout_make_leaf(lcchild
, wp
);
438 TAILQ_INSERT_TAIL(&lccolumn
->cells
, lcchild
, entry
);
440 /* Move to the next cell. */
441 if ((wp
= TAILQ_NEXT(wp
, entry
)) == NULL
)
445 /* Adjust the column to fit the full height if necessary. */
448 used
= ((i
+ 1) * (height
+ 1)) - 1;
451 lcchild
= TAILQ_LAST(&lccolumn
->cells
, layout_cells
);
452 layout_resize_adjust(lcchild
, LAYOUT_TOPBOTTOM
, w
->sy
- used
);
455 /* Adjust the last column width to fit if necessary. */
456 used
= mainwidth
+ (columns
* width
) + columns
- 1;
458 lccolumn
= TAILQ_LAST(&lc
->cells
, layout_cells
);
459 layout_resize_adjust(lccolumn
, LAYOUT_LEFTRIGHT
, w
->sx
- used
);
462 /* Fix cell offsets. */
463 layout_fix_offsets(lc
);
464 layout_fix_panes(w
, w
->sx
, w
->sy
);
466 layout_print_cell(w
->layout_root
, __func__
, 1);
468 server_redraw_window(w
);
472 layout_set_tiled(struct window
*w
)
474 struct window_pane
*wp
;
475 struct layout_cell
*lc
, *lcrow
, *lcchild
;
476 u_int n
, width
, height
, used
;
477 u_int i
, j
, columns
, rows
;
479 layout_print_cell(w
->layout_root
, __func__
, 1);
481 /* Get number of panes. */
482 n
= window_count_panes(w
);
486 /* How many rows and columns are wanted? */
488 while (rows
* columns
< n
) {
490 if (rows
* columns
< n
)
494 /* What width and height should they be? */
495 width
= (w
->sx
- (columns
- 1)) / columns
;
496 if (width
< PANE_MINIMUM
)
497 width
= PANE_MINIMUM
;
498 height
= (w
->sy
- (rows
- 1)) / rows
;
499 if (height
< PANE_MINIMUM
)
500 height
= PANE_MINIMUM
;
502 /* Free old tree and create a new root. */
504 lc
= w
->layout_root
= layout_create_cell(NULL
);
505 layout_set_size(lc
, (width
+ 1) * columns
- 1,
506 (height
+ 1) * rows
- 1, 0, 0);
507 layout_make_node(lc
, LAYOUT_TOPBOTTOM
);
509 /* Create a grid of the cells. */
510 wp
= TAILQ_FIRST(&w
->panes
);
511 for (j
= 0; j
< rows
; j
++) {
512 /* If this is the last cell, all done. */
516 /* Create the new row. */
517 lcrow
= layout_create_cell(lc
);
518 layout_set_size(lcrow
, w
->sx
, height
, 0, 0);
519 TAILQ_INSERT_TAIL(&lc
->cells
, lcrow
, entry
);
521 /* If only one column, just use the row directly. */
522 if (n
- (j
* columns
) == 1 || columns
== 1) {
523 layout_make_leaf(lcrow
, wp
);
524 wp
= TAILQ_NEXT(wp
, entry
);
528 /* Add in the columns. */
529 layout_make_node(lcrow
, LAYOUT_LEFTRIGHT
);
530 for (i
= 0; i
< columns
; i
++) {
531 /* Create and add a pane cell. */
532 lcchild
= layout_create_cell(lcrow
);
533 layout_set_size(lcchild
, width
, height
, 0, 0);
534 layout_make_leaf(lcchild
, wp
);
535 TAILQ_INSERT_TAIL(&lcrow
->cells
, lcchild
, entry
);
537 /* Move to the next cell. */
538 if ((wp
= TAILQ_NEXT(wp
, entry
)) == NULL
)
543 * Adjust the row and columns to fit the full width if
548 used
= ((i
+ 1) * (width
+ 1)) - 1;
551 lcchild
= TAILQ_LAST(&lcrow
->cells
, layout_cells
);
552 layout_resize_adjust(lcchild
, LAYOUT_LEFTRIGHT
, w
->sx
- used
);
555 /* Adjust the last row height to fit if necessary. */
556 used
= (rows
* height
) + rows
- 1;
558 lcrow
= TAILQ_LAST(&lc
->cells
, layout_cells
);
559 layout_resize_adjust(lcrow
, LAYOUT_TOPBOTTOM
, w
->sy
- used
);
562 /* Fix cell offsets. */
563 layout_fix_offsets(lc
);
564 layout_fix_panes(w
, w
->sx
, w
->sy
);
566 layout_print_cell(w
->layout_root
, __func__
, 1);
568 server_redraw_window(w
);