4 * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
26 * Set window layouts - predefined methods to arrange windows. These are one-off
27 * and generate a layout tree.
30 void layout_set_even_h(struct window
*);
31 void layout_set_even_v(struct window
*);
32 void layout_set_main_h(struct window
*);
33 void layout_set_main_v(struct window
*);
34 void layout_set_tiled(struct window
*);
38 void (*arrange
)(struct window
*);
40 { "even-horizontal", layout_set_even_h
},
41 { "even-vertical", layout_set_even_v
},
42 { "main-horizontal", layout_set_main_h
},
43 { "main-vertical", layout_set_main_v
},
44 { "tiled", layout_set_tiled
},
48 layout_set_name(u_int layout
)
50 return (layout_sets
[layout
].name
);
54 layout_set_lookup(const char *name
)
59 for (i
= 0; i
< nitems(layout_sets
); i
++) {
60 if (strncmp(layout_sets
[i
].name
, name
, strlen(name
)) == 0) {
61 if (matched
!= -1) /* ambiguous */
71 layout_set_select(struct window
*w
, u_int layout
)
73 if (layout
> nitems(layout_sets
) - 1)
74 layout
= nitems(layout_sets
) - 1;
76 if (layout_sets
[layout
].arrange
!= NULL
)
77 layout_sets
[layout
].arrange(w
);
79 w
->lastlayout
= layout
;
84 layout_set_next(struct window
*w
)
88 if (w
->lastlayout
== -1)
91 layout
= w
->lastlayout
+ 1;
92 if (layout
> nitems(layout_sets
) - 1)
96 if (layout_sets
[layout
].arrange
!= NULL
)
97 layout_sets
[layout
].arrange(w
);
98 w
->lastlayout
= layout
;
103 layout_set_previous(struct window
*w
)
107 if (w
->lastlayout
== -1)
108 layout
= nitems(layout_sets
) - 1;
110 layout
= w
->lastlayout
;
112 layout
= nitems(layout_sets
) - 1;
117 if (layout_sets
[layout
].arrange
!= NULL
)
118 layout_sets
[layout
].arrange(w
);
119 w
->lastlayout
= layout
;
124 layout_set_even_h(struct window
*w
)
126 struct window_pane
*wp
;
127 struct layout_cell
*lc
, *lcnew
;
128 u_int i
, n
, width
, xoff
;
130 layout_print_cell(w
->layout_root
, __func__
, 1);
132 /* Get number of panes. */
133 n
= window_count_panes(w
);
137 /* How many can we fit? */
138 if (w
->sx
/ n
< PANE_MINIMUM
+ 1)
139 width
= PANE_MINIMUM
+ 1;
143 /* Free the old root and construct a new. */
145 lc
= w
->layout_root
= layout_create_cell(NULL
);
146 layout_set_size(lc
, w
->sx
, w
->sy
, 0, 0);
147 layout_make_node(lc
, LAYOUT_LEFTRIGHT
);
149 /* Build new leaf cells. */
151 TAILQ_FOREACH(wp
, &w
->panes
, entry
) {
152 /* Create child cell. */
153 lcnew
= layout_create_cell(lc
);
154 layout_set_size(lcnew
, width
- 1, w
->sy
, xoff
, 0);
155 layout_make_leaf(lcnew
, wp
);
156 TAILQ_INSERT_TAIL(&lc
->cells
, lcnew
, entry
);
162 /* Allocate any remaining space. */
163 if (w
->sx
> xoff
- 1) {
164 lc
= TAILQ_LAST(&lc
->cells
, layout_cells
);
165 layout_resize_adjust(lc
, LAYOUT_LEFTRIGHT
, w
->sx
- (xoff
- 1));
168 /* Fix cell offsets. */
169 layout_fix_offsets(lc
);
170 layout_fix_panes(w
, w
->sx
, w
->sy
);
172 layout_print_cell(w
->layout_root
, __func__
, 1);
174 server_redraw_window(w
);
178 layout_set_even_v(struct window
*w
)
180 struct window_pane
*wp
;
181 struct layout_cell
*lc
, *lcnew
;
182 u_int i
, n
, height
, yoff
;
184 layout_print_cell(w
->layout_root
, __func__
, 1);
186 /* Get number of panes. */
187 n
= window_count_panes(w
);
191 /* How many can we fit? */
192 if (w
->sy
/ n
< PANE_MINIMUM
+ 1)
193 height
= PANE_MINIMUM
+ 1;
197 /* Free the old root and construct a new. */
199 lc
= w
->layout_root
= layout_create_cell(NULL
);
200 layout_set_size(lc
, w
->sx
, w
->sy
, 0, 0);
201 layout_make_node(lc
, LAYOUT_TOPBOTTOM
);
203 /* Build new leaf cells. */
205 TAILQ_FOREACH(wp
, &w
->panes
, entry
) {
206 /* Create child cell. */
207 lcnew
= layout_create_cell(lc
);
208 layout_set_size(lcnew
, w
->sx
, height
- 1, 0, yoff
);
209 layout_make_leaf(lcnew
, wp
);
210 TAILQ_INSERT_TAIL(&lc
->cells
, lcnew
, entry
);
216 /* Allocate any remaining space. */
217 if (w
->sy
> yoff
- 1) {
218 lc
= TAILQ_LAST(&lc
->cells
, layout_cells
);
219 layout_resize_adjust(lc
, LAYOUT_TOPBOTTOM
, w
->sy
- (yoff
- 1));
222 /* Fix cell offsets. */
223 layout_fix_offsets(lc
);
224 layout_fix_panes(w
, w
->sx
, w
->sy
);
226 layout_print_cell(w
->layout_root
, __func__
, 1);
228 server_redraw_window(w
);
232 layout_set_main_h(struct window
*w
)
234 struct window_pane
*wp
;
235 struct layout_cell
*lc
, *lcmain
, *lcrow
, *lcchild
;
236 u_int n
, mainheight
, width
, height
, used
;
237 u_int i
, j
, columns
, rows
, totalrows
;
239 layout_print_cell(w
->layout_root
, __func__
, 1);
241 /* Get number of panes. */
242 n
= window_count_panes(w
);
245 n
--; /* take off main pane */
247 /* How many rows and columns will be needed? */
248 columns
= w
->sx
/ (PANE_MINIMUM
+ 1); /* maximum columns */
251 rows
= 1 + (n
- 1) / columns
;
252 columns
= 1 + (n
- 1) / rows
;
253 width
= w
->sx
/ columns
;
255 /* Get the main pane height and add one for separator line. */
256 mainheight
= options_get_number(&w
->options
, "main-pane-height") + 1;
257 if (mainheight
< PANE_MINIMUM
+ 1)
258 mainheight
= PANE_MINIMUM
+ 1;
260 /* Try and make everything fit. */
261 totalrows
= rows
* (PANE_MINIMUM
+ 1) - 1;
262 if (mainheight
+ totalrows
> w
->sy
) {
263 if (totalrows
+ PANE_MINIMUM
+ 1 > w
->sy
)
264 mainheight
= PANE_MINIMUM
+ 2;
266 mainheight
= w
->sy
- totalrows
;
267 height
= PANE_MINIMUM
+ 1;
269 height
= (w
->sy
- mainheight
) / rows
;
271 /* Free old tree and create a new root. */
273 lc
= w
->layout_root
= layout_create_cell(NULL
);
274 layout_set_size(lc
, w
->sx
, mainheight
+ rows
* height
, 0, 0);
275 layout_make_node(lc
, LAYOUT_TOPBOTTOM
);
277 /* Create the main pane. */
278 lcmain
= layout_create_cell(lc
);
279 layout_set_size(lcmain
, w
->sx
, mainheight
- 1, 0, 0);
280 layout_make_leaf(lcmain
, TAILQ_FIRST(&w
->panes
));
281 TAILQ_INSERT_TAIL(&lc
->cells
, lcmain
, entry
);
283 /* Create a grid of the remaining cells. */
284 wp
= TAILQ_NEXT(TAILQ_FIRST(&w
->panes
), entry
);
285 for (j
= 0; j
< rows
; j
++) {
286 /* If this is the last cell, all done. */
290 /* Create the new row. */
291 lcrow
= layout_create_cell(lc
);
292 layout_set_size(lcrow
, w
->sx
, height
- 1, 0, 0);
293 TAILQ_INSERT_TAIL(&lc
->cells
, lcrow
, entry
);
295 /* If only one column, just use the row directly. */
297 layout_make_leaf(lcrow
, wp
);
298 wp
= TAILQ_NEXT(wp
, entry
);
302 /* Add in the columns. */
303 layout_make_node(lcrow
, LAYOUT_LEFTRIGHT
);
304 for (i
= 0; i
< columns
; i
++) {
305 /* Create and add a pane cell. */
306 lcchild
= layout_create_cell(lcrow
);
307 layout_set_size(lcchild
, width
- 1, height
- 1, 0, 0);
308 layout_make_leaf(lcchild
, wp
);
309 TAILQ_INSERT_TAIL(&lcrow
->cells
, lcchild
, entry
);
311 /* Move to the next cell. */
312 if ((wp
= TAILQ_NEXT(wp
, entry
)) == NULL
)
316 /* Adjust the row to fit the full width if necessary. */
319 used
= ((i
+ 1) * width
) - 1;
322 lcchild
= TAILQ_LAST(&lcrow
->cells
, layout_cells
);
323 layout_resize_adjust(lcchild
, LAYOUT_LEFTRIGHT
, w
->sx
- used
);
326 /* Adjust the last row height to fit if necessary. */
327 used
= mainheight
+ (rows
* height
) - 1;
329 lcrow
= TAILQ_LAST(&lc
->cells
, layout_cells
);
330 layout_resize_adjust(lcrow
, LAYOUT_TOPBOTTOM
, w
->sy
- used
);
333 /* Fix cell offsets. */
334 layout_fix_offsets(lc
);
335 layout_fix_panes(w
, w
->sx
, w
->sy
);
337 layout_print_cell(w
->layout_root
, __func__
, 1);
339 server_redraw_window(w
);
343 layout_set_main_v(struct window
*w
)
345 struct window_pane
*wp
;
346 struct layout_cell
*lc
, *lcmain
, *lccolumn
, *lcchild
;
347 u_int n
, mainwidth
, width
, height
, used
;
348 u_int i
, j
, columns
, rows
, totalcolumns
;
350 layout_print_cell(w
->layout_root
, __func__
, 1);
352 /* Get number of panes. */
353 n
= window_count_panes(w
);
356 n
--; /* take off main pane */
358 /* How many rows and columns will be needed? */
359 rows
= w
->sy
/ (PANE_MINIMUM
+ 1); /* maximum rows */
362 columns
= 1 + (n
- 1) / rows
;
363 rows
= 1 + (n
- 1) / columns
;
364 height
= w
->sy
/ rows
;
366 /* Get the main pane width and add one for separator line. */
367 mainwidth
= options_get_number(&w
->options
, "main-pane-width") + 1;
368 if (mainwidth
< PANE_MINIMUM
+ 1)
369 mainwidth
= PANE_MINIMUM
+ 1;
371 /* Try and make everything fit. */
372 totalcolumns
= columns
* (PANE_MINIMUM
+ 1) - 1;
373 if (mainwidth
+ totalcolumns
> w
->sx
) {
374 if (totalcolumns
+ PANE_MINIMUM
+ 1 > w
->sx
)
375 mainwidth
= PANE_MINIMUM
+ 2;
377 mainwidth
= w
->sx
- totalcolumns
;
378 width
= PANE_MINIMUM
+ 1;
380 width
= (w
->sx
- mainwidth
) / columns
;
382 /* Free old tree and create a new root. */
384 lc
= w
->layout_root
= layout_create_cell(NULL
);
385 layout_set_size(lc
, mainwidth
+ columns
* width
, w
->sy
, 0, 0);
386 layout_make_node(lc
, LAYOUT_LEFTRIGHT
);
388 /* Create the main pane. */
389 lcmain
= layout_create_cell(lc
);
390 layout_set_size(lcmain
, mainwidth
- 1, w
->sy
, 0, 0);
391 layout_make_leaf(lcmain
, TAILQ_FIRST(&w
->panes
));
392 TAILQ_INSERT_TAIL(&lc
->cells
, lcmain
, entry
);
394 /* Create a grid of the remaining cells. */
395 wp
= TAILQ_NEXT(TAILQ_FIRST(&w
->panes
), entry
);
396 for (j
= 0; j
< columns
; j
++) {
397 /* If this is the last cell, all done. */
401 /* Create the new column. */
402 lccolumn
= layout_create_cell(lc
);
403 layout_set_size(lccolumn
, width
- 1, w
->sy
, 0, 0);
404 TAILQ_INSERT_TAIL(&lc
->cells
, lccolumn
, entry
);
406 /* If only one row, just use the row directly. */
408 layout_make_leaf(lccolumn
, wp
);
409 wp
= TAILQ_NEXT(wp
, entry
);
413 /* Add in the rows. */
414 layout_make_node(lccolumn
, LAYOUT_TOPBOTTOM
);
415 for (i
= 0; i
< rows
; i
++) {
416 /* Create and add a pane cell. */
417 lcchild
= layout_create_cell(lccolumn
);
418 layout_set_size(lcchild
, width
- 1, height
- 1, 0, 0);
419 layout_make_leaf(lcchild
, wp
);
420 TAILQ_INSERT_TAIL(&lccolumn
->cells
, lcchild
, entry
);
422 /* Move to the next cell. */
423 if ((wp
= TAILQ_NEXT(wp
, entry
)) == NULL
)
427 /* Adjust the column to fit the full height if necessary. */
430 used
= ((i
+ 1) * height
) - 1;
433 lcchild
= TAILQ_LAST(&lccolumn
->cells
, layout_cells
);
434 layout_resize_adjust(lcchild
, LAYOUT_TOPBOTTOM
, w
->sy
- used
);
437 /* Adjust the last column width to fit if necessary. */
438 used
= mainwidth
+ (columns
* width
) - 1;
440 lccolumn
= TAILQ_LAST(&lc
->cells
, layout_cells
);
441 layout_resize_adjust(lccolumn
, LAYOUT_LEFTRIGHT
, w
->sx
- used
);
444 /* Fix cell offsets. */
445 layout_fix_offsets(lc
);
446 layout_fix_panes(w
, w
->sx
, w
->sy
);
448 layout_print_cell(w
->layout_root
, __func__
, 1);
450 server_redraw_window(w
);
454 layout_set_tiled(struct window
*w
)
456 struct window_pane
*wp
;
457 struct layout_cell
*lc
, *lcrow
, *lcchild
;
458 u_int n
, width
, height
, used
;
459 u_int i
, j
, columns
, rows
;
461 layout_print_cell(w
->layout_root
, __func__
, 1);
463 /* Get number of panes. */
464 n
= window_count_panes(w
);
468 /* How many rows and columns are wanted? */
470 while (rows
* columns
< n
) {
472 if (rows
* columns
< n
)
476 /* What width and height should they be? */
477 width
= w
->sx
/ columns
;
478 if (width
< PANE_MINIMUM
+ 1)
479 width
= PANE_MINIMUM
+ 1;
480 height
= w
->sy
/ rows
;
481 if (width
< PANE_MINIMUM
+ 1)
482 width
= PANE_MINIMUM
+ 1;
484 /* Free old tree and create a new root. */
486 lc
= w
->layout_root
= layout_create_cell(NULL
);
487 layout_set_size(lc
, width
* columns
, height
* rows
, 0, 0);
488 layout_make_node(lc
, LAYOUT_TOPBOTTOM
);
490 /* Create a grid of the cells. */
491 wp
= TAILQ_FIRST(&w
->panes
);
492 for (j
= 0; j
< rows
; j
++) {
493 /* If this is the last cell, all done. */
497 /* Create the new row. */
498 lcrow
= layout_create_cell(lc
);
499 layout_set_size(lcrow
, w
->sx
, height
- 1, 0, 0);
500 TAILQ_INSERT_TAIL(&lc
->cells
, lcrow
, entry
);
502 /* If only one column, just use the row directly. */
503 if (n
- (j
* columns
) == 1) {
504 layout_make_leaf(lcrow
, wp
);
505 wp
= TAILQ_NEXT(wp
, entry
);
509 /* Add in the columns. */
510 layout_make_node(lcrow
, LAYOUT_LEFTRIGHT
);
511 for (i
= 0; i
< columns
; i
++) {
512 /* Create and add a pane cell. */
513 lcchild
= layout_create_cell(lcrow
);
514 layout_set_size(lcchild
, width
- 1, height
- 1, 0, 0);
515 layout_make_leaf(lcchild
, wp
);
516 TAILQ_INSERT_TAIL(&lcrow
->cells
, lcchild
, entry
);
518 /* Move to the next cell. */
519 if ((wp
= TAILQ_NEXT(wp
, entry
)) == NULL
)
524 * Adjust the row and columns to fit the full width if
529 used
= ((i
+ 1) * width
) - 1;
532 lcchild
= TAILQ_LAST(&lcrow
->cells
, layout_cells
);
533 layout_resize_adjust(lcchild
, LAYOUT_LEFTRIGHT
, w
->sx
- used
);
536 /* Adjust the last row height to fit if necessary. */
537 used
= (rows
* height
) - 1;
539 lcrow
= TAILQ_LAST(&lc
->cells
, layout_cells
);
540 layout_resize_adjust(lcrow
, LAYOUT_TOPBOTTOM
, w
->sy
- used
);
543 /* Fix cell offsets. */
544 layout_fix_offsets(lc
);
545 layout_fix_panes(w
, w
->sx
, w
->sy
);
547 layout_print_cell(w
->layout_root
, __func__
, 1);
549 server_redraw_window(w
);