Annotation of embedaddon/tmux/layout-set.c, revision 1.1.1.1
1.1 misho 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 <string.h>
22:
23: #include "tmux.h"
24:
25: /*
26: * Set window layouts - predefined methods to arrange windows. These are
27: * one-off and generate a layout tree.
28: */
29:
30: static void layout_set_even_h(struct window *);
31: static void layout_set_even_v(struct window *);
32: static void layout_set_main_h(struct window *);
33: static void layout_set_main_v(struct window *);
34: static void layout_set_tiled(struct window *);
35:
36: static const struct {
37: const char *name;
38: void (*arrange)(struct window *);
39: } layout_sets[] = {
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 },
45: };
46:
47: int
48: layout_set_lookup(const char *name)
49: {
50: u_int i;
51: int matched = -1;
52:
53: for (i = 0; i < nitems(layout_sets); i++) {
54: if (strncmp(layout_sets[i].name, name, strlen(name)) == 0) {
55: if (matched != -1) /* ambiguous */
56: return (-1);
57: matched = i;
58: }
59: }
60:
61: return (matched);
62: }
63:
64: u_int
65: layout_set_select(struct window *w, u_int layout)
66: {
67: if (layout > nitems(layout_sets) - 1)
68: layout = nitems(layout_sets) - 1;
69:
70: if (layout_sets[layout].arrange != NULL)
71: layout_sets[layout].arrange(w);
72:
73: w->lastlayout = layout;
74: return (layout);
75: }
76:
77: u_int
78: layout_set_next(struct window *w)
79: {
80: u_int layout;
81:
82: if (w->lastlayout == -1)
83: layout = 0;
84: else {
85: layout = w->lastlayout + 1;
86: if (layout > nitems(layout_sets) - 1)
87: layout = 0;
88: }
89:
90: if (layout_sets[layout].arrange != NULL)
91: layout_sets[layout].arrange(w);
92: w->lastlayout = layout;
93: return (layout);
94: }
95:
96: u_int
97: layout_set_previous(struct window *w)
98: {
99: u_int layout;
100:
101: if (w->lastlayout == -1)
102: layout = nitems(layout_sets) - 1;
103: else {
104: layout = w->lastlayout;
105: if (layout == 0)
106: layout = nitems(layout_sets) - 1;
107: else
108: layout--;
109: }
110:
111: if (layout_sets[layout].arrange != NULL)
112: layout_sets[layout].arrange(w);
113: w->lastlayout = layout;
114: return (layout);
115: }
116:
117: static void
118: layout_set_even_h(struct window *w)
119: {
120: struct window_pane *wp;
121: struct layout_cell *lc, *lcnew;
122: u_int i, n, width, xoff;
123:
124: layout_print_cell(w->layout_root, __func__, 1);
125:
126: /* Get number of panes. */
127: n = window_count_panes(w);
128: if (n <= 1)
129: return;
130:
131: /* How many can we fit? */
132: width = (w->sx - (n - 1)) / n;
133: if (width < PANE_MINIMUM)
134: width = PANE_MINIMUM;
135:
136: /* Free the old root and construct a new. */
137: layout_free(w);
138: lc = w->layout_root = layout_create_cell(NULL);
139: layout_set_size(lc, w->sx, w->sy, 0, 0);
140: layout_make_node(lc, LAYOUT_LEFTRIGHT);
141:
142: /* Build new leaf cells. */
143: i = xoff = 0;
144: TAILQ_FOREACH(wp, &w->panes, entry) {
145: /* Create child cell. */
146: lcnew = layout_create_cell(lc);
147: layout_set_size(lcnew, width, w->sy, xoff, 0);
148: layout_make_leaf(lcnew, wp);
149: TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
150:
151: i++;
152: xoff += width + 1;
153: }
154:
155: /* Allocate any remaining space. */
156: if (w->sx > xoff - 1) {
157: lc = TAILQ_LAST(&lc->cells, layout_cells);
158: layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT,
159: w->sx - (xoff - 1));
160: }
161:
162: /* Fix cell offsets. */
163: layout_fix_offsets(lc);
164: layout_fix_panes(w, w->sx, w->sy);
165:
166: layout_print_cell(w->layout_root, __func__, 1);
167:
168: server_redraw_window(w);
169: }
170:
171: static void
172: layout_set_even_v(struct window *w)
173: {
174: struct window_pane *wp;
175: struct layout_cell *lc, *lcnew;
176: u_int i, n, height, yoff;
177:
178: layout_print_cell(w->layout_root, __func__, 1);
179:
180: /* Get number of panes. */
181: n = window_count_panes(w);
182: if (n <= 1)
183: return;
184:
185: /* How many can we fit? */
186: height = (w->sy - (n - 1)) / n;
187: if (height < PANE_MINIMUM)
188: height = PANE_MINIMUM;
189:
190: /* Free the old root and construct a new. */
191: layout_free(w);
192: lc = w->layout_root = layout_create_cell(NULL);
193: layout_set_size(lc, w->sx, w->sy, 0, 0);
194: layout_make_node(lc, LAYOUT_TOPBOTTOM);
195:
196: /* Build new leaf cells. */
197: i = yoff = 0;
198: TAILQ_FOREACH(wp, &w->panes, entry) {
199: /* Create child cell. */
200: lcnew = layout_create_cell(lc);
201: layout_set_size(lcnew, w->sx, height, 0, yoff);
202: layout_make_leaf(lcnew, wp);
203: TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
204:
205: i++;
206: yoff += height + 1;
207: }
208:
209: /* Allocate any remaining space. */
210: if (w->sy > yoff - 1) {
211: lc = TAILQ_LAST(&lc->cells, layout_cells);
212: layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM,
213: w->sy - (yoff - 1));
214: }
215:
216: /* Fix cell offsets. */
217: layout_fix_offsets(lc);
218: layout_fix_panes(w, w->sx, w->sy);
219:
220: layout_print_cell(w->layout_root, __func__, 1);
221:
222: server_redraw_window(w);
223: }
224:
225: static void
226: layout_set_main_h(struct window *w)
227: {
228: struct window_pane *wp;
229: struct layout_cell *lc, *lcmain, *lcrow, *lcchild;
230: u_int n, mainheight, otherheight, width, height;
231: u_int used, i, j, columns, rows, totalrows;
232:
233: layout_print_cell(w->layout_root, __func__, 1);
234:
235: /* Get number of panes. */
236: n = window_count_panes(w);
237: if (n <= 1)
238: return;
239: n--; /* take off main pane */
240:
241: /* How many rows and columns will be needed, not counting main? */
242: columns = (w->sx + 1) / (PANE_MINIMUM + 1); /* maximum columns */
243: if (columns == 0)
244: columns = 1;
245: rows = 1 + (n - 1) / columns;
246: columns = 1 + (n - 1) / rows;
247: width = (w->sx - (n - 1)) / columns;
248:
249: /* Get the main pane height and add one for separator line. */
250: mainheight = options_get_number(w->options, "main-pane-height") + 1;
251:
252: /* Get the optional other pane height and add one for separator line. */
253: otherheight = options_get_number(w->options, "other-pane-height") + 1;
254:
255: /*
256: * If an other pane height was specified, honour it so long as it
257: * doesn't shrink the main height to less than the main-pane-height
258: */
259: if (otherheight > 1 && w->sy - otherheight > mainheight)
260: mainheight = w->sy - otherheight;
261: if (mainheight < PANE_MINIMUM + 1)
262: mainheight = PANE_MINIMUM + 1;
263:
264: /* Try and make everything fit. */
265: totalrows = rows * (PANE_MINIMUM + 1) - 1;
266: if (mainheight + totalrows > w->sy) {
267: if (totalrows + PANE_MINIMUM + 1 > w->sy)
268: mainheight = PANE_MINIMUM + 2;
269: else
270: mainheight = w->sy - totalrows;
271: height = PANE_MINIMUM;
272: } else
273: height = (w->sy - mainheight - (rows - 1)) / rows;
274:
275: /* Free old tree and create a new root. */
276: layout_free(w);
277: lc = w->layout_root = layout_create_cell(NULL);
278: layout_set_size(lc, w->sx, mainheight + rows * (height + 1) - 1, 0, 0);
279: layout_make_node(lc, LAYOUT_TOPBOTTOM);
280:
281: /* Create the main pane. */
282: lcmain = layout_create_cell(lc);
283: layout_set_size(lcmain, w->sx, mainheight - 1, 0, 0);
284: layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
285: TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
286:
287: /* Create a grid of the remaining cells. */
288: wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
289: for (j = 0; j < rows; j++) {
290: /* If this is the last cell, all done. */
291: if (wp == NULL)
292: break;
293:
294: /* Create the new row. */
295: lcrow = layout_create_cell(lc);
296: layout_set_size(lcrow, w->sx, height, 0, 0);
297: TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry);
298:
299: /* If only one column, just use the row directly. */
300: if (columns == 1) {
301: layout_make_leaf(lcrow, wp);
302: wp = TAILQ_NEXT(wp, entry);
303: continue;
304: }
305:
306: /* Add in the columns. */
307: layout_make_node(lcrow, LAYOUT_LEFTRIGHT);
308: for (i = 0; i < columns; i++) {
309: /* Create and add a pane cell. */
310: lcchild = layout_create_cell(lcrow);
311: layout_set_size(lcchild, width, height, 0, 0);
312: layout_make_leaf(lcchild, wp);
313: TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry);
314:
315: /* Move to the next cell. */
316: if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
317: break;
318: }
319:
320: /* Adjust the row to fit the full width if necessary. */
321: if (i == columns)
322: i--;
323: used = ((i + 1) * (width + 1)) - 1;
324: if (w->sx <= used)
325: continue;
326: lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
327: layout_resize_adjust(w, lcchild, LAYOUT_LEFTRIGHT,
328: w->sx - used);
329: }
330:
331: /* Adjust the last row height to fit if necessary. */
332: used = mainheight + (rows * height) + rows - 1;
333: if (w->sy > used) {
334: lcrow = TAILQ_LAST(&lc->cells, layout_cells);
335: layout_resize_adjust(w, lcrow, LAYOUT_TOPBOTTOM,
336: w->sy - used);
337: }
338:
339: /* Fix cell offsets. */
340: layout_fix_offsets(lc);
341: layout_fix_panes(w, w->sx, w->sy);
342:
343: layout_print_cell(w->layout_root, __func__, 1);
344:
345: server_redraw_window(w);
346: }
347:
348: static void
349: layout_set_main_v(struct window *w)
350: {
351: struct window_pane *wp;
352: struct layout_cell *lc, *lcmain, *lccolumn, *lcchild;
353: u_int n, mainwidth, otherwidth, width, height;
354: u_int used, i, j, columns, rows, totalcolumns;
355:
356: layout_print_cell(w->layout_root, __func__, 1);
357:
358: /* Get number of panes. */
359: n = window_count_panes(w);
360: if (n <= 1)
361: return;
362: n--; /* take off main pane */
363:
364: /* How many rows and columns will be needed, not counting main? */
365: rows = (w->sy + 1) / (PANE_MINIMUM + 1); /* maximum rows */
366: if (rows == 0)
367: rows = 1;
368: columns = 1 + (n - 1) / rows;
369: rows = 1 + (n - 1) / columns;
370: height = (w->sy - (n - 1)) / rows;
371:
372: /* Get the main pane width and add one for separator line. */
373: mainwidth = options_get_number(w->options, "main-pane-width") + 1;
374:
375: /* Get the optional other pane width and add one for separator line. */
376: otherwidth = options_get_number(w->options, "other-pane-width") + 1;
377:
378: /*
379: * If an other pane width was specified, honour it so long as it
380: * doesn't shrink the main width to less than the main-pane-width
381: */
382: if (otherwidth > 1 && w->sx - otherwidth > mainwidth)
383: mainwidth = w->sx - otherwidth;
384: if (mainwidth < PANE_MINIMUM + 1)
385: mainwidth = PANE_MINIMUM + 1;
386:
387: /* Try and make everything fit. */
388: totalcolumns = columns * (PANE_MINIMUM + 1) - 1;
389: if (mainwidth + totalcolumns > w->sx) {
390: if (totalcolumns + PANE_MINIMUM + 1 > w->sx)
391: mainwidth = PANE_MINIMUM + 2;
392: else
393: mainwidth = w->sx - totalcolumns;
394: width = PANE_MINIMUM;
395: } else
396: width = (w->sx - mainwidth - (columns - 1)) / columns;
397:
398: /* Free old tree and create a new root. */
399: layout_free(w);
400: lc = w->layout_root = layout_create_cell(NULL);
401: layout_set_size(lc, mainwidth + columns * (width + 1) - 1, w->sy, 0, 0);
402: layout_make_node(lc, LAYOUT_LEFTRIGHT);
403:
404: /* Create the main pane. */
405: lcmain = layout_create_cell(lc);
406: layout_set_size(lcmain, mainwidth - 1, w->sy, 0, 0);
407: layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
408: TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
409:
410: /* Create a grid of the remaining cells. */
411: wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
412: for (j = 0; j < columns; j++) {
413: /* If this is the last cell, all done. */
414: if (wp == NULL)
415: break;
416:
417: /* Create the new column. */
418: lccolumn = layout_create_cell(lc);
419: layout_set_size(lccolumn, width, w->sy, 0, 0);
420: TAILQ_INSERT_TAIL(&lc->cells, lccolumn, entry);
421:
422: /* If only one row, just use the row directly. */
423: if (rows == 1) {
424: layout_make_leaf(lccolumn, wp);
425: wp = TAILQ_NEXT(wp, entry);
426: continue;
427: }
428:
429: /* Add in the rows. */
430: layout_make_node(lccolumn, LAYOUT_TOPBOTTOM);
431: for (i = 0; i < rows; i++) {
432: /* Create and add a pane cell. */
433: lcchild = layout_create_cell(lccolumn);
434: layout_set_size(lcchild, width, height, 0, 0);
435: layout_make_leaf(lcchild, wp);
436: TAILQ_INSERT_TAIL(&lccolumn->cells, lcchild, entry);
437:
438: /* Move to the next cell. */
439: if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
440: break;
441: }
442:
443: /* Adjust the column to fit the full height if necessary. */
444: if (i == rows)
445: i--;
446: used = ((i + 1) * (height + 1)) - 1;
447: if (w->sy <= used)
448: continue;
449: lcchild = TAILQ_LAST(&lccolumn->cells, layout_cells);
450: layout_resize_adjust(w, lcchild, LAYOUT_TOPBOTTOM,
451: w->sy - used);
452: }
453:
454: /* Adjust the last column width to fit if necessary. */
455: used = mainwidth + (columns * width) + columns - 1;
456: if (w->sx > used) {
457: lccolumn = TAILQ_LAST(&lc->cells, layout_cells);
458: layout_resize_adjust(w, lccolumn, LAYOUT_LEFTRIGHT,
459: w->sx - used);
460: }
461:
462: /* Fix cell offsets. */
463: layout_fix_offsets(lc);
464: layout_fix_panes(w, w->sx, w->sy);
465:
466: layout_print_cell(w->layout_root, __func__, 1);
467:
468: server_redraw_window(w);
469: }
470:
471: void
472: layout_set_tiled(struct window *w)
473: {
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;
478:
479: layout_print_cell(w->layout_root, __func__, 1);
480:
481: /* Get number of panes. */
482: n = window_count_panes(w);
483: if (n <= 1)
484: return;
485:
486: /* How many rows and columns are wanted? */
487: rows = columns = 1;
488: while (rows * columns < n) {
489: rows++;
490: if (rows * columns < n)
491: columns++;
492: }
493:
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;
501:
502: /* Free old tree and create a new root. */
503: layout_free(w);
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);
508:
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. */
513: if (wp == NULL)
514: break;
515:
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);
520:
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);
525: continue;
526: }
527:
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);
536:
537: /* Move to the next cell. */
538: if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
539: break;
540: }
541:
542: /*
543: * Adjust the row and columns to fit the full width if
544: * necessary.
545: */
546: if (i == columns)
547: i--;
548: used = ((i + 1) * (width + 1)) - 1;
549: if (w->sx <= used)
550: continue;
551: lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
552: layout_resize_adjust(w, lcchild, LAYOUT_LEFTRIGHT,
553: w->sx - used);
554: }
555:
556: /* Adjust the last row height to fit if necessary. */
557: used = (rows * height) + rows - 1;
558: if (w->sy > used) {
559: lcrow = TAILQ_LAST(&lc->cells, layout_cells);
560: layout_resize_adjust(w, lcrow, LAYOUT_TOPBOTTOM,
561: w->sy - used);
562: }
563:
564: /* Fix cell offsets. */
565: layout_fix_offsets(lc);
566: layout_fix_panes(w, w->sx, w->sy);
567:
568: layout_print_cell(w->layout_root, __func__, 1);
569:
570: server_redraw_window(w);
571: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>