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-set.c
Go to the documentation of this file.
1 /* $OpenBSD$ */
2 
3 /*
4  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
5  *
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.
9  *
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.
17  */
18 
19 #include <sys/types.h>
20 
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include "tmux.h"
25 
26 /*
27  * Set window layouts - predefined methods to arrange windows. These are
28  * one-off and generate a layout tree.
29  */
30 
31 static void layout_set_even_h(struct window *);
32 static void layout_set_even_v(struct window *);
33 static void layout_set_main_h(struct window *);
34 static void layout_set_main_v(struct window *);
35 static void layout_set_tiled(struct window *);
36 
37 static const struct {
38  const char *name;
39  void (*arrange)(struct window *);
40 } layout_sets[] = {
41  { "even-horizontal", layout_set_even_h },
42  { "even-vertical", layout_set_even_v },
43  { "main-horizontal", layout_set_main_h },
44  { "main-vertical", layout_set_main_v },
45  { "tiled", layout_set_tiled },
46 };
47 
48 int
49 layout_set_lookup(const char *name)
50 {
51  u_int i;
52  int matched = -1;
53 
54  for (i = 0; i < nitems(layout_sets); i++) {
55  if (strncmp(layout_sets[i].name, name, strlen(name)) == 0) {
56  if (matched != -1) /* ambiguous */
57  return (-1);
58  matched = i;
59  }
60  }
61 
62  return (matched);
63 }
64 
65 u_int
66 layout_set_select(struct window *w, u_int layout)
67 {
68  if (layout > nitems(layout_sets) - 1)
69  layout = nitems(layout_sets) - 1;
70 
71  if (layout_sets[layout].arrange != NULL)
72  layout_sets[layout].arrange(w);
73 
74  w->lastlayout = layout;
75  return (layout);
76 }
77 
78 u_int
80 {
81  u_int layout;
82 
83  if (w->lastlayout == -1)
84  layout = 0;
85  else {
86  layout = w->lastlayout + 1;
87  if (layout > nitems(layout_sets) - 1)
88  layout = 0;
89  }
90 
91  if (layout_sets[layout].arrange != NULL)
92  layout_sets[layout].arrange(w);
93  w->lastlayout = layout;
94  return (layout);
95 }
96 
97 u_int
99 {
100  u_int layout;
101 
102  if (w->lastlayout == -1)
103  layout = nitems(layout_sets) - 1;
104  else {
105  layout = w->lastlayout;
106  if (layout == 0)
107  layout = nitems(layout_sets) - 1;
108  else
109  layout--;
110  }
111 
112  if (layout_sets[layout].arrange != NULL)
113  layout_sets[layout].arrange(w);
114  w->lastlayout = layout;
115  return (layout);
116 }
117 
118 static void
119 layout_set_even(struct window *w, enum layout_type type)
120 {
121  struct window_pane *wp;
122  struct layout_cell *lc, *lcnew;
123  u_int n, sx, sy;
124 
125  layout_print_cell(w->layout_root, __func__, 1);
126 
127  /* Get number of panes. */
128  n = window_count_panes(w);
129  if (n <= 1)
130  return;
131 
132  /* Free the old root and construct a new. */
133  layout_free(w);
134  lc = w->layout_root = layout_create_cell(NULL);
135  if (type == LAYOUT_LEFTRIGHT) {
136  sx = (n * (PANE_MINIMUM + 1)) - 1;
137  if (sx < w->sx)
138  sx = w->sx;
139  sy = w->sy;
140  } else {
141  sy = (n * (PANE_MINIMUM + 1)) - 1;
142  if (sy < w->sy)
143  sy = w->sy;
144  sx = w->sx;
145  }
146  layout_set_size(lc, sx, sy, 0, 0);
147  layout_make_node(lc, type);
148 
149  /* Build new leaf cells. */
150  TAILQ_FOREACH(wp, &w->panes, entry) {
151  lcnew = layout_create_cell(lc);
152  layout_make_leaf(lcnew, wp);
153  lcnew->sx = w->sx;
154  lcnew->sy = w->sy;
155  TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
156  }
157 
158  /* Spread out cells. */
159  layout_spread_cell(w, lc);
160 
161  /* Fix cell offsets. */
163  layout_fix_panes(w, NULL);
164 
165  layout_print_cell(w->layout_root, __func__, 1);
166 
167  window_resize(w, lc->sx, lc->sy, -1, -1);
168  notify_window("window-layout-changed", w);
170 }
171 
172 static void
174 {
176 }
177 
178 static void
180 {
182 }
183 
184 static void
186 {
187  struct window_pane *wp;
188  struct layout_cell *lc, *lcmain, *lcother, *lcchild;
189  u_int n, mainh, otherh, sx, sy;
190  char *cause;
191  const char *s;
192 
193  layout_print_cell(w->layout_root, __func__, 1);
194 
195  /* Get number of panes. */
196  n = window_count_panes(w);
197  if (n <= 1)
198  return;
199  n--; /* take off main pane */
200 
201  /* Find available height - take off one line for the border. */
202  sy = w->sy - 1;
203 
204  /* Get the main pane height. */
205  s = options_get_string(w->options, "main-pane-height");
206  mainh = args_string_percentage(s, 0, sy, sy, &cause);
207  if (cause != NULL) {
208  mainh = 24;
209  free(cause);
210  }
211 
212  /* Work out the other pane height. */
213  if (mainh + PANE_MINIMUM >= sy) {
214  if (sy <= PANE_MINIMUM + PANE_MINIMUM)
215  mainh = PANE_MINIMUM;
216  else
217  mainh = sy - PANE_MINIMUM;
218  otherh = PANE_MINIMUM;
219  } else {
220  s = options_get_string(w->options, "other-pane-height");
221  otherh = args_string_percentage(s, 0, sy, sy, &cause);
222  if (cause != NULL || otherh == 0) {
223  otherh = sy - mainh;
224  free(cause);
225  } else if (otherh > sy || sy - otherh < mainh)
226  otherh = sy - mainh;
227  else
228  mainh = sy - otherh;
229  }
230 
231  /* Work out what width is needed. */
232  sx = (n * (PANE_MINIMUM + 1)) - 1;
233  if (sx < w->sx)
234  sx = w->sx;
235 
236  /* Free old tree and create a new root. */
237  layout_free(w);
238  lc = w->layout_root = layout_create_cell(NULL);
239  layout_set_size(lc, sx, mainh + otherh + 1, 0, 0);
241 
242  /* Create the main pane. */
243  lcmain = layout_create_cell(lc);
244  layout_set_size(lcmain, sx, mainh, 0, 0);
245  layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
246  TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
247 
248  /* Create the other pane. */
249  lcother = layout_create_cell(lc);
250  layout_set_size(lcother, sx, otherh, 0, 0);
251  if (n == 1) {
252  wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
253  layout_make_leaf(lcother, wp);
254  TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
255  } else {
257  TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
258 
259  /* Add the remaining panes as children. */
260  TAILQ_FOREACH(wp, &w->panes, entry) {
261  if (wp == TAILQ_FIRST(&w->panes))
262  continue;
263  lcchild = layout_create_cell(lcother);
264  layout_set_size(lcchild, PANE_MINIMUM, otherh, 0, 0);
265  layout_make_leaf(lcchild, wp);
266  TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
267  }
268  layout_spread_cell(w, lcother);
269  }
270 
271  /* Fix cell offsets. */
273  layout_fix_panes(w, NULL);
274 
275  layout_print_cell(w->layout_root, __func__, 1);
276 
277  window_resize(w, lc->sx, lc->sy, -1, -1);
278  notify_window("window-layout-changed", w);
280 }
281 
282 static void
284 {
285  struct window_pane *wp;
286  struct layout_cell *lc, *lcmain, *lcother, *lcchild;
287  u_int n, mainw, otherw, sx, sy;
288  char *cause;
289  const char *s;
290 
291  layout_print_cell(w->layout_root, __func__, 1);
292 
293  /* Get number of panes. */
294  n = window_count_panes(w);
295  if (n <= 1)
296  return;
297  n--; /* take off main pane */
298 
299  /* Find available width - take off one line for the border. */
300  sx = w->sx - 1;
301 
302  /* Get the main pane width. */
303  s = options_get_string(w->options, "main-pane-width");
304  mainw = args_string_percentage(s, 0, sx, sx, &cause);
305  if (cause != NULL) {
306  mainw = 80;
307  free(cause);
308  }
309 
310  /* Work out the other pane width. */
311  if (mainw + PANE_MINIMUM >= sx) {
312  if (sx <= PANE_MINIMUM + PANE_MINIMUM)
313  mainw = PANE_MINIMUM;
314  else
315  mainw = sx - PANE_MINIMUM;
316  otherw = PANE_MINIMUM;
317  } else {
318  s = options_get_string(w->options, "other-pane-width");
319  otherw = args_string_percentage(s, 0, sx, sx, &cause);
320  if (cause != NULL || otherw == 0) {
321  otherw = sx - mainw;
322  free(cause);
323  } else if (otherw > sx || sx - otherw < mainw)
324  otherw = sx - mainw;
325  else
326  mainw = sx - otherw;
327  }
328 
329  /* Work out what height is needed. */
330  sy = (n * (PANE_MINIMUM + 1)) - 1;
331  if (sy < w->sy)
332  sy = w->sy;
333 
334  /* Free old tree and create a new root. */
335  layout_free(w);
336  lc = w->layout_root = layout_create_cell(NULL);
337  layout_set_size(lc, mainw + otherw + 1, sy, 0, 0);
339 
340  /* Create the main pane. */
341  lcmain = layout_create_cell(lc);
342  layout_set_size(lcmain, mainw, sy, 0, 0);
343  layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
344  TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
345 
346  /* Create the other pane. */
347  lcother = layout_create_cell(lc);
348  layout_set_size(lcother, otherw, sy, 0, 0);
349  if (n == 1) {
350  wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
351  layout_make_leaf(lcother, wp);
352  TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
353  } else {
355  TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
356 
357  /* Add the remaining panes as children. */
358  TAILQ_FOREACH(wp, &w->panes, entry) {
359  if (wp == TAILQ_FIRST(&w->panes))
360  continue;
361  lcchild = layout_create_cell(lcother);
362  layout_set_size(lcchild, otherw, PANE_MINIMUM, 0, 0);
363  layout_make_leaf(lcchild, wp);
364  TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
365  }
366  layout_spread_cell(w, lcother);
367  }
368 
369  /* Fix cell offsets. */
371  layout_fix_panes(w, NULL);
372 
373  layout_print_cell(w->layout_root, __func__, 1);
374 
375  window_resize(w, lc->sx, lc->sy, -1, -1);
376  notify_window("window-layout-changed", w);
378 }
379 
380 void
382 {
383  struct window_pane *wp;
384  struct layout_cell *lc, *lcrow, *lcchild;
385  u_int n, width, height, used, sx, sy;
386  u_int i, j, columns, rows;
387 
388  layout_print_cell(w->layout_root, __func__, 1);
389 
390  /* Get number of panes. */
391  n = window_count_panes(w);
392  if (n <= 1)
393  return;
394 
395  /* How many rows and columns are wanted? */
396  rows = columns = 1;
397  while (rows * columns < n) {
398  rows++;
399  if (rows * columns < n)
400  columns++;
401  }
402 
403  /* What width and height should they be? */
404  width = (w->sx - (columns - 1)) / columns;
405  if (width < PANE_MINIMUM)
406  width = PANE_MINIMUM;
407  height = (w->sy - (rows - 1)) / rows;
408  if (height < PANE_MINIMUM)
409  height = PANE_MINIMUM;
410 
411  /* Free old tree and create a new root. */
412  layout_free(w);
413  lc = w->layout_root = layout_create_cell(NULL);
414  sx = ((width + 1) * columns) - 1;
415  if (sx < w->sx)
416  sx = w->sx;
417  sy = ((height + 1) * rows) - 1;
418  if (sy < w->sy)
419  sy = w->sy;
420  layout_set_size(lc, sx, sy, 0, 0);
422 
423  /* Create a grid of the cells. */
424  wp = TAILQ_FIRST(&w->panes);
425  for (j = 0; j < rows; j++) {
426  /* If this is the last cell, all done. */
427  if (wp == NULL)
428  break;
429 
430  /* Create the new row. */
431  lcrow = layout_create_cell(lc);
432  layout_set_size(lcrow, w->sx, height, 0, 0);
433  TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry);
434 
435  /* If only one column, just use the row directly. */
436  if (n - (j * columns) == 1 || columns == 1) {
437  layout_make_leaf(lcrow, wp);
438  wp = TAILQ_NEXT(wp, entry);
439  continue;
440  }
441 
442  /* Add in the columns. */
444  for (i = 0; i < columns; i++) {
445  /* Create and add a pane cell. */
446  lcchild = layout_create_cell(lcrow);
447  layout_set_size(lcchild, width, height, 0, 0);
448  layout_make_leaf(lcchild, wp);
449  TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry);
450 
451  /* Move to the next cell. */
452  if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
453  break;
454  }
455 
456  /*
457  * Adjust the row and columns to fit the full width if
458  * necessary.
459  */
460  if (i == columns)
461  i--;
462  used = ((i + 1) * (width + 1)) - 1;
463  if (w->sx <= used)
464  continue;
465  lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
467  w->sx - used);
468  }
469 
470  /* Adjust the last row height to fit if necessary. */
471  used = (rows * height) + rows - 1;
472  if (w->sy > used) {
473  lcrow = TAILQ_LAST(&lc->cells, layout_cells);
475  w->sy - used);
476  }
477 
478  /* Fix cell offsets. */
480  layout_fix_panes(w, NULL);
481 
482  layout_print_cell(w->layout_root, __func__, 1);
483 
484  window_resize(w, lc->sx, lc->sy, -1, -1);
485  notify_window("window-layout-changed", w);
487 }
long long args_string_percentage(const char *value, long long minval, long long maxval, long long curval, char **cause)
Definition: arguments.c:397
static void layout_set_even_h(struct window *)
Definition: layout-set.c:173
int layout_set_lookup(const char *name)
Definition: layout-set.c:49
void(* arrange)(struct window *)
Definition: layout-set.c:39
static void layout_set_even_v(struct window *)
Definition: layout-set.c:179
static void layout_set_main_h(struct window *)
Definition: layout-set.c:185
static const struct @9 layout_sets[]
static void layout_set_tiled(struct window *)
Definition: layout-set.c:381
const char * name
Definition: layout-set.c:38
static void layout_set_even(struct window *w, enum layout_type type)
Definition: layout-set.c:119
u_int layout_set_next(struct window *w)
Definition: layout-set.c:79
u_int layout_set_previous(struct window *w)
Definition: layout-set.c:98
u_int layout_set_select(struct window *w, u_int layout)
Definition: layout-set.c:66
static void layout_set_main_v(struct window *)
Definition: layout-set.c:283
void layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n)
Definition: layout.c:96
struct layout_cell * layout_create_cell(struct layout_cell *lcparent)
Definition: layout.c:51
void layout_free(struct window *w)
Definition: layout.c:489
void layout_fix_offsets(struct window *w)
Definition: layout.c:231
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
void layout_make_node(struct layout_cell *lc, enum layout_type type)
Definition: layout.c:188
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
void layout_make_leaf(struct layout_cell *lc, struct window_pane *wp)
Definition: layout.c:177
void notify_window(const char *name, struct window *w)
Definition: notify.c:253
const char * options_get_string(struct options *oo, const char *name)
Definition: options.c:686
#define nitems(_a)
void server_redraw_window(struct window *w)
Definition: server-fn.c:94
struct window_pane * wp
Definition: tmux.h:1153
u_int sx
Definition: tmux.h:1147
u_int sy
Definition: tmux.h:1148
enum layout_type type
Definition: tmux.h:1143
struct layout_cells cells
Definition: tmux.h:1154
Definition: tmux.h:1041
int lastlayout
Definition: tmux.h:1058
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
#define PANE_MINIMUM
Definition: tmux.h:80
u_int window_count_panes(struct window *)
Definition: window.c:773
void window_resize(struct window *, u_int, u_int, int, int)
Definition: window.c:409