4 * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
5 * Copyright (c) 2016 Stephen Kent <smkent@smkent.net>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
16 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/types.h>
27 * The window layout is a tree of cells each of which can be one of: a
28 * left-right container for a list of cells, a top-bottom container for a list
29 * of cells, or a container for a window pane.
31 * Each window has a pointer to the root of its layout tree (containing its
32 * panes), every pane has a pointer back to the cell containing it, and each
33 * cell a pointer to its parent cell.
36 static u_int
layout_resize_check(struct window
*, struct layout_cell
*,
38 static int layout_resize_pane_grow(struct window
*, struct layout_cell
*,
39 enum layout_type
, int, int);
40 static int layout_resize_pane_shrink(struct window
*, struct layout_cell
*,
41 enum layout_type
, int);
42 static u_int
layout_new_pane_size(struct window
*, u_int
,
43 struct layout_cell
*, enum layout_type
, u_int
, u_int
,
45 static int layout_set_size_check(struct window
*, struct layout_cell
*,
46 enum layout_type
, int);
47 static void layout_resize_child_cells(struct window
*,
48 struct layout_cell
*);
51 layout_create_cell(struct layout_cell
*lcparent
)
53 struct layout_cell
*lc
;
55 lc
= xmalloc(sizeof *lc
);
56 lc
->type
= LAYOUT_WINDOWPANE
;
57 lc
->parent
= lcparent
;
59 TAILQ_INIT(&lc
->cells
);
73 layout_free_cell(struct layout_cell
*lc
)
75 struct layout_cell
*lcchild
;
78 case LAYOUT_LEFTRIGHT
:
79 case LAYOUT_TOPBOTTOM
:
80 while (!TAILQ_EMPTY(&lc
->cells
)) {
81 lcchild
= TAILQ_FIRST(&lc
->cells
);
82 TAILQ_REMOVE(&lc
->cells
, lcchild
, entry
);
83 layout_free_cell(lcchild
);
86 case LAYOUT_WINDOWPANE
:
88 lc
->wp
->layout_cell
= NULL
;
96 layout_print_cell(struct layout_cell
*lc
, const char *hdr
, u_int n
)
98 struct layout_cell
*lcchild
;
102 case LAYOUT_LEFTRIGHT
:
105 case LAYOUT_TOPBOTTOM
:
108 case LAYOUT_WINDOWPANE
:
115 log_debug("%s:%*s%p type %s [parent %p] wp=%p [%u,%u %ux%u]", hdr
, n
,
116 " ", lc
, type
, lc
->parent
, lc
->wp
, lc
->xoff
, lc
->yoff
, lc
->sx
,
119 case LAYOUT_LEFTRIGHT
:
120 case LAYOUT_TOPBOTTOM
:
121 TAILQ_FOREACH(lcchild
, &lc
->cells
, entry
)
122 layout_print_cell(lcchild
, hdr
, n
+ 1);
124 case LAYOUT_WINDOWPANE
:
130 layout_search_by_border(struct layout_cell
*lc
, u_int x
, u_int y
)
132 struct layout_cell
*lcchild
, *last
= NULL
;
134 TAILQ_FOREACH(lcchild
, &lc
->cells
, entry
) {
135 if (x
>= lcchild
->xoff
&& x
< lcchild
->xoff
+ lcchild
->sx
&&
136 y
>= lcchild
->yoff
&& y
< lcchild
->yoff
+ lcchild
->sy
) {
137 /* Inside the cell - recurse. */
138 return (layout_search_by_border(lcchild
, x
, y
));
147 case LAYOUT_LEFTRIGHT
:
148 if (x
< lcchild
->xoff
&& x
>= last
->xoff
+ last
->sx
)
151 case LAYOUT_TOPBOTTOM
:
152 if (y
< lcchild
->yoff
&& y
>= last
->yoff
+ last
->sy
)
155 case LAYOUT_WINDOWPANE
:
166 layout_set_size(struct layout_cell
*lc
, u_int sx
, u_int sy
, u_int xoff
,
177 layout_make_leaf(struct layout_cell
*lc
, struct window_pane
*wp
)
179 lc
->type
= LAYOUT_WINDOWPANE
;
181 TAILQ_INIT(&lc
->cells
);
183 wp
->layout_cell
= lc
;
188 layout_make_node(struct layout_cell
*lc
, enum layout_type type
)
190 if (type
== LAYOUT_WINDOWPANE
)
191 fatalx("bad layout type");
194 TAILQ_INIT(&lc
->cells
);
197 lc
->wp
->layout_cell
= NULL
;
201 /* Fix cell offsets for a child cell. */
203 layout_fix_offsets1(struct layout_cell
*lc
)
205 struct layout_cell
*lcchild
;
208 if (lc
->type
== LAYOUT_LEFTRIGHT
) {
210 TAILQ_FOREACH(lcchild
, &lc
->cells
, entry
) {
211 lcchild
->xoff
= xoff
;
212 lcchild
->yoff
= lc
->yoff
;
213 if (lcchild
->type
!= LAYOUT_WINDOWPANE
)
214 layout_fix_offsets1(lcchild
);
215 xoff
+= lcchild
->sx
+ 1;
219 TAILQ_FOREACH(lcchild
, &lc
->cells
, entry
) {
220 lcchild
->xoff
= lc
->xoff
;
221 lcchild
->yoff
= yoff
;
222 if (lcchild
->type
!= LAYOUT_WINDOWPANE
)
223 layout_fix_offsets1(lcchild
);
224 yoff
+= lcchild
->sy
+ 1;
229 /* Update cell offsets based on their sizes. */
231 layout_fix_offsets(struct window
*w
)
233 struct layout_cell
*lc
= w
->layout_root
;
238 layout_fix_offsets1(lc
);
241 /* Is this a top cell? */
243 layout_cell_is_top(struct window
*w
, struct layout_cell
*lc
)
245 struct layout_cell
*next
;
247 while (lc
!= w
->layout_root
) {
249 if (next
->type
== LAYOUT_TOPBOTTOM
&&
250 lc
!= TAILQ_FIRST(&next
->cells
))
257 /* Is this a bottom cell? */
259 layout_cell_is_bottom(struct window
*w
, struct layout_cell
*lc
)
261 struct layout_cell
*next
;
263 while (lc
!= w
->layout_root
) {
265 if (next
->type
== LAYOUT_TOPBOTTOM
&&
266 lc
!= TAILQ_LAST(&next
->cells
, layout_cells
))
274 * Returns 1 if we need to add an extra line for the pane status line. This is
275 * the case for the most upper or lower panes only.
278 layout_add_border(struct window
*w
, struct layout_cell
*lc
, int status
)
280 if (status
== PANE_STATUS_TOP
)
281 return (layout_cell_is_top(w
, lc
));
282 if (status
== PANE_STATUS_BOTTOM
)
283 return (layout_cell_is_bottom(w
, lc
));
287 /* Update pane offsets and sizes based on their cells. */
289 layout_fix_panes(struct window
*w
, struct window_pane
*skip
)
291 struct window_pane
*wp
;
292 struct layout_cell
*lc
;
295 status
= options_get_number(w
->options
, "pane-border-status");
296 TAILQ_FOREACH(wp
, &w
->panes
, entry
) {
297 if ((lc
= wp
->layout_cell
) == NULL
|| wp
== skip
)
303 if (layout_add_border(w
, lc
, status
)) {
304 if (status
== PANE_STATUS_TOP
)
306 window_pane_resize(wp
, lc
->sx
, lc
->sy
- 1);
308 window_pane_resize(wp
, lc
->sx
, lc
->sy
);
312 /* Count the number of available cells in a layout. */
314 layout_count_cells(struct layout_cell
*lc
)
316 struct layout_cell
*lcchild
;
320 case LAYOUT_WINDOWPANE
:
322 case LAYOUT_LEFTRIGHT
:
323 case LAYOUT_TOPBOTTOM
:
325 TAILQ_FOREACH(lcchild
, &lc
->cells
, entry
)
326 count
+= layout_count_cells(lcchild
);
329 fatalx("bad layout type");
333 /* Calculate how much size is available to be removed from a cell. */
335 layout_resize_check(struct window
*w
, struct layout_cell
*lc
,
336 enum layout_type type
)
338 struct layout_cell
*lcchild
;
339 u_int available
, minimum
;
342 status
= options_get_number(w
->options
, "pane-border-status");
343 if (lc
->type
== LAYOUT_WINDOWPANE
) {
344 /* Space available in this cell only. */
345 if (type
== LAYOUT_LEFTRIGHT
) {
347 minimum
= PANE_MINIMUM
;
350 if (layout_add_border(w
, lc
, status
))
351 minimum
= PANE_MINIMUM
+ 1;
353 minimum
= PANE_MINIMUM
;
355 if (available
> minimum
)
356 available
-= minimum
;
359 } else if (lc
->type
== type
) {
360 /* Same type: total of available space in all child cells. */
362 TAILQ_FOREACH(lcchild
, &lc
->cells
, entry
)
363 available
+= layout_resize_check(w
, lcchild
, type
);
365 /* Different type: minimum of available space in child cells. */
367 TAILQ_FOREACH(lcchild
, &lc
->cells
, entry
) {
368 available
= layout_resize_check(w
, lcchild
, type
);
369 if (available
< minimum
)
379 * Adjust cell size evenly, including altering its children. This function
380 * expects the change to have already been bounded to the space available.
383 layout_resize_adjust(struct window
*w
, struct layout_cell
*lc
,
384 enum layout_type type
, int change
)
386 struct layout_cell
*lcchild
;
388 /* Adjust the cell size. */
389 if (type
== LAYOUT_LEFTRIGHT
)
394 /* If this is a leaf cell, that is all that is necessary. */
395 if (type
== LAYOUT_WINDOWPANE
)
398 /* Child cell runs in a different direction. */
399 if (lc
->type
!= type
) {
400 TAILQ_FOREACH(lcchild
, &lc
->cells
, entry
)
401 layout_resize_adjust(w
, lcchild
, type
, change
);
406 * Child cell runs in the same direction. Adjust each child equally
407 * until no further change is possible.
409 while (change
!= 0) {
410 TAILQ_FOREACH(lcchild
, &lc
->cells
, entry
) {
414 layout_resize_adjust(w
, lcchild
, type
, 1);
418 if (layout_resize_check(w
, lcchild
, type
) > 0) {
419 layout_resize_adjust(w
, lcchild
, type
, -1);
426 /* Destroy a cell and redistribute the space. */
428 layout_destroy_cell(struct window
*w
, struct layout_cell
*lc
,
429 struct layout_cell
**lcroot
)
431 struct layout_cell
*lcother
, *lcparent
;
434 * If no parent, this is the last pane so window close is imminent and
435 * there is no need to resize anything.
437 lcparent
= lc
->parent
;
438 if (lcparent
== NULL
) {
439 layout_free_cell(lc
);
444 /* Merge the space into the previous or next cell. */
445 if (lc
== TAILQ_FIRST(&lcparent
->cells
))
446 lcother
= TAILQ_NEXT(lc
, entry
);
448 lcother
= TAILQ_PREV(lc
, layout_cells
, entry
);
449 if (lcother
!= NULL
&& lcparent
->type
== LAYOUT_LEFTRIGHT
)
450 layout_resize_adjust(w
, lcother
, lcparent
->type
, lc
->sx
+ 1);
451 else if (lcother
!= NULL
)
452 layout_resize_adjust(w
, lcother
, lcparent
->type
, lc
->sy
+ 1);
454 /* Remove this from the parent's list. */
455 TAILQ_REMOVE(&lcparent
->cells
, lc
, entry
);
456 layout_free_cell(lc
);
459 * If the parent now has one cell, remove the parent from the tree and
460 * replace it by that cell.
462 lc
= TAILQ_FIRST(&lcparent
->cells
);
463 if (TAILQ_NEXT(lc
, entry
) == NULL
) {
464 TAILQ_REMOVE(&lcparent
->cells
, lc
, entry
);
466 lc
->parent
= lcparent
->parent
;
467 if (lc
->parent
== NULL
) {
468 lc
->xoff
= 0; lc
->yoff
= 0;
471 TAILQ_REPLACE(&lc
->parent
->cells
, lcparent
, lc
, entry
);
473 layout_free_cell(lcparent
);
478 layout_init(struct window
*w
, struct window_pane
*wp
)
480 struct layout_cell
*lc
;
482 lc
= w
->layout_root
= layout_create_cell(NULL
);
483 layout_set_size(lc
, w
->sx
, w
->sy
, 0, 0);
484 layout_make_leaf(lc
, wp
);
485 layout_fix_panes(w
, NULL
);
489 layout_free(struct window
*w
)
491 layout_free_cell(w
->layout_root
);
494 /* Resize the entire layout after window resize. */
496 layout_resize(struct window
*w
, u_int sx
, u_int sy
)
498 struct layout_cell
*lc
= w
->layout_root
;
499 int xlimit
, ylimit
, xchange
, ychange
;
502 * Adjust horizontally. Do not attempt to reduce the layout lower than
503 * the minimum (more than the amount returned by layout_resize_check).
505 * This can mean that the window size is smaller than the total layout
506 * size: redrawing this is handled at a higher level, but it does leave
507 * a problem with growing the window size here: if the current size is
508 * < the minimum, growing proportionately by adding to each pane is
509 * wrong as it would keep the layout size larger than the window size.
510 * Instead, spread the difference between the minimum and the new size
511 * out proportionately - this should leave the layout fitting the new
514 xchange
= sx
- lc
->sx
;
515 xlimit
= layout_resize_check(w
, lc
, LAYOUT_LEFTRIGHT
);
516 if (xchange
< 0 && xchange
< -xlimit
)
519 if (sx
<= lc
->sx
) /* lc->sx is minimum possible */
522 xchange
= sx
- lc
->sx
;
525 layout_resize_adjust(w
, lc
, LAYOUT_LEFTRIGHT
, xchange
);
527 /* Adjust vertically in a similar fashion. */
528 ychange
= sy
- lc
->sy
;
529 ylimit
= layout_resize_check(w
, lc
, LAYOUT_TOPBOTTOM
);
530 if (ychange
< 0 && ychange
< -ylimit
)
533 if (sy
<= lc
->sy
) /* lc->sy is minimum possible */
536 ychange
= sy
- lc
->sy
;
539 layout_resize_adjust(w
, lc
, LAYOUT_TOPBOTTOM
, ychange
);
541 /* Fix cell offsets. */
542 layout_fix_offsets(w
);
543 layout_fix_panes(w
, NULL
);
546 /* Resize a pane to an absolute size. */
548 layout_resize_pane_to(struct window_pane
*wp
, enum layout_type type
,
551 struct layout_cell
*lc
, *lcparent
;
554 lc
= wp
->layout_cell
;
556 /* Find next parent of the same type. */
557 lcparent
= lc
->parent
;
558 while (lcparent
!= NULL
&& lcparent
->type
!= type
) {
560 lcparent
= lc
->parent
;
562 if (lcparent
== NULL
)
565 /* Work out the size adjustment. */
566 if (type
== LAYOUT_LEFTRIGHT
)
570 if (lc
== TAILQ_LAST(&lcparent
->cells
, layout_cells
))
571 change
= size
- new_size
;
573 change
= new_size
- size
;
575 /* Resize the pane. */
576 layout_resize_pane(wp
, type
, change
, 1);
580 layout_resize_layout(struct window
*w
, struct layout_cell
*lc
,
581 enum layout_type type
, int change
, int opposite
)
585 /* Grow or shrink the cell. */
587 while (needed
!= 0) {
589 size
= layout_resize_pane_grow(w
, lc
, type
, needed
,
593 size
= layout_resize_pane_shrink(w
, lc
, type
, needed
);
597 if (size
== 0) /* no more change possible */
601 /* Fix cell offsets. */
602 layout_fix_offsets(w
);
603 layout_fix_panes(w
, NULL
);
604 notify_window("window-layout-changed", w
);
607 /* Resize a single pane within the layout. */
609 layout_resize_pane(struct window_pane
*wp
, enum layout_type type
, int change
,
612 struct layout_cell
*lc
, *lcparent
;
614 lc
= wp
->layout_cell
;
616 /* Find next parent of the same type. */
617 lcparent
= lc
->parent
;
618 while (lcparent
!= NULL
&& lcparent
->type
!= type
) {
620 lcparent
= lc
->parent
;
622 if (lcparent
== NULL
)
625 /* If this is the last cell, move back one. */
626 if (lc
== TAILQ_LAST(&lcparent
->cells
, layout_cells
))
627 lc
= TAILQ_PREV(lc
, layout_cells
, entry
);
629 layout_resize_layout(wp
->window
, lc
, type
, change
, opposite
);
632 /* Helper function to grow pane. */
634 layout_resize_pane_grow(struct window
*w
, struct layout_cell
*lc
,
635 enum layout_type type
, int needed
, int opposite
)
637 struct layout_cell
*lcadd
, *lcremove
;
640 /* Growing. Always add to the current cell. */
643 /* Look towards the tail for a suitable cell for reduction. */
644 lcremove
= TAILQ_NEXT(lc
, entry
);
645 while (lcremove
!= NULL
) {
646 size
= layout_resize_check(w
, lcremove
, type
);
649 lcremove
= TAILQ_NEXT(lcremove
, entry
);
652 /* If none found, look towards the head. */
653 if (opposite
&& lcremove
== NULL
) {
654 lcremove
= TAILQ_PREV(lc
, layout_cells
, entry
);
655 while (lcremove
!= NULL
) {
656 size
= layout_resize_check(w
, lcremove
, type
);
659 lcremove
= TAILQ_PREV(lcremove
, layout_cells
, entry
);
662 if (lcremove
== NULL
)
665 /* Change the cells. */
666 if (size
> (u_int
) needed
)
668 layout_resize_adjust(w
, lcadd
, type
, size
);
669 layout_resize_adjust(w
, lcremove
, type
, -size
);
673 /* Helper function to shrink pane. */
675 layout_resize_pane_shrink(struct window
*w
, struct layout_cell
*lc
,
676 enum layout_type type
, int needed
)
678 struct layout_cell
*lcadd
, *lcremove
;
681 /* Shrinking. Find cell to remove from by walking towards head. */
684 size
= layout_resize_check(w
, lcremove
, type
);
687 lcremove
= TAILQ_PREV(lcremove
, layout_cells
, entry
);
688 } while (lcremove
!= NULL
);
689 if (lcremove
== NULL
)
692 /* And add onto the next cell (from the original cell). */
693 lcadd
= TAILQ_NEXT(lc
, entry
);
697 /* Change the cells. */
698 if (size
> (u_int
) -needed
)
700 layout_resize_adjust(w
, lcadd
, type
, size
);
701 layout_resize_adjust(w
, lcremove
, type
, -size
);
705 /* Assign window pane to newly split cell. */
707 layout_assign_pane(struct layout_cell
*lc
, struct window_pane
*wp
,
710 layout_make_leaf(lc
, wp
);
712 layout_fix_panes(wp
->window
, wp
);
714 layout_fix_panes(wp
->window
, NULL
);
717 /* Calculate the new pane size for resized parent. */
719 layout_new_pane_size(struct window
*w
, u_int previous
, struct layout_cell
*lc
,
720 enum layout_type type
, u_int size
, u_int count_left
, u_int size_left
)
722 u_int new_size
, min
, max
, available
;
724 /* If this is the last cell, it can take all of the remaining size. */
728 /* How much is available in this parent? */
729 available
= layout_resize_check(w
, lc
, type
);
732 * Work out the minimum size of this cell and the new size
733 * proportionate to the previous size.
735 min
= (PANE_MINIMUM
+ 1) * (count_left
- 1);
736 if (type
== LAYOUT_LEFTRIGHT
) {
737 if (lc
->sx
- available
> min
)
738 min
= lc
->sx
- available
;
739 new_size
= (lc
->sx
* size
) / previous
;
741 if (lc
->sy
- available
> min
)
742 min
= lc
->sy
- available
;
743 new_size
= (lc
->sy
* size
) / previous
;
746 /* Check against the maximum and minimum size. */
747 max
= size_left
- min
;
750 if (new_size
< PANE_MINIMUM
)
751 new_size
= PANE_MINIMUM
;
755 /* Check if the cell and all its children can be resized to a specific size. */
757 layout_set_size_check(struct window
*w
, struct layout_cell
*lc
,
758 enum layout_type type
, int size
)
760 struct layout_cell
*lcchild
;
761 u_int new_size
, available
, previous
, count
, idx
;
763 /* Cells with no children must just be bigger than minimum. */
764 if (lc
->type
== LAYOUT_WINDOWPANE
)
765 return (size
>= PANE_MINIMUM
);
768 /* Count number of children. */
770 TAILQ_FOREACH(lcchild
, &lc
->cells
, entry
)
773 /* Check new size will work for each child. */
774 if (lc
->type
== type
) {
775 if (available
< (count
* 2) - 1)
778 if (type
== LAYOUT_LEFTRIGHT
)
784 TAILQ_FOREACH(lcchild
, &lc
->cells
, entry
) {
785 new_size
= layout_new_pane_size(w
, previous
, lcchild
,
786 type
, size
, count
- idx
, available
);
787 if (idx
== count
- 1) {
788 if (new_size
> available
)
790 available
-= new_size
;
792 if (new_size
+ 1 > available
)
794 available
-= new_size
+ 1;
796 if (!layout_set_size_check(w
, lcchild
, type
, new_size
))
801 TAILQ_FOREACH(lcchild
, &lc
->cells
, entry
) {
802 if (lcchild
->type
== LAYOUT_WINDOWPANE
)
804 if (!layout_set_size_check(w
, lcchild
, type
, size
))
812 /* Resize all child cells to fit within the current cell. */
814 layout_resize_child_cells(struct window
*w
, struct layout_cell
*lc
)
816 struct layout_cell
*lcchild
;
817 u_int previous
, available
, count
, idx
;
819 if (lc
->type
== LAYOUT_WINDOWPANE
)
822 /* What is the current size used? */
825 TAILQ_FOREACH(lcchild
, &lc
->cells
, entry
) {
827 if (lc
->type
== LAYOUT_LEFTRIGHT
)
828 previous
+= lcchild
->sx
;
829 else if (lc
->type
== LAYOUT_TOPBOTTOM
)
830 previous
+= lcchild
->sy
;
832 previous
+= (count
- 1);
834 /* And how much is available? */
836 if (lc
->type
== LAYOUT_LEFTRIGHT
)
838 else if (lc
->type
== LAYOUT_TOPBOTTOM
)
841 /* Resize children into the new size. */
843 TAILQ_FOREACH(lcchild
, &lc
->cells
, entry
) {
844 if (lc
->type
== LAYOUT_TOPBOTTOM
) {
845 lcchild
->sx
= lc
->sx
;
846 lcchild
->xoff
= lc
->xoff
;
848 lcchild
->sx
= layout_new_pane_size(w
, previous
, lcchild
,
849 lc
->type
, lc
->sx
, count
- idx
, available
);
850 available
-= (lcchild
->sx
+ 1);
852 if (lc
->type
== LAYOUT_LEFTRIGHT
)
853 lcchild
->sy
= lc
->sy
;
855 lcchild
->sy
= layout_new_pane_size(w
, previous
, lcchild
,
856 lc
->type
, lc
->sy
, count
- idx
, available
);
857 available
-= (lcchild
->sy
+ 1);
859 layout_resize_child_cells(w
, lcchild
);
865 * Split a pane into two. size is a hint, or -1 for default half/half
866 * split. This must be followed by layout_assign_pane before much else happens!
869 layout_split_pane(struct window_pane
*wp
, enum layout_type type
, int size
,
872 struct layout_cell
*lc
, *lcparent
, *lcnew
, *lc1
, *lc2
;
873 u_int sx
, sy
, xoff
, yoff
, size1
, size2
, minimum
;
874 u_int new_size
, saved_size
, resize_first
= 0;
875 int full_size
= (flags
& SPAWN_FULLSIZE
), status
;
878 * If full_size is specified, add a new cell at the top of the window
879 * layout. Otherwise, split the cell for the current pane.
882 lc
= wp
->window
->layout_root
;
884 lc
= wp
->layout_cell
;
885 status
= options_get_number(wp
->window
->options
, "pane-border-status");
887 /* Copy the old cell size. */
893 /* Check there is enough space for the two new panes. */
895 case LAYOUT_LEFTRIGHT
:
896 if (sx
< PANE_MINIMUM
* 2 + 1)
899 case LAYOUT_TOPBOTTOM
:
900 if (layout_add_border(wp
->window
, lc
, status
))
901 minimum
= PANE_MINIMUM
* 2 + 2;
903 minimum
= PANE_MINIMUM
* 2 + 1;
908 fatalx("bad layout type");
912 * Calculate new cell sizes. size is the target size or -1 for middle
913 * split, size1 is the size of the top/left and size2 the bottom/right.
915 if (type
== LAYOUT_LEFTRIGHT
)
920 size2
= ((saved_size
+ 1) / 2) - 1;
921 else if (flags
& SPAWN_BEFORE
)
922 size2
= saved_size
- size
- 1;
925 if (size2
< PANE_MINIMUM
)
926 size2
= PANE_MINIMUM
;
927 else if (size2
> saved_size
- 2)
928 size2
= saved_size
- 2;
929 size1
= saved_size
- 1 - size2
;
931 /* Which size are we using? */
932 if (flags
& SPAWN_BEFORE
)
937 /* Confirm there is enough space for full size pane. */
938 if (full_size
&& !layout_set_size_check(wp
->window
, lc
, type
, new_size
))
941 if (lc
->parent
!= NULL
&& lc
->parent
->type
== type
) {
943 * If the parent exists and is of the same type as the split,
944 * create a new cell and insert it after this one.
946 lcparent
= lc
->parent
;
947 lcnew
= layout_create_cell(lcparent
);
948 if (flags
& SPAWN_BEFORE
)
949 TAILQ_INSERT_BEFORE(lc
, lcnew
, entry
);
951 TAILQ_INSERT_AFTER(&lcparent
->cells
, lc
, lcnew
, entry
);
952 } else if (full_size
&& lc
->parent
== NULL
&& lc
->type
== type
) {
954 * If the new full size pane is the same type as the root
955 * split, insert the new pane under the existing root cell
956 * instead of creating a new root cell. The existing layout
957 * must be resized before inserting the new cell.
959 if (lc
->type
== LAYOUT_LEFTRIGHT
) {
961 layout_resize_child_cells(wp
->window
, lc
);
963 } else if (lc
->type
== LAYOUT_TOPBOTTOM
) {
965 layout_resize_child_cells(wp
->window
, lc
);
970 /* Create the new cell. */
971 lcnew
= layout_create_cell(lc
);
972 size
= saved_size
- 1 - new_size
;
973 if (lc
->type
== LAYOUT_LEFTRIGHT
)
974 layout_set_size(lcnew
, size
, sy
, 0, 0);
975 else if (lc
->type
== LAYOUT_TOPBOTTOM
)
976 layout_set_size(lcnew
, sx
, size
, 0, 0);
977 if (flags
& SPAWN_BEFORE
)
978 TAILQ_INSERT_HEAD(&lc
->cells
, lcnew
, entry
);
980 TAILQ_INSERT_TAIL(&lc
->cells
, lcnew
, entry
);
983 * Otherwise create a new parent and insert it.
986 /* Create and insert the replacement parent. */
987 lcparent
= layout_create_cell(lc
->parent
);
988 layout_make_node(lcparent
, type
);
989 layout_set_size(lcparent
, sx
, sy
, xoff
, yoff
);
990 if (lc
->parent
== NULL
)
991 wp
->window
->layout_root
= lcparent
;
993 TAILQ_REPLACE(&lc
->parent
->cells
, lc
, lcparent
, entry
);
995 /* Insert the old cell. */
996 lc
->parent
= lcparent
;
997 TAILQ_INSERT_HEAD(&lcparent
->cells
, lc
, entry
);
999 /* Create the new child cell. */
1000 lcnew
= layout_create_cell(lcparent
);
1001 if (flags
& SPAWN_BEFORE
)
1002 TAILQ_INSERT_HEAD(&lcparent
->cells
, lcnew
, entry
);
1004 TAILQ_INSERT_TAIL(&lcparent
->cells
, lcnew
, entry
);
1006 if (flags
& SPAWN_BEFORE
) {
1015 * Set new cell sizes. size1 is the size of the top/left and size2 the
1018 if (!resize_first
&& type
== LAYOUT_LEFTRIGHT
) {
1019 layout_set_size(lc1
, size1
, sy
, xoff
, yoff
);
1020 layout_set_size(lc2
, size2
, sy
, xoff
+ lc1
->sx
+ 1, yoff
);
1021 } else if (!resize_first
&& type
== LAYOUT_TOPBOTTOM
) {
1022 layout_set_size(lc1
, sx
, size1
, xoff
, yoff
);
1023 layout_set_size(lc2
, sx
, size2
, xoff
, yoff
+ lc1
->sy
+ 1);
1027 layout_resize_child_cells(wp
->window
, lc
);
1028 layout_fix_offsets(wp
->window
);
1030 layout_make_leaf(lc
, wp
);
1035 /* Destroy the cell associated with a pane. */
1037 layout_close_pane(struct window_pane
*wp
)
1039 struct window
*w
= wp
->window
;
1041 /* Remove the cell. */
1042 layout_destroy_cell(w
, wp
->layout_cell
, &w
->layout_root
);
1044 /* Fix pane offsets and sizes. */
1045 if (w
->layout_root
!= NULL
) {
1046 layout_fix_offsets(w
);
1047 layout_fix_panes(w
, NULL
);
1049 notify_window("window-layout-changed", w
);
1053 layout_spread_cell(struct window
*w
, struct layout_cell
*parent
)
1055 struct layout_cell
*lc
;
1056 u_int number
, each
, size
, this;
1057 int change
, changed
, status
;
1060 TAILQ_FOREACH (lc
, &parent
->cells
, entry
)
1064 status
= options_get_number(w
->options
, "pane-border-status");
1066 if (parent
->type
== LAYOUT_LEFTRIGHT
)
1068 else if (parent
->type
== LAYOUT_TOPBOTTOM
) {
1069 if (layout_add_border(w
, parent
, status
))
1070 size
= parent
->sy
- 1;
1075 if (size
< number
- 1)
1077 each
= (size
- (number
- 1)) / number
;
1082 TAILQ_FOREACH (lc
, &parent
->cells
, entry
) {
1083 if (TAILQ_NEXT(lc
, entry
) == NULL
)
1084 each
= size
- ((each
+ 1) * (number
- 1));
1086 if (parent
->type
== LAYOUT_LEFTRIGHT
) {
1087 change
= each
- (int)lc
->sx
;
1088 layout_resize_adjust(w
, lc
, LAYOUT_LEFTRIGHT
, change
);
1089 } else if (parent
->type
== LAYOUT_TOPBOTTOM
) {
1090 if (layout_add_border(w
, lc
, status
))
1094 change
= this - (int)lc
->sy
;
1095 layout_resize_adjust(w
, lc
, LAYOUT_TOPBOTTOM
, change
);
1104 layout_spread_out(struct window_pane
*wp
)
1106 struct layout_cell
*parent
;
1107 struct window
*w
= wp
->window
;
1109 parent
= wp
->layout_cell
->parent
;
1114 if (layout_spread_cell(w
, parent
)) {
1115 layout_fix_offsets(w
);
1116 layout_fix_panes(w
, NULL
);
1119 } while ((parent
= parent
->parent
) != NULL
);