tmux  3.2a
About: tmux is a terminal multiplexer that lets you switch easily between several programs in one terminal.
  Fossies Dox: tmux-3.2a.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

layout.c
Go to the documentation of this file.
1 /* $OpenBSD$ */
2 
3 /*
4  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
5  * Copyright (c) 2016 Stephen Kent <smkent@smkent.net>
6  *
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.
10  *
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.
18  */
19 
20 #include <sys/types.h>
21 
22 #include <stdlib.h>
23 
24 #include "tmux.h"
25 
26 /*
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.
30  *
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.
34  */
35 
36 static u_int layout_resize_check(struct window *, struct layout_cell *,
37  enum layout_type);
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,
44  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 *);
49 
50 struct layout_cell *
52 {
53  struct layout_cell *lc;
54 
55  lc = xmalloc(sizeof *lc);
56  lc->type = LAYOUT_WINDOWPANE;
57  lc->parent = lcparent;
58 
59  TAILQ_INIT(&lc->cells);
60 
61  lc->sx = UINT_MAX;
62  lc->sy = UINT_MAX;
63 
64  lc->xoff = UINT_MAX;
65  lc->yoff = UINT_MAX;
66 
67  lc->wp = NULL;
68 
69  return (lc);
70 }
71 
72 void
74 {
75  struct layout_cell *lcchild;
76 
77  switch (lc->type) {
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);
84  }
85  break;
86  case LAYOUT_WINDOWPANE:
87  if (lc->wp != NULL)
88  lc->wp->layout_cell = NULL;
89  break;
90  }
91 
92  free(lc);
93 }
94 
95 void
96 layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n)
97 {
98  struct layout_cell *lcchild;
99  const char *type;
100 
101  switch (lc->type) {
102  case LAYOUT_LEFTRIGHT:
103  type = "LEFTRIGHT";
104  break;
105  case LAYOUT_TOPBOTTOM:
106  type = "TOPBOTTOM";
107  break;
108  case LAYOUT_WINDOWPANE:
109  type = "WINDOWPANE";
110  break;
111  default:
112  type = "UNKNOWN";
113  break;
114  }
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,
117  lc->sy);
118  switch (lc->type) {
119  case LAYOUT_LEFTRIGHT:
120  case LAYOUT_TOPBOTTOM:
121  TAILQ_FOREACH(lcchild, &lc->cells, entry)
122  layout_print_cell(lcchild, hdr, n + 1);
123  break;
124  case LAYOUT_WINDOWPANE:
125  break;
126  }
127 }
128 
129 struct layout_cell *
130 layout_search_by_border(struct layout_cell *lc, u_int x, u_int y)
131 {
132  struct layout_cell *lcchild, *last = NULL;
133 
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));
139  }
140 
141  if (last == NULL) {
142  last = lcchild;
143  continue;
144  }
145 
146  switch (lc->type) {
147  case LAYOUT_LEFTRIGHT:
148  if (x < lcchild->xoff && x >= last->xoff + last->sx)
149  return (last);
150  break;
151  case LAYOUT_TOPBOTTOM:
152  if (y < lcchild->yoff && y >= last->yoff + last->sy)
153  return (last);
154  break;
155  case LAYOUT_WINDOWPANE:
156  break;
157  }
158 
159  last = lcchild;
160  }
161 
162  return (NULL);
163 }
164 
165 void
166 layout_set_size(struct layout_cell *lc, u_int sx, u_int sy, u_int xoff,
167  u_int yoff)
168 {
169  lc->sx = sx;
170  lc->sy = sy;
171 
172  lc->xoff = xoff;
173  lc->yoff = yoff;
174 }
175 
176 void
178 {
179  lc->type = LAYOUT_WINDOWPANE;
180 
181  TAILQ_INIT(&lc->cells);
182 
183  wp->layout_cell = lc;
184  lc->wp = wp;
185 }
186 
187 void
189 {
190  if (type == LAYOUT_WINDOWPANE)
191  fatalx("bad layout type");
192  lc->type = type;
193 
194  TAILQ_INIT(&lc->cells);
195 
196  if (lc->wp != NULL)
197  lc->wp->layout_cell = NULL;
198  lc->wp = NULL;
199 }
200 
201 /* Fix cell offsets for a child cell. */
202 static void
204 {
205  struct layout_cell *lcchild;
206  u_int xoff, yoff;
207 
208  if (lc->type == LAYOUT_LEFTRIGHT) {
209  xoff = lc->xoff;
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;
216  }
217  } else {
218  yoff = lc->yoff;
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;
225  }
226  }
227 }
228 
229 /* Update cell offsets based on their sizes. */
230 void
232 {
233  struct layout_cell *lc = w->layout_root;
234 
235  lc->xoff = 0;
236  lc->yoff = 0;
237 
239 }
240 
241 /* Is this a top cell? */
242 static int
243 layout_cell_is_top(struct window *w, struct layout_cell *lc)
244 {
245  struct layout_cell *next;
246 
247  while (lc != w->layout_root) {
248  next = lc->parent;
249  if (next->type == LAYOUT_TOPBOTTOM &&
250  lc != TAILQ_FIRST(&next->cells))
251  return (0);
252  lc = next;
253  }
254  return (1);
255 }
256 
257 /* Is this a bottom cell? */
258 static int
260 {
261  struct layout_cell *next;
262 
263  while (lc != w->layout_root) {
264  next = lc->parent;
265  if (next->type == LAYOUT_TOPBOTTOM &&
266  lc != TAILQ_LAST(&next->cells, layout_cells))
267  return (0);
268  lc = next;
269  }
270  return (1);
271 }
272 
273 /*
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.
276  */
277 static int
278 layout_add_border(struct window *w, struct layout_cell *lc, int status)
279 {
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));
284  return (0);
285 }
286 
287 /* Update pane offsets and sizes based on their cells. */
288 void
289 layout_fix_panes(struct window *w, struct window_pane *skip)
290 {
291  struct window_pane *wp;
292  struct layout_cell *lc;
293  int status;
294 
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)
298  continue;
299 
300  wp->xoff = lc->xoff;
301  wp->yoff = lc->yoff;
302 
303  if (layout_add_border(w, lc, status)) {
304  if (status == PANE_STATUS_TOP)
305  wp->yoff++;
306  window_pane_resize(wp, lc->sx, lc->sy - 1);
307  } else
308  window_pane_resize(wp, lc->sx, lc->sy);
309  }
310 }
311 
312 /* Count the number of available cells in a layout. */
313 u_int
315 {
316  struct layout_cell *lcchild;
317  u_int count;
318 
319  switch (lc->type) {
320  case LAYOUT_WINDOWPANE:
321  return (1);
322  case LAYOUT_LEFTRIGHT:
323  case LAYOUT_TOPBOTTOM:
324  count = 0;
325  TAILQ_FOREACH(lcchild, &lc->cells, entry)
326  count += layout_count_cells(lcchild);
327  return (count);
328  default:
329  fatalx("bad layout type");
330  }
331 }
332 
333 /* Calculate how much size is available to be removed from a cell. */
334 static u_int
335 layout_resize_check(struct window *w, struct layout_cell *lc,
336  enum layout_type type)
337 {
338  struct layout_cell *lcchild;
339  u_int available, minimum;
340  int status;
341 
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) {
346  available = lc->sx;
347  minimum = PANE_MINIMUM;
348  } else {
349  available = lc->sy;
350  if (layout_add_border(w, lc, status))
351  minimum = PANE_MINIMUM + 1;
352  else
353  minimum = PANE_MINIMUM;
354  }
355  if (available > minimum)
356  available -= minimum;
357  else
358  available = 0;
359  } else if (lc->type == type) {
360  /* Same type: total of available space in all child cells. */
361  available = 0;
362  TAILQ_FOREACH(lcchild, &lc->cells, entry)
363  available += layout_resize_check(w, lcchild, type);
364  } else {
365  /* Different type: minimum of available space in child cells. */
366  minimum = UINT_MAX;
367  TAILQ_FOREACH(lcchild, &lc->cells, entry) {
368  available = layout_resize_check(w, lcchild, type);
369  if (available < minimum)
370  minimum = available;
371  }
372  available = minimum;
373  }
374 
375  return (available);
376 }
377 
378 /*
379  * Adjust cell size evenly, including altering its children. This function
380  * expects the change to have already been bounded to the space available.
381  */
382 void
384  enum layout_type type, int change)
385 {
386  struct layout_cell *lcchild;
387 
388  /* Adjust the cell size. */
389  if (type == LAYOUT_LEFTRIGHT)
390  lc->sx += change;
391  else
392  lc->sy += change;
393 
394  /* If this is a leaf cell, that is all that is necessary. */
395  if (type == LAYOUT_WINDOWPANE)
396  return;
397 
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);
402  return;
403  }
404 
405  /*
406  * Child cell runs in the same direction. Adjust each child equally
407  * until no further change is possible.
408  */
409  while (change != 0) {
410  TAILQ_FOREACH(lcchild, &lc->cells, entry) {
411  if (change == 0)
412  break;
413  if (change > 0) {
414  layout_resize_adjust(w, lcchild, type, 1);
415  change--;
416  continue;
417  }
418  if (layout_resize_check(w, lcchild, type) > 0) {
419  layout_resize_adjust(w, lcchild, type, -1);
420  change++;
421  }
422  }
423  }
424 }
425 
426 /* Destroy a cell and redistribute the space. */
427 void
428 layout_destroy_cell(struct window *w, struct layout_cell *lc,
429  struct layout_cell **lcroot)
430 {
431  struct layout_cell *lcother, *lcparent;
432 
433  /*
434  * If no parent, this is the last pane so window close is imminent and
435  * there is no need to resize anything.
436  */
437  lcparent = lc->parent;
438  if (lcparent == NULL) {
439  layout_free_cell(lc);
440  *lcroot = NULL;
441  return;
442  }
443 
444  /* Merge the space into the previous or next cell. */
445  if (lc == TAILQ_FIRST(&lcparent->cells))
446  lcother = TAILQ_NEXT(lc, entry);
447  else
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);
453 
454  /* Remove this from the parent's list. */
455  TAILQ_REMOVE(&lcparent->cells, lc, entry);
456  layout_free_cell(lc);
457 
458  /*
459  * If the parent now has one cell, remove the parent from the tree and
460  * replace it by that cell.
461  */
462  lc = TAILQ_FIRST(&lcparent->cells);
463  if (TAILQ_NEXT(lc, entry) == NULL) {
464  TAILQ_REMOVE(&lcparent->cells, lc, entry);
465 
466  lc->parent = lcparent->parent;
467  if (lc->parent == NULL) {
468  lc->xoff = 0; lc->yoff = 0;
469  *lcroot = lc;
470  } else
471  TAILQ_REPLACE(&lc->parent->cells, lcparent, lc, entry);
472 
473  layout_free_cell(lcparent);
474  }
475 }
476 
477 void
478 layout_init(struct window *w, struct window_pane *wp)
479 {
480  struct layout_cell *lc;
481 
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);
486 }
487 
488 void
489 layout_free(struct window *w)
490 {
492 }
493 
494 /* Resize the entire layout after window resize. */
495 void
496 layout_resize(struct window *w, u_int sx, u_int sy)
497 {
498  struct layout_cell *lc = w->layout_root;
499  int xlimit, ylimit, xchange, ychange;
500 
501  /*
502  * Adjust horizontally. Do not attempt to reduce the layout lower than
503  * the minimum (more than the amount returned by layout_resize_check).
504  *
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
512  * window size.
513  */
514  xchange = sx - lc->sx;
515  xlimit = layout_resize_check(w, lc, LAYOUT_LEFTRIGHT);
516  if (xchange < 0 && xchange < -xlimit)
517  xchange = -xlimit;
518  if (xlimit == 0) {
519  if (sx <= lc->sx) /* lc->sx is minimum possible */
520  xchange = 0;
521  else
522  xchange = sx - lc->sx;
523  }
524  if (xchange != 0)
525  layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT, xchange);
526 
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)
531  ychange = -ylimit;
532  if (ylimit == 0) {
533  if (sy <= lc->sy) /* lc->sy is minimum possible */
534  ychange = 0;
535  else
536  ychange = sy - lc->sy;
537  }
538  if (ychange != 0)
539  layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM, ychange);
540 
541  /* Fix cell offsets. */
543  layout_fix_panes(w, NULL);
544 }
545 
546 /* Resize a pane to an absolute size. */
547 void
549  u_int new_size)
550 {
551  struct layout_cell *lc, *lcparent;
552  int change, size;
553 
554  lc = wp->layout_cell;
555 
556  /* Find next parent of the same type. */
557  lcparent = lc->parent;
558  while (lcparent != NULL && lcparent->type != type) {
559  lc = lcparent;
560  lcparent = lc->parent;
561  }
562  if (lcparent == NULL)
563  return;
564 
565  /* Work out the size adjustment. */
566  if (type == LAYOUT_LEFTRIGHT)
567  size = lc->sx;
568  else
569  size = lc->sy;
570  if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
571  change = size - new_size;
572  else
573  change = new_size - size;
574 
575  /* Resize the pane. */
576  layout_resize_pane(wp, type, change, 1);
577 }
578 
579 void
581  enum layout_type type, int change, int opposite)
582 {
583  int needed, size;
584 
585  /* Grow or shrink the cell. */
586  needed = change;
587  while (needed != 0) {
588  if (change > 0) {
589  size = layout_resize_pane_grow(w, lc, type, needed,
590  opposite);
591  needed -= size;
592  } else {
593  size = layout_resize_pane_shrink(w, lc, type, needed);
594  needed += size;
595  }
596 
597  if (size == 0) /* no more change possible */
598  break;
599  }
600 
601  /* Fix cell offsets. */
603  layout_fix_panes(w, NULL);
604  notify_window("window-layout-changed", w);
605 }
606 
607 /* Resize a single pane within the layout. */
608 void
610  int opposite)
611 {
612  struct layout_cell *lc, *lcparent;
613 
614  lc = wp->layout_cell;
615 
616  /* Find next parent of the same type. */
617  lcparent = lc->parent;
618  while (lcparent != NULL && lcparent->type != type) {
619  lc = lcparent;
620  lcparent = lc->parent;
621  }
622  if (lcparent == NULL)
623  return;
624 
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);
628 
629  layout_resize_layout(wp->window, lc, type, change, opposite);
630 }
631 
632 /* Helper function to grow pane. */
633 static int
635  enum layout_type type, int needed, int opposite)
636 {
637  struct layout_cell *lcadd, *lcremove;
638  u_int size = 0;
639 
640  /* Growing. Always add to the current cell. */
641  lcadd = lc;
642 
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);
647  if (size > 0)
648  break;
649  lcremove = TAILQ_NEXT(lcremove, entry);
650  }
651 
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);
657  if (size > 0)
658  break;
659  lcremove = TAILQ_PREV(lcremove, layout_cells, entry);
660  }
661  }
662  if (lcremove == NULL)
663  return (0);
664 
665  /* Change the cells. */
666  if (size > (u_int) needed)
667  size = needed;
668  layout_resize_adjust(w, lcadd, type, size);
669  layout_resize_adjust(w, lcremove, type, -size);
670  return (size);
671 }
672 
673 /* Helper function to shrink pane. */
674 static int
676  enum layout_type type, int needed)
677 {
678  struct layout_cell *lcadd, *lcremove;
679  u_int size;
680 
681  /* Shrinking. Find cell to remove from by walking towards head. */
682  lcremove = lc;
683  do {
684  size = layout_resize_check(w, lcremove, type);
685  if (size != 0)
686  break;
687  lcremove = TAILQ_PREV(lcremove, layout_cells, entry);
688  } while (lcremove != NULL);
689  if (lcremove == NULL)
690  return (0);
691 
692  /* And add onto the next cell (from the original cell). */
693  lcadd = TAILQ_NEXT(lc, entry);
694  if (lcadd == NULL)
695  return (0);
696 
697  /* Change the cells. */
698  if (size > (u_int) -needed)
699  size = -needed;
700  layout_resize_adjust(w, lcadd, type, size);
701  layout_resize_adjust(w, lcremove, type, -size);
702  return (size);
703 }
704 
705 /* Assign window pane to newly split cell. */
706 void
708  int do_not_resize)
709 {
710  layout_make_leaf(lc, wp);
711  if (do_not_resize)
713  else
714  layout_fix_panes(wp->window, NULL);
715 }
716 
717 /* Calculate the new pane size for resized parent. */
718 static u_int
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)
721 {
722  u_int new_size, min, max, available;
723 
724  /* If this is the last cell, it can take all of the remaining size. */
725  if (count_left == 1)
726  return (size_left);
727 
728  /* How much is available in this parent? */
729  available = layout_resize_check(w, lc, type);
730 
731  /*
732  * Work out the minimum size of this cell and the new size
733  * proportionate to the previous size.
734  */
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;
740  } else {
741  if (lc->sy - available > min)
742  min = lc->sy - available;
743  new_size = (lc->sy * size) / previous;
744  }
745 
746  /* Check against the maximum and minimum size. */
747  max = size_left - min;
748  if (new_size > max)
749  new_size = max;
750  if (new_size < PANE_MINIMUM)
751  new_size = PANE_MINIMUM;
752  return (new_size);
753 }
754 
755 /* Check if the cell and all its children can be resized to a specific size. */
756 static int
758  enum layout_type type, int size)
759 {
760  struct layout_cell *lcchild;
761  u_int new_size, available, previous, count, idx;
762 
763  /* Cells with no children must just be bigger than minimum. */
764  if (lc->type == LAYOUT_WINDOWPANE)
765  return (size >= PANE_MINIMUM);
766  available = size;
767 
768  /* Count number of children. */
769  count = 0;
770  TAILQ_FOREACH(lcchild, &lc->cells, entry)
771  count++;
772 
773  /* Check new size will work for each child. */
774  if (lc->type == type) {
775  if (available < (count * 2) - 1)
776  return (0);
777 
778  if (type == LAYOUT_LEFTRIGHT)
779  previous = lc->sx;
780  else
781  previous = lc->sy;
782 
783  idx = 0;
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)
789  return (0);
790  available -= new_size;
791  } else {
792  if (new_size + 1 > available)
793  return (0);
794  available -= new_size + 1;
795  }
796  if (!layout_set_size_check(w, lcchild, type, new_size))
797  return (0);
798  idx++;
799  }
800  } else {
801  TAILQ_FOREACH(lcchild, &lc->cells, entry) {
802  if (lcchild->type == LAYOUT_WINDOWPANE)
803  continue;
804  if (!layout_set_size_check(w, lcchild, type, size))
805  return (0);
806  }
807  }
808 
809  return (1);
810 }
811 
812 /* Resize all child cells to fit within the current cell. */
813 static void
815 {
816  struct layout_cell *lcchild;
817  u_int previous, available, count, idx;
818 
819  if (lc->type == LAYOUT_WINDOWPANE)
820  return;
821 
822  /* What is the current size used? */
823  count = 0;
824  previous = 0;
825  TAILQ_FOREACH(lcchild, &lc->cells, entry) {
826  count++;
827  if (lc->type == LAYOUT_LEFTRIGHT)
828  previous += lcchild->sx;
829  else if (lc->type == LAYOUT_TOPBOTTOM)
830  previous += lcchild->sy;
831  }
832  previous += (count - 1);
833 
834  /* And how much is available? */
835  available = 0;
836  if (lc->type == LAYOUT_LEFTRIGHT)
837  available = lc->sx;
838  else if (lc->type == LAYOUT_TOPBOTTOM)
839  available = lc->sy;
840 
841  /* Resize children into the new size. */
842  idx = 0;
843  TAILQ_FOREACH(lcchild, &lc->cells, entry) {
844  if (lc->type == LAYOUT_TOPBOTTOM) {
845  lcchild->sx = lc->sx;
846  lcchild->xoff = lc->xoff;
847  } else {
848  lcchild->sx = layout_new_pane_size(w, previous, lcchild,
849  lc->type, lc->sx, count - idx, available);
850  available -= (lcchild->sx + 1);
851  }
852  if (lc->type == LAYOUT_LEFTRIGHT)
853  lcchild->sy = lc->sy;
854  else {
855  lcchild->sy = layout_new_pane_size(w, previous, lcchild,
856  lc->type, lc->sy, count - idx, available);
857  available -= (lcchild->sy + 1);
858  }
859  layout_resize_child_cells(w, lcchild);
860  idx++;
861  }
862 }
863 
864 /*
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!
867  */
868 struct layout_cell *
870  int flags)
871 {
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;
876 
877  /*
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.
880  */
881  if (full_size)
882  lc = wp->window->layout_root;
883  else
884  lc = wp->layout_cell;
885  status = options_get_number(wp->window->options, "pane-border-status");
886 
887  /* Copy the old cell size. */
888  sx = lc->sx;
889  sy = lc->sy;
890  xoff = lc->xoff;
891  yoff = lc->yoff;
892 
893  /* Check there is enough space for the two new panes. */
894  switch (type) {
895  case LAYOUT_LEFTRIGHT:
896  if (sx < PANE_MINIMUM * 2 + 1)
897  return (NULL);
898  break;
899  case LAYOUT_TOPBOTTOM:
900  if (layout_add_border(wp->window, lc, status))
901  minimum = PANE_MINIMUM * 2 + 2;
902  else
903  minimum = PANE_MINIMUM * 2 + 1;
904  if (sy < minimum)
905  return (NULL);
906  break;
907  default:
908  fatalx("bad layout type");
909  }
910 
911  /*
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.
914  */
915  if (type == LAYOUT_LEFTRIGHT)
916  saved_size = sx;
917  else
918  saved_size = sy;
919  if (size < 0)
920  size2 = ((saved_size + 1) / 2) - 1;
921  else if (flags & SPAWN_BEFORE)
922  size2 = saved_size - size - 1;
923  else
924  size2 = size;
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;
930 
931  /* Which size are we using? */
932  if (flags & SPAWN_BEFORE)
933  new_size = size2;
934  else
935  new_size = size1;
936 
937  /* Confirm there is enough space for full size pane. */
938  if (full_size && !layout_set_size_check(wp->window, lc, type, new_size))
939  return (NULL);
940 
941  if (lc->parent != NULL && lc->parent->type == type) {
942  /*
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.
945  */
946  lcparent = lc->parent;
947  lcnew = layout_create_cell(lcparent);
948  if (flags & SPAWN_BEFORE)
949  TAILQ_INSERT_BEFORE(lc, lcnew, entry);
950  else
951  TAILQ_INSERT_AFTER(&lcparent->cells, lc, lcnew, entry);
952  } else if (full_size && lc->parent == NULL && lc->type == type) {
953  /*
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.
958  */
959  if (lc->type == LAYOUT_LEFTRIGHT) {
960  lc->sx = new_size;
962  lc->sx = saved_size;
963  } else if (lc->type == LAYOUT_TOPBOTTOM) {
964  lc->sy = new_size;
966  lc->sy = saved_size;
967  }
968  resize_first = 1;
969 
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);
979  else
980  TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
981  } else {
982  /*
983  * Otherwise create a new parent and insert it.
984  */
985 
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;
992  else
993  TAILQ_REPLACE(&lc->parent->cells, lc, lcparent, entry);
994 
995  /* Insert the old cell. */
996  lc->parent = lcparent;
997  TAILQ_INSERT_HEAD(&lcparent->cells, lc, entry);
998 
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);
1003  else
1004  TAILQ_INSERT_TAIL(&lcparent->cells, lcnew, entry);
1005  }
1006  if (flags & SPAWN_BEFORE) {
1007  lc1 = lcnew;
1008  lc2 = lc;
1009  } else {
1010  lc1 = lc;
1011  lc2 = lcnew;
1012  }
1013 
1014  /*
1015  * Set new cell sizes. size1 is the size of the top/left and size2 the
1016  * bottom/right.
1017  */
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);
1024  }
1025  if (full_size) {
1026  if (!resize_first)
1029  } else
1030  layout_make_leaf(lc, wp);
1031 
1032  return (lcnew);
1033 }
1034 
1035 /* Destroy the cell associated with a pane. */
1036 void
1038 {
1039  struct window *w = wp->window;
1040 
1041  /* Remove the cell. */
1043 
1044  /* Fix pane offsets and sizes. */
1045  if (w->layout_root != NULL) {
1046  layout_fix_offsets(w);
1047  layout_fix_panes(w, NULL);
1048  }
1049  notify_window("window-layout-changed", w);
1050 }
1051 
1052 int
1053 layout_spread_cell(struct window *w, struct layout_cell *parent)
1054 {
1055  struct layout_cell *lc;
1056  u_int number, each, size, this;
1057  int change, changed, status;
1058 
1059  number = 0;
1060  TAILQ_FOREACH (lc, &parent->cells, entry)
1061  number++;
1062  if (number <= 1)
1063  return (0);
1064  status = options_get_number(w->options, "pane-border-status");
1065 
1066  if (parent->type == LAYOUT_LEFTRIGHT)
1067  size = parent->sx;
1068  else if (parent->type == LAYOUT_TOPBOTTOM) {
1069  if (layout_add_border(w, parent, status))
1070  size = parent->sy - 1;
1071  else
1072  size = parent->sy;
1073  } else
1074  return (0);
1075  if (size < number - 1)
1076  return (0);
1077  each = (size - (number - 1)) / number;
1078  if (each == 0)
1079  return (0);
1080 
1081  changed = 0;
1082  TAILQ_FOREACH (lc, &parent->cells, entry) {
1083  if (TAILQ_NEXT(lc, entry) == NULL)
1084  each = size - ((each + 1) * (number - 1));
1085  change = 0;
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))
1091  this = each + 1;
1092  else
1093  this = each;
1094  change = this - (int)lc->sy;
1095  layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM, change);
1096  }
1097  if (change != 0)
1098  changed = 1;
1099  }
1100  return (changed);
1101 }
1102 
1103 void
1105 {
1106  struct layout_cell *parent;
1107  struct window *w = wp->window;
1108 
1109  parent = wp->layout_cell->parent;
1110  if (parent == NULL)
1111  return;
1112 
1113  do {
1114  if (layout_spread_cell(w, parent)) {
1115  layout_fix_offsets(w);
1116  layout_fix_panes(w, NULL);
1117  break;
1118  }
1119  } while ((parent = parent->parent) != NULL);
1120 }
void layout_destroy_cell(struct window *w, struct layout_cell *lc, struct layout_cell **lcroot)
Definition: layout.c:428
void layout_init(struct window *w, struct window_pane *wp)
Definition: layout.c:478
void layout_assign_pane(struct layout_cell *lc, struct window_pane *wp, int do_not_resize)
Definition: layout.c:707
void layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n)
Definition: layout.c:96
static int layout_resize_pane_grow(struct window *, struct layout_cell *, enum layout_type, int, int)
Definition: layout.c:634
void layout_free_cell(struct layout_cell *lc)
Definition: layout.c:73
static u_int layout_new_pane_size(struct window *, u_int, struct layout_cell *, enum layout_type, u_int, u_int, u_int)
Definition: layout.c:719
void layout_resize_layout(struct window *w, struct layout_cell *lc, enum layout_type type, int change, int opposite)
Definition: layout.c:580
static int layout_cell_is_bottom(struct window *w, struct layout_cell *lc)
Definition: layout.c:259
void layout_close_pane(struct window_pane *wp)
Definition: layout.c:1037
static int layout_cell_is_top(struct window *w, struct layout_cell *lc)
Definition: layout.c:243
static int layout_set_size_check(struct window *, struct layout_cell *, enum layout_type, int)
Definition: layout.c:757
void layout_spread_out(struct window_pane *wp)
Definition: layout.c:1104
struct layout_cell * layout_create_cell(struct layout_cell *lcparent)
Definition: layout.c:51
static void layout_fix_offsets1(struct layout_cell *lc)
Definition: layout.c:203
void layout_free(struct window *w)
Definition: layout.c:489
void layout_fix_offsets(struct window *w)
Definition: layout.c:231
static void layout_resize_child_cells(struct window *, struct layout_cell *)
Definition: layout.c:814
void layout_resize(struct window *w, u_int sx, u_int sy)
Definition: layout.c:496
struct layout_cell * layout_search_by_border(struct layout_cell *lc, u_int x, u_int y)
Definition: layout.c:130
static u_int layout_resize_check(struct window *, struct layout_cell *, enum layout_type)
Definition: layout.c:335
void layout_resize_adjust(struct window *w, struct layout_cell *lc, enum layout_type type, int change)
Definition: layout.c:383
void layout_set_size(struct layout_cell *lc, u_int sx, u_int sy, u_int xoff, u_int yoff)
Definition: layout.c:166
static int layout_add_border(struct window *w, struct layout_cell *lc, int status)
Definition: layout.c:278
struct layout_cell * layout_split_pane(struct window_pane *wp, enum layout_type type, int size, int flags)
Definition: layout.c:869
void layout_make_node(struct layout_cell *lc, enum layout_type type)
Definition: layout.c:188
static int layout_resize_pane_shrink(struct window *, struct layout_cell *, enum layout_type, int)
Definition: layout.c:675
int layout_spread_cell(struct window *w, struct layout_cell *parent)
Definition: layout.c:1053
void layout_fix_panes(struct window *w, struct window_pane *skip)
Definition: layout.c:289
u_int layout_count_cells(struct layout_cell *lc)
Definition: layout.c:314
void layout_resize_pane(struct window_pane *wp, enum layout_type type, int change, int opposite)
Definition: layout.c:609
void layout_make_leaf(struct layout_cell *lc, struct window_pane *wp)
Definition: layout.c:177
void layout_resize_pane_to(struct window_pane *wp, enum layout_type type, u_int new_size)
Definition: layout.c:548
void fatalx(const char *msg,...)
Definition: log.c:159
void log_debug(const char *msg,...)
Definition: log.c:130
void notify_window(const char *name, struct window *w)
Definition: notify.c:253
long long options_get_number(struct options *oo, const char *name)
Definition: options.c:699
struct window_pane * wp
Definition: tmux.h:1153
u_int xoff
Definition: tmux.h:1150
u_int sx
Definition: tmux.h:1147
u_int sy
Definition: tmux.h:1148
u_int yoff
Definition: tmux.h:1151
enum layout_type type
Definition: tmux.h:1143
struct layout_cells cells
Definition: tmux.h:1154
struct layout_cell * parent
Definition: tmux.h:1145
u_int xoff
Definition: tmux.h:971
struct layout_cell * layout_cell
Definition: tmux.h:965
u_int yoff
Definition: tmux.h:972
struct window * window
Definition: tmux.h:962
Definition: tmux.h:1041
struct layout_cell * layout_root
Definition: tmux.h:1059
struct options * options
Definition: tmux.h:1085
u_int sx
Definition: tmux.h:1063
struct window_panes panes
Definition: tmux.h:1056
u_int sy
Definition: tmux.h:1064
layout_type
Definition: tmux.h:1132
@ LAYOUT_TOPBOTTOM
Definition: tmux.h:1134
@ LAYOUT_LEFTRIGHT
Definition: tmux.h:1133
@ LAYOUT_WINDOWPANE
Definition: tmux.h:1135
#define PANE_STATUS_BOTTOM
Definition: tmux.h:1122
#define PANE_STATUS_TOP
Definition: tmux.h:1121
void window_pane_resize(struct window_pane *, u_int, u_int)
Definition: window.c:987
#define PANE_MINIMUM
Definition: tmux.h:80
#define SPAWN_BEFORE
Definition: tmux.h:1891
#define SPAWN_FULLSIZE
Definition: tmux.h:1893
void * xmalloc(size_t size)
Definition: xmalloc.c:27