xref: /minix3/external/bsd/tmux/dist/layout-custom.c (revision eda6f5931d42c77e1480347b1fc3eef2f8d33806)
1*eda6f593SDavid van Moolenbroek /* $Id: layout-custom.c,v 1.1.1.2 2011/08/17 18:40:04 jmmv Exp $ */
2*eda6f593SDavid van Moolenbroek 
3*eda6f593SDavid van Moolenbroek /*
4*eda6f593SDavid van Moolenbroek  * Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
5*eda6f593SDavid van Moolenbroek  *
6*eda6f593SDavid van Moolenbroek  * Permission to use, copy, modify, and distribute this software for any
7*eda6f593SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
8*eda6f593SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
9*eda6f593SDavid van Moolenbroek  *
10*eda6f593SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*eda6f593SDavid van Moolenbroek  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*eda6f593SDavid van Moolenbroek  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*eda6f593SDavid van Moolenbroek  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*eda6f593SDavid van Moolenbroek  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15*eda6f593SDavid van Moolenbroek  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16*eda6f593SDavid van Moolenbroek  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*eda6f593SDavid van Moolenbroek  */
18*eda6f593SDavid van Moolenbroek 
19*eda6f593SDavid van Moolenbroek #include <sys/types.h>
20*eda6f593SDavid van Moolenbroek 
21*eda6f593SDavid van Moolenbroek #include <ctype.h>
22*eda6f593SDavid van Moolenbroek #include <string.h>
23*eda6f593SDavid van Moolenbroek 
24*eda6f593SDavid van Moolenbroek #include "tmux.h"
25*eda6f593SDavid van Moolenbroek 
26*eda6f593SDavid van Moolenbroek struct layout_cell     *layout_find_bottomright(struct layout_cell *);
27*eda6f593SDavid van Moolenbroek u_short			layout_checksum(const char *);
28*eda6f593SDavid van Moolenbroek int			layout_append(struct layout_cell *, char *, size_t);
29*eda6f593SDavid van Moolenbroek struct layout_cell     *layout_construct(struct layout_cell *, const char **);
30*eda6f593SDavid van Moolenbroek void			layout_assign(struct window_pane **, struct layout_cell *);
31*eda6f593SDavid van Moolenbroek 
32*eda6f593SDavid van Moolenbroek /* Find the bottom-right cell. */
33*eda6f593SDavid van Moolenbroek struct layout_cell *
34*eda6f593SDavid van Moolenbroek layout_find_bottomright(struct layout_cell *lc)
35*eda6f593SDavid van Moolenbroek {
36*eda6f593SDavid van Moolenbroek 	if (lc->type == LAYOUT_WINDOWPANE)
37*eda6f593SDavid van Moolenbroek 		return (lc);
38*eda6f593SDavid van Moolenbroek 	lc = TAILQ_LAST(&lc->cells, layout_cells);
39*eda6f593SDavid van Moolenbroek 	return (layout_find_bottomright(lc));
40*eda6f593SDavid van Moolenbroek }
41*eda6f593SDavid van Moolenbroek 
42*eda6f593SDavid van Moolenbroek /* Calculate layout checksum. */
43*eda6f593SDavid van Moolenbroek u_short
44*eda6f593SDavid van Moolenbroek layout_checksum(const char *layout)
45*eda6f593SDavid van Moolenbroek {
46*eda6f593SDavid van Moolenbroek 	u_short	csum;
47*eda6f593SDavid van Moolenbroek 
48*eda6f593SDavid van Moolenbroek 	csum = 0;
49*eda6f593SDavid van Moolenbroek 	for (; *layout != '\0'; layout++) {
50*eda6f593SDavid van Moolenbroek 		csum = (csum >> 1) + ((csum & 1) << 15);
51*eda6f593SDavid van Moolenbroek 		csum += *layout;
52*eda6f593SDavid van Moolenbroek 	}
53*eda6f593SDavid van Moolenbroek 	return (csum);
54*eda6f593SDavid van Moolenbroek }
55*eda6f593SDavid van Moolenbroek 
56*eda6f593SDavid van Moolenbroek /* Dump layout as a string. */
57*eda6f593SDavid van Moolenbroek char *
58*eda6f593SDavid van Moolenbroek layout_dump(struct window *w)
59*eda6f593SDavid van Moolenbroek {
60*eda6f593SDavid van Moolenbroek 	char	layout[BUFSIZ], *out;
61*eda6f593SDavid van Moolenbroek 
62*eda6f593SDavid van Moolenbroek 	*layout = '\0';
63*eda6f593SDavid van Moolenbroek 	if (layout_append(w->layout_root, layout, sizeof layout) != 0)
64*eda6f593SDavid van Moolenbroek 		return (NULL);
65*eda6f593SDavid van Moolenbroek 
66*eda6f593SDavid van Moolenbroek 	xasprintf(&out, "%4x,%s", layout_checksum(layout), layout);
67*eda6f593SDavid van Moolenbroek 	return (out);
68*eda6f593SDavid van Moolenbroek }
69*eda6f593SDavid van Moolenbroek 
70*eda6f593SDavid van Moolenbroek /* Append information for a single cell. */
71*eda6f593SDavid van Moolenbroek int
72*eda6f593SDavid van Moolenbroek layout_append(struct layout_cell *lc, char *buf, size_t len)
73*eda6f593SDavid van Moolenbroek {
74*eda6f593SDavid van Moolenbroek 	struct layout_cell     *lcchild;
75*eda6f593SDavid van Moolenbroek 	char			tmp[64];
76*eda6f593SDavid van Moolenbroek 	size_t			tmplen;
77*eda6f593SDavid van Moolenbroek 	const char	       *brackets = "][";
78*eda6f593SDavid van Moolenbroek 
79*eda6f593SDavid van Moolenbroek 	if (len == 0)
80*eda6f593SDavid van Moolenbroek 		return (-1);
81*eda6f593SDavid van Moolenbroek 
82*eda6f593SDavid van Moolenbroek 	tmplen = xsnprintf(tmp, sizeof tmp,
83*eda6f593SDavid van Moolenbroek 	    "%ux%u,%u,%u", lc->sx, lc->sy, lc->xoff, lc->yoff);
84*eda6f593SDavid van Moolenbroek 	if (tmplen > (sizeof tmp) - 1)
85*eda6f593SDavid van Moolenbroek 		return (-1);
86*eda6f593SDavid van Moolenbroek 	if (strlcat(buf, tmp, len) >= len)
87*eda6f593SDavid van Moolenbroek 		return (-1);
88*eda6f593SDavid van Moolenbroek 
89*eda6f593SDavid van Moolenbroek 	switch (lc->type) {
90*eda6f593SDavid van Moolenbroek 	case LAYOUT_LEFTRIGHT:
91*eda6f593SDavid van Moolenbroek 		brackets = "}{";
92*eda6f593SDavid van Moolenbroek 		/* FALLTHROUGH */
93*eda6f593SDavid van Moolenbroek 	case LAYOUT_TOPBOTTOM:
94*eda6f593SDavid van Moolenbroek 		if (strlcat(buf, &brackets[1], len) >= len)
95*eda6f593SDavid van Moolenbroek 			return (-1);
96*eda6f593SDavid van Moolenbroek 		TAILQ_FOREACH(lcchild, &lc->cells, entry) {
97*eda6f593SDavid van Moolenbroek 			if (layout_append(lcchild, buf, len) != 0)
98*eda6f593SDavid van Moolenbroek 				return (-1);
99*eda6f593SDavid van Moolenbroek 			if (strlcat(buf, ",", len) >= len)
100*eda6f593SDavid van Moolenbroek 				return (-1);
101*eda6f593SDavid van Moolenbroek 		}
102*eda6f593SDavid van Moolenbroek 		buf[strlen(buf) - 1] = brackets[0];
103*eda6f593SDavid van Moolenbroek 		break;
104*eda6f593SDavid van Moolenbroek 	case LAYOUT_WINDOWPANE:
105*eda6f593SDavid van Moolenbroek 		break;
106*eda6f593SDavid van Moolenbroek 	}
107*eda6f593SDavid van Moolenbroek 
108*eda6f593SDavid van Moolenbroek 	return (0);
109*eda6f593SDavid van Moolenbroek }
110*eda6f593SDavid van Moolenbroek 
111*eda6f593SDavid van Moolenbroek /* Parse a layout string and arrange window as layout. */
112*eda6f593SDavid van Moolenbroek int
113*eda6f593SDavid van Moolenbroek layout_parse(struct window *w, const char *layout)
114*eda6f593SDavid van Moolenbroek {
115*eda6f593SDavid van Moolenbroek 	struct layout_cell	*lc, *lcchild;
116*eda6f593SDavid van Moolenbroek 	struct window_pane	*wp;
117*eda6f593SDavid van Moolenbroek 	u_int			 npanes, ncells, sx, sy;
118*eda6f593SDavid van Moolenbroek 	u_short			 csum;
119*eda6f593SDavid van Moolenbroek 
120*eda6f593SDavid van Moolenbroek 	/* Check validity. */
121*eda6f593SDavid van Moolenbroek 	if (sscanf(layout, "%hx,", &csum) != 1)
122*eda6f593SDavid van Moolenbroek 		return (-1);
123*eda6f593SDavid van Moolenbroek 	layout += 5;
124*eda6f593SDavid van Moolenbroek 	if (csum != layout_checksum(layout))
125*eda6f593SDavid van Moolenbroek 		return (-1);
126*eda6f593SDavid van Moolenbroek 
127*eda6f593SDavid van Moolenbroek 	/* Build the layout. */
128*eda6f593SDavid van Moolenbroek 	lc = layout_construct(NULL, &layout);
129*eda6f593SDavid van Moolenbroek 	if (lc == NULL)
130*eda6f593SDavid van Moolenbroek 		return (-1);
131*eda6f593SDavid van Moolenbroek 	if (*layout != '\0')
132*eda6f593SDavid van Moolenbroek 		goto fail;
133*eda6f593SDavid van Moolenbroek 
134*eda6f593SDavid van Moolenbroek 	/* Check this window will fit into the layout. */
135*eda6f593SDavid van Moolenbroek 	for (;;) {
136*eda6f593SDavid van Moolenbroek 		npanes = window_count_panes(w);
137*eda6f593SDavid van Moolenbroek 		ncells = layout_count_cells(lc);
138*eda6f593SDavid van Moolenbroek 		if (npanes > ncells)
139*eda6f593SDavid van Moolenbroek 			goto fail;
140*eda6f593SDavid van Moolenbroek 		if (npanes == ncells)
141*eda6f593SDavid van Moolenbroek 			break;
142*eda6f593SDavid van Moolenbroek 
143*eda6f593SDavid van Moolenbroek 		/* Fewer panes than cells - close the bottom right. */
144*eda6f593SDavid van Moolenbroek 		lcchild = layout_find_bottomright(lc);
145*eda6f593SDavid van Moolenbroek 		layout_destroy_cell(lcchild, &lc);
146*eda6f593SDavid van Moolenbroek 	}
147*eda6f593SDavid van Moolenbroek 
148*eda6f593SDavid van Moolenbroek 	/* Save the old window size and resize to the layout size. */
149*eda6f593SDavid van Moolenbroek 	sx = w->sx; sy = w->sy;
150*eda6f593SDavid van Moolenbroek 	window_resize(w, lc->sx, lc->sy);
151*eda6f593SDavid van Moolenbroek 
152*eda6f593SDavid van Moolenbroek 	/* Destroy the old layout and swap to the new. */
153*eda6f593SDavid van Moolenbroek 	layout_free_cell(w->layout_root);
154*eda6f593SDavid van Moolenbroek 	w->layout_root = lc;
155*eda6f593SDavid van Moolenbroek 
156*eda6f593SDavid van Moolenbroek 	/* Assign the panes into the cells. */
157*eda6f593SDavid van Moolenbroek 	wp = TAILQ_FIRST(&w->panes);
158*eda6f593SDavid van Moolenbroek 	layout_assign(&wp, lc);
159*eda6f593SDavid van Moolenbroek 
160*eda6f593SDavid van Moolenbroek 	/* Update pane offsets and sizes. */
161*eda6f593SDavid van Moolenbroek 	layout_fix_offsets(lc);
162*eda6f593SDavid van Moolenbroek 	layout_fix_panes(w, lc->sx, lc->sy);
163*eda6f593SDavid van Moolenbroek 
164*eda6f593SDavid van Moolenbroek 	/* Then resize the layout back to the original window size. */
165*eda6f593SDavid van Moolenbroek 	layout_resize(w, sx, sy);
166*eda6f593SDavid van Moolenbroek 	window_resize(w, sx, sy);
167*eda6f593SDavid van Moolenbroek 
168*eda6f593SDavid van Moolenbroek 	layout_print_cell(lc, __func__, 0);
169*eda6f593SDavid van Moolenbroek 
170*eda6f593SDavid van Moolenbroek 	return (0);
171*eda6f593SDavid van Moolenbroek 
172*eda6f593SDavid van Moolenbroek fail:
173*eda6f593SDavid van Moolenbroek 	layout_free_cell(lc);
174*eda6f593SDavid van Moolenbroek 	return (-1);
175*eda6f593SDavid van Moolenbroek }
176*eda6f593SDavid van Moolenbroek 
177*eda6f593SDavid van Moolenbroek /* Assign panes into cells. */
178*eda6f593SDavid van Moolenbroek void
179*eda6f593SDavid van Moolenbroek layout_assign(struct window_pane **wp, struct layout_cell *lc)
180*eda6f593SDavid van Moolenbroek {
181*eda6f593SDavid van Moolenbroek 	struct layout_cell	*lcchild;
182*eda6f593SDavid van Moolenbroek 
183*eda6f593SDavid van Moolenbroek 	switch (lc->type) {
184*eda6f593SDavid van Moolenbroek 	case LAYOUT_WINDOWPANE:
185*eda6f593SDavid van Moolenbroek 		layout_make_leaf(lc, *wp);
186*eda6f593SDavid van Moolenbroek 		*wp = TAILQ_NEXT(*wp, entry);
187*eda6f593SDavid van Moolenbroek 		return;
188*eda6f593SDavid van Moolenbroek 	case LAYOUT_LEFTRIGHT:
189*eda6f593SDavid van Moolenbroek 	case LAYOUT_TOPBOTTOM:
190*eda6f593SDavid van Moolenbroek 		TAILQ_FOREACH(lcchild, &lc->cells, entry)
191*eda6f593SDavid van Moolenbroek 			layout_assign(wp, lcchild);
192*eda6f593SDavid van Moolenbroek 		return;
193*eda6f593SDavid van Moolenbroek 	}
194*eda6f593SDavid van Moolenbroek }
195*eda6f593SDavid van Moolenbroek 
196*eda6f593SDavid van Moolenbroek /* Construct a cell from all or part of a layout tree. */
197*eda6f593SDavid van Moolenbroek struct layout_cell *
198*eda6f593SDavid van Moolenbroek layout_construct(struct layout_cell *lcparent, const char **layout)
199*eda6f593SDavid van Moolenbroek {
200*eda6f593SDavid van Moolenbroek 	struct layout_cell     *lc, *lcchild;
201*eda6f593SDavid van Moolenbroek 	u_int			sx, sy, xoff, yoff;
202*eda6f593SDavid van Moolenbroek 
203*eda6f593SDavid van Moolenbroek 	if (!isdigit((u_char) **layout))
204*eda6f593SDavid van Moolenbroek 		return (NULL);
205*eda6f593SDavid van Moolenbroek 	if (sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4)
206*eda6f593SDavid van Moolenbroek 		return (NULL);
207*eda6f593SDavid van Moolenbroek 
208*eda6f593SDavid van Moolenbroek 	while (isdigit((u_char) **layout))
209*eda6f593SDavid van Moolenbroek 		(*layout)++;
210*eda6f593SDavid van Moolenbroek 	if (**layout != 'x')
211*eda6f593SDavid van Moolenbroek 		return (NULL);
212*eda6f593SDavid van Moolenbroek 	(*layout)++;
213*eda6f593SDavid van Moolenbroek 	while (isdigit((u_char) **layout))
214*eda6f593SDavid van Moolenbroek 		(*layout)++;
215*eda6f593SDavid van Moolenbroek 	if (**layout != ',')
216*eda6f593SDavid van Moolenbroek 		return (NULL);
217*eda6f593SDavid van Moolenbroek 	(*layout)++;
218*eda6f593SDavid van Moolenbroek 	while (isdigit((u_char) **layout))
219*eda6f593SDavid van Moolenbroek 		(*layout)++;
220*eda6f593SDavid van Moolenbroek 	if (**layout != ',')
221*eda6f593SDavid van Moolenbroek 		return (NULL);
222*eda6f593SDavid van Moolenbroek 	(*layout)++;
223*eda6f593SDavid van Moolenbroek 	while (isdigit((u_char) **layout))
224*eda6f593SDavid van Moolenbroek 		(*layout)++;
225*eda6f593SDavid van Moolenbroek 
226*eda6f593SDavid van Moolenbroek 	lc = layout_create_cell(lcparent);
227*eda6f593SDavid van Moolenbroek 	lc->sx = sx;
228*eda6f593SDavid van Moolenbroek 	lc->sy = sy;
229*eda6f593SDavid van Moolenbroek 	lc->xoff = xoff;
230*eda6f593SDavid van Moolenbroek 	lc->yoff = yoff;
231*eda6f593SDavid van Moolenbroek 
232*eda6f593SDavid van Moolenbroek 	switch (**layout) {
233*eda6f593SDavid van Moolenbroek 	case ',':
234*eda6f593SDavid van Moolenbroek 	case '}':
235*eda6f593SDavid van Moolenbroek 	case ']':
236*eda6f593SDavid van Moolenbroek 	case '\0':
237*eda6f593SDavid van Moolenbroek 		return (lc);
238*eda6f593SDavid van Moolenbroek 	case '{':
239*eda6f593SDavid van Moolenbroek 		lc->type = LAYOUT_LEFTRIGHT;
240*eda6f593SDavid van Moolenbroek 		break;
241*eda6f593SDavid van Moolenbroek 	case '[':
242*eda6f593SDavid van Moolenbroek 		lc->type = LAYOUT_TOPBOTTOM;
243*eda6f593SDavid van Moolenbroek 		break;
244*eda6f593SDavid van Moolenbroek 	default:
245*eda6f593SDavid van Moolenbroek 		goto fail;
246*eda6f593SDavid van Moolenbroek 	}
247*eda6f593SDavid van Moolenbroek 
248*eda6f593SDavid van Moolenbroek 	do {
249*eda6f593SDavid van Moolenbroek 		(*layout)++;
250*eda6f593SDavid van Moolenbroek 		lcchild = layout_construct(lc, layout);
251*eda6f593SDavid van Moolenbroek 		if (lcchild == NULL)
252*eda6f593SDavid van Moolenbroek 			goto fail;
253*eda6f593SDavid van Moolenbroek 		TAILQ_INSERT_TAIL(&lc->cells, lcchild, entry);
254*eda6f593SDavid van Moolenbroek 	} while (**layout == ',');
255*eda6f593SDavid van Moolenbroek 
256*eda6f593SDavid van Moolenbroek 	switch (lc->type) {
257*eda6f593SDavid van Moolenbroek 	case LAYOUT_LEFTRIGHT:
258*eda6f593SDavid van Moolenbroek 		if (**layout != '}')
259*eda6f593SDavid van Moolenbroek 			goto fail;
260*eda6f593SDavid van Moolenbroek 		break;
261*eda6f593SDavid van Moolenbroek 	case LAYOUT_TOPBOTTOM:
262*eda6f593SDavid van Moolenbroek 		if (**layout != ']')
263*eda6f593SDavid van Moolenbroek 			goto fail;
264*eda6f593SDavid van Moolenbroek 		break;
265*eda6f593SDavid van Moolenbroek 	default:
266*eda6f593SDavid van Moolenbroek 		goto fail;
267*eda6f593SDavid van Moolenbroek 	}
268*eda6f593SDavid van Moolenbroek 	(*layout)++;
269*eda6f593SDavid van Moolenbroek 
270*eda6f593SDavid van Moolenbroek 	return (lc);
271*eda6f593SDavid van Moolenbroek 
272*eda6f593SDavid van Moolenbroek fail:
273*eda6f593SDavid van Moolenbroek 	layout_free_cell(lc);
274*eda6f593SDavid van Moolenbroek 	return (NULL);
275*eda6f593SDavid van Moolenbroek }
276