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