GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/tmux/layout-set.c Lines: 0 269 0.0 %
Date: 2016-12-06 Branches: 0 124 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: layout-set.c,v 1.14 2016/01/19 15:59:12 nicm Exp $ */
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
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 *);
35
36
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
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(lc, LAYOUT_LEFTRIGHT, w->sx - (xoff - 1));
159
	}
160
161
	/* Fix cell offsets. */
162
	layout_fix_offsets(lc);
163
	layout_fix_panes(w, w->sx, w->sy);
164
165
	layout_print_cell(w->layout_root, __func__, 1);
166
167
	server_redraw_window(w);
168
}
169
170
void
171
layout_set_even_v(struct window *w)
172
{
173
	struct window_pane	*wp;
174
	struct layout_cell	*lc, *lcnew;
175
	u_int			 i, n, height, yoff;
176
177
	layout_print_cell(w->layout_root, __func__, 1);
178
179
	/* Get number of panes. */
180
	n = window_count_panes(w);
181
	if (n <= 1)
182
		return;
183
184
	/* How many can we fit? */
185
	height = (w->sy - (n - 1)) / n;
186
	if (height < PANE_MINIMUM)
187
		height = PANE_MINIMUM;
188
189
	/* Free the old root and construct a new. */
190
	layout_free(w);
191
	lc = w->layout_root = layout_create_cell(NULL);
192
	layout_set_size(lc, w->sx, w->sy, 0, 0);
193
	layout_make_node(lc, LAYOUT_TOPBOTTOM);
194
195
	/* Build new leaf cells. */
196
	i = yoff = 0;
197
	TAILQ_FOREACH(wp, &w->panes, entry) {
198
		/* Create child cell. */
199
		lcnew = layout_create_cell(lc);
200
		layout_set_size(lcnew, w->sx, height, 0, yoff);
201
		layout_make_leaf(lcnew, wp);
202
		TAILQ_INSERT_TAIL(&lc->cells, lcnew, entry);
203
204
		i++;
205
		yoff += height + 1;
206
	}
207
208
	/* Allocate any remaining space. */
209
	if (w->sy > yoff - 1) {
210
		lc = TAILQ_LAST(&lc->cells, layout_cells);
211
		layout_resize_adjust(lc, LAYOUT_TOPBOTTOM, w->sy - (yoff - 1));
212
	}
213
214
	/* Fix cell offsets. */
215
	layout_fix_offsets(lc);
216
	layout_fix_panes(w, w->sx, w->sy);
217
218
	layout_print_cell(w->layout_root, __func__, 1);
219
220
	server_redraw_window(w);
221
}
222
223
void
224
layout_set_main_h(struct window *w)
225
{
226
	struct window_pane	*wp;
227
	struct layout_cell	*lc, *lcmain, *lcrow, *lcchild;
228
	u_int			 n, mainheight, otherheight, width, height;
229
	u_int			 used, i, j, columns, rows, totalrows;
230
231
	layout_print_cell(w->layout_root, __func__, 1);
232
233
	/* Get number of panes. */
234
	n = window_count_panes(w);
235
	if (n <= 1)
236
		return;
237
	n--;	/* take off main pane */
238
239
	/* How many rows and columns will be needed, not counting main? */
240
	columns = (w->sx + 1) / (PANE_MINIMUM + 1);	/* maximum columns */
241
	if (columns == 0)
242
		columns = 1;
243
	rows = 1 + (n - 1) / columns;
244
	columns = 1 + (n - 1) / rows;
245
	width = (w->sx - (n - 1)) / columns;
246
247
	/* Get the main pane height and add one for separator line. */
248
	mainheight = options_get_number(w->options, "main-pane-height") + 1;
249
250
	/* Get the optional other pane height and add one for separator line. */
251
	otherheight = options_get_number(w->options, "other-pane-height") + 1;
252
253
	/*
254
	 * If an other pane height was specified, honour it so long as it
255
	 * doesn't shrink the main height to less than the main-pane-height
256
	 */
257
	if (otherheight > 1 && w->sy - otherheight > mainheight)
258
		mainheight = w->sy - otherheight;
259
	if (mainheight < PANE_MINIMUM + 1)
260
		mainheight = PANE_MINIMUM + 1;
261
262
	/* Try and make everything fit. */
263
	totalrows = rows * (PANE_MINIMUM + 1) - 1;
264
	if (mainheight + totalrows > w->sy) {
265
		if (totalrows + PANE_MINIMUM + 1 > w->sy)
266
			mainheight = PANE_MINIMUM + 2;
267
		else
268
			mainheight = w->sy - totalrows;
269
		height = PANE_MINIMUM;
270
	} else
271
		height = (w->sy - mainheight - (rows - 1)) / rows;
272
273
	/* Free old tree and create a new root. */
274
	layout_free(w);
275
	lc = w->layout_root = layout_create_cell(NULL);
276
	layout_set_size(lc, w->sx, mainheight + rows * (height + 1) - 1, 0, 0);
277
	layout_make_node(lc, LAYOUT_TOPBOTTOM);
278
279
	/* Create the main pane. */
280
	lcmain = layout_create_cell(lc);
281
	layout_set_size(lcmain, w->sx, mainheight - 1, 0, 0);
282
	layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
283
	TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
284
285
	/* Create a grid of the remaining cells. */
286
	wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
287
	for (j = 0; j < rows; j++) {
288
		/* If this is the last cell, all done. */
289
		if (wp == NULL)
290
			break;
291
292
		/* Create the new row. */
293
		lcrow = layout_create_cell(lc);
294
		layout_set_size(lcrow, w->sx, height, 0, 0);
295
		TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry);
296
297
		/* If only one column, just use the row directly. */
298
		if (columns == 1) {
299
			layout_make_leaf(lcrow, wp);
300
			wp = TAILQ_NEXT(wp, entry);
301
			continue;
302
		}
303
304
		/* Add in the columns. */
305
		layout_make_node(lcrow, LAYOUT_LEFTRIGHT);
306
		for (i = 0; i < columns; i++) {
307
			/* Create and add a pane cell. */
308
			lcchild = layout_create_cell(lcrow);
309
			layout_set_size(lcchild, width, height, 0, 0);
310
			layout_make_leaf(lcchild, wp);
311
			TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry);
312
313
			/* Move to the next cell. */
314
			if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
315
				break;
316
		}
317
318
		/* Adjust the row to fit the full width if necessary. */
319
		if (i == columns)
320
			i--;
321
		used = ((i + 1) * (width + 1)) - 1;
322
		if (w->sx <= used)
323
			continue;
324
		lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
325
		layout_resize_adjust(lcchild, LAYOUT_LEFTRIGHT, w->sx - used);
326
	}
327
328
	/* Adjust the last row height to fit if necessary. */
329
	used = mainheight + (rows * height) + rows - 1;
330
	if (w->sy > used) {
331
		lcrow = TAILQ_LAST(&lc->cells, layout_cells);
332
		layout_resize_adjust(lcrow, LAYOUT_TOPBOTTOM, w->sy - used);
333
	}
334
335
	/* Fix cell offsets. */
336
	layout_fix_offsets(lc);
337
	layout_fix_panes(w, w->sx, w->sy);
338
339
	layout_print_cell(w->layout_root, __func__, 1);
340
341
	server_redraw_window(w);
342
}
343
344
void
345
layout_set_main_v(struct window *w)
346
{
347
	struct window_pane	*wp;
348
	struct layout_cell	*lc, *lcmain, *lccolumn, *lcchild;
349
	u_int			 n, mainwidth, otherwidth, width, height;
350
	u_int			 used, i, j, columns, rows, totalcolumns;
351
352
	layout_print_cell(w->layout_root, __func__, 1);
353
354
	/* Get number of panes. */
355
	n = window_count_panes(w);
356
	if (n <= 1)
357
		return;
358
	n--;	/* take off main pane */
359
360
	/* How many rows and columns will be needed, not counting main? */
361
	rows = (w->sy + 1) / (PANE_MINIMUM + 1);	/* maximum rows */
362
	if (rows == 0)
363
		rows = 1;
364
	columns = 1 + (n - 1) / rows;
365
	rows = 1 + (n - 1) / columns;
366
	height = (w->sy - (n - 1)) / rows;
367
368
	/* Get the main pane width and add one for separator line. */
369
	mainwidth = options_get_number(w->options, "main-pane-width") + 1;
370
371
	/* Get the optional other pane width and add one for separator line. */
372
	otherwidth = options_get_number(w->options, "other-pane-width") + 1;
373
374
	/*
375
	 * If an other pane width was specified, honour it so long as it
376
	 * doesn't shrink the main width to less than the main-pane-width
377
	 */
378
	if (otherwidth > 1 && w->sx - otherwidth > mainwidth)
379
		mainwidth = w->sx - otherwidth;
380
	if (mainwidth < PANE_MINIMUM + 1)
381
		mainwidth = PANE_MINIMUM + 1;
382
383
	/* Try and make everything fit. */
384
	totalcolumns = columns * (PANE_MINIMUM + 1) - 1;
385
	if (mainwidth + totalcolumns > w->sx) {
386
		if (totalcolumns + PANE_MINIMUM + 1 > w->sx)
387
			mainwidth = PANE_MINIMUM + 2;
388
		else
389
			mainwidth = w->sx - totalcolumns;
390
		width = PANE_MINIMUM;
391
	} else
392
		width = (w->sx - mainwidth - (columns - 1)) / columns;
393
394
	/* Free old tree and create a new root. */
395
	layout_free(w);
396
	lc = w->layout_root = layout_create_cell(NULL);
397
	layout_set_size(lc, mainwidth + columns * (width + 1) - 1, w->sy, 0, 0);
398
	layout_make_node(lc, LAYOUT_LEFTRIGHT);
399
400
	/* Create the main pane. */
401
	lcmain = layout_create_cell(lc);
402
	layout_set_size(lcmain, mainwidth - 1, w->sy, 0, 0);
403
	layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
404
	TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
405
406
	/* Create a grid of the remaining cells. */
407
	wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
408
	for (j = 0; j < columns; j++) {
409
		/* If this is the last cell, all done. */
410
		if (wp == NULL)
411
			break;
412
413
		/* Create the new column. */
414
		lccolumn = layout_create_cell(lc);
415
		layout_set_size(lccolumn, width, w->sy, 0, 0);
416
		TAILQ_INSERT_TAIL(&lc->cells, lccolumn, entry);
417
418
		/* If only one row, just use the row directly. */
419
		if (rows == 1) {
420
			layout_make_leaf(lccolumn, wp);
421
			wp = TAILQ_NEXT(wp, entry);
422
			continue;
423
		}
424
425
		/* Add in the rows. */
426
		layout_make_node(lccolumn, LAYOUT_TOPBOTTOM);
427
		for (i = 0; i < rows; i++) {
428
			/* Create and add a pane cell. */
429
			lcchild = layout_create_cell(lccolumn);
430
			layout_set_size(lcchild, width, height, 0, 0);
431
			layout_make_leaf(lcchild, wp);
432
			TAILQ_INSERT_TAIL(&lccolumn->cells, lcchild, entry);
433
434
			/* Move to the next cell. */
435
			if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
436
				break;
437
		}
438
439
		/* Adjust the column to fit the full height if necessary. */
440
		if (i == rows)
441
			i--;
442
		used = ((i + 1) * (height + 1)) - 1;
443
		if (w->sy <= used)
444
			continue;
445
		lcchild = TAILQ_LAST(&lccolumn->cells, layout_cells);
446
		layout_resize_adjust(lcchild, LAYOUT_TOPBOTTOM, w->sy - used);
447
	}
448
449
	/* Adjust the last column width to fit if necessary. */
450
	used = mainwidth + (columns * width) + columns - 1;
451
	if (w->sx > used) {
452
		lccolumn = TAILQ_LAST(&lc->cells, layout_cells);
453
		layout_resize_adjust(lccolumn, LAYOUT_LEFTRIGHT, w->sx - used);
454
	}
455
456
	/* Fix cell offsets. */
457
	layout_fix_offsets(lc);
458
	layout_fix_panes(w, w->sx, w->sy);
459
460
	layout_print_cell(w->layout_root, __func__, 1);
461
462
	server_redraw_window(w);
463
}
464
465
void
466
layout_set_tiled(struct window *w)
467
{
468
	struct window_pane	*wp;
469
	struct layout_cell	*lc, *lcrow, *lcchild;
470
	u_int			 n, width, height, used;
471
	u_int			 i, j, columns, rows;
472
473
	layout_print_cell(w->layout_root, __func__, 1);
474
475
	/* Get number of panes. */
476
	n = window_count_panes(w);
477
	if (n <= 1)
478
		return;
479
480
	/* How many rows and columns are wanted? */
481
	rows = columns = 1;
482
	while (rows * columns < n) {
483
		rows++;
484
		if (rows * columns < n)
485
			columns++;
486
	}
487
488
	/* What width and height should they be? */
489
	width = (w->sx - (columns - 1)) / columns;
490
	if (width < PANE_MINIMUM)
491
		width = PANE_MINIMUM;
492
	height = (w->sy - (rows - 1)) / rows;
493
	if (height < PANE_MINIMUM)
494
		height = PANE_MINIMUM;
495
496
	/* Free old tree and create a new root. */
497
	layout_free(w);
498
	lc = w->layout_root = layout_create_cell(NULL);
499
	layout_set_size(lc, (width + 1) * columns - 1,
500
	    (height + 1) * rows - 1, 0, 0);
501
	layout_make_node(lc, LAYOUT_TOPBOTTOM);
502
503
	/* Create a grid of the cells. */
504
	wp = TAILQ_FIRST(&w->panes);
505
	for (j = 0; j < rows; j++) {
506
		/* If this is the last cell, all done. */
507
		if (wp == NULL)
508
			break;
509
510
		/* Create the new row. */
511
		lcrow = layout_create_cell(lc);
512
		layout_set_size(lcrow, w->sx, height, 0, 0);
513
		TAILQ_INSERT_TAIL(&lc->cells, lcrow, entry);
514
515
		/* If only one column, just use the row directly. */
516
		if (n - (j * columns) == 1 || columns == 1) {
517
			layout_make_leaf(lcrow, wp);
518
			wp = TAILQ_NEXT(wp, entry);
519
			continue;
520
		}
521
522
		/* Add in the columns. */
523
		layout_make_node(lcrow, LAYOUT_LEFTRIGHT);
524
		for (i = 0; i < columns; i++) {
525
			/* Create and add a pane cell. */
526
			lcchild = layout_create_cell(lcrow);
527
			layout_set_size(lcchild, width, height, 0, 0);
528
			layout_make_leaf(lcchild, wp);
529
			TAILQ_INSERT_TAIL(&lcrow->cells, lcchild, entry);
530
531
			/* Move to the next cell. */
532
			if ((wp = TAILQ_NEXT(wp, entry)) == NULL)
533
				break;
534
		}
535
536
		/*
537
		 * Adjust the row and columns to fit the full width if
538
		 * necessary.
539
		 */
540
		if (i == columns)
541
			i--;
542
		used = ((i + 1) * (width + 1)) - 1;
543
		if (w->sx <= used)
544
			continue;
545
		lcchild = TAILQ_LAST(&lcrow->cells, layout_cells);
546
		layout_resize_adjust(lcchild, LAYOUT_LEFTRIGHT, w->sx - used);
547
	}
548
549
	/* Adjust the last row height to fit if necessary. */
550
	used = (rows * height) + rows - 1;
551
	if (w->sy > used) {
552
		lcrow = TAILQ_LAST(&lc->cells, layout_cells);
553
		layout_resize_adjust(lcrow, LAYOUT_TOPBOTTOM, w->sy - used);
554
	}
555
556
	/* Fix cell offsets. */
557
	layout_fix_offsets(lc);
558
	layout_fix_panes(w, w->sx, w->sy);
559
560
	layout_print_cell(w->layout_root, __func__, 1);
561
562
	server_redraw_window(w);
563
}