Annotation of src/usr.bin/tmux/layout-custom.c, Revision 1.4
1.4 ! nicm 1: /* $OpenBSD: layout-custom.c,v 1.3 2012/01/30 20:57:02 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
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 <ctype.h>
22: #include <string.h>
23:
24: #include "tmux.h"
25:
1.2 nicm 26: struct layout_cell *layout_find_bottomright(struct layout_cell *);
1.1 nicm 27: u_short layout_checksum(const char *);
28: int layout_append(struct layout_cell *, char *, size_t);
29: struct layout_cell *layout_construct(struct layout_cell *, const char **);
30: void layout_assign(struct window_pane **, struct layout_cell *);
1.2 nicm 31:
32: /* Find the bottom-right cell. */
33: struct layout_cell *
34: layout_find_bottomright(struct layout_cell *lc)
35: {
36: if (lc->type == LAYOUT_WINDOWPANE)
37: return (lc);
38: lc = TAILQ_LAST(&lc->cells, layout_cells);
39: return (layout_find_bottomright(lc));
40: }
1.1 nicm 41:
42: /* Calculate layout checksum. */
43: u_short
44: layout_checksum(const char *layout)
45: {
46: u_short csum;
47:
48: csum = 0;
49: for (; *layout != '\0'; layout++) {
50: csum = (csum >> 1) + ((csum & 1) << 15);
51: csum += *layout;
52: }
53: return (csum);
54: }
55:
56: /* Dump layout as a string. */
57: char *
58: layout_dump(struct window *w)
59: {
60: char layout[BUFSIZ], *out;
61:
62: *layout = '\0';
63: if (layout_append(w->layout_root, layout, sizeof layout) != 0)
64: return (NULL);
65:
66: xasprintf(&out, "%4x,%s", layout_checksum(layout), layout);
67: return (out);
68: }
69:
70: /* Append information for a single cell. */
71: int
72: layout_append(struct layout_cell *lc, char *buf, size_t len)
73: {
74: struct layout_cell *lcchild;
75: char tmp[64];
76: size_t tmplen;
77: const char *brackets = "][";
78:
79: if (len == 0)
80: return (-1);
81:
1.3 nicm 82: if (lc->wp != NULL) {
83: tmplen = xsnprintf(tmp, sizeof tmp, "%ux%u,%u,%u,%u",
84: lc->sx, lc->sy, lc->xoff, lc->yoff, lc->wp->id);
85: } else {
86: tmplen = xsnprintf(tmp, sizeof tmp, "%ux%u,%u,%u",
87: lc->sx, lc->sy, lc->xoff, lc->yoff);
88: }
1.1 nicm 89: if (tmplen > (sizeof tmp) - 1)
90: return (-1);
91: if (strlcat(buf, tmp, len) >= len)
92: return (-1);
93:
94: switch (lc->type) {
95: case LAYOUT_LEFTRIGHT:
96: brackets = "}{";
97: /* FALLTHROUGH */
98: case LAYOUT_TOPBOTTOM:
99: if (strlcat(buf, &brackets[1], len) >= len)
100: return (-1);
101: TAILQ_FOREACH(lcchild, &lc->cells, entry) {
102: if (layout_append(lcchild, buf, len) != 0)
103: return (-1);
104: if (strlcat(buf, ",", len) >= len)
105: return (-1);
106: }
107: buf[strlen(buf) - 1] = brackets[0];
108: break;
109: case LAYOUT_WINDOWPANE:
110: break;
111: }
112:
113: return (0);
114: }
115:
116: /* Parse a layout string and arrange window as layout. */
117: int
118: layout_parse(struct window *w, const char *layout)
119: {
120: struct layout_cell *lc, *lcchild;
121: struct window_pane *wp;
122: u_int npanes, ncells, sx, sy;
123: u_short csum;
124:
125: /* Check validity. */
126: if (sscanf(layout, "%hx,", &csum) != 1)
127: return (-1);
128: layout += 5;
129: if (csum != layout_checksum(layout))
130: return (-1);
131:
132: /* Build the layout. */
133: lc = layout_construct(NULL, &layout);
134: if (lc == NULL)
135: return (-1);
136: if (*layout != '\0')
137: goto fail;
138:
139: /* Check this window will fit into the layout. */
140: for (;;) {
141: npanes = window_count_panes(w);
142: ncells = layout_count_cells(lc);
143: if (npanes > ncells)
144: goto fail;
145: if (npanes == ncells)
146: break;
147:
148: /* Fewer panes than cells - close the bottom right. */
149: lcchild = layout_find_bottomright(lc);
150: layout_destroy_cell(lcchild, &lc);
151: }
152:
153: /* Save the old window size and resize to the layout size. */
154: sx = w->sx; sy = w->sy;
155: window_resize(w, lc->sx, lc->sy);
156:
157: /* Destroy the old layout and swap to the new. */
158: layout_free_cell(w->layout_root);
159: w->layout_root = lc;
160:
161: /* Assign the panes into the cells. */
162: wp = TAILQ_FIRST(&w->panes);
163: layout_assign(&wp, lc);
164:
165: /* Update pane offsets and sizes. */
166: layout_fix_offsets(lc);
167: layout_fix_panes(w, lc->sx, lc->sy);
168:
169: /* Then resize the layout back to the original window size. */
170: layout_resize(w, sx, sy);
171: window_resize(w, sx, sy);
172:
173: layout_print_cell(lc, __func__, 0);
174:
175: return (0);
176:
177: fail:
178: layout_free_cell(lc);
179: return (-1);
180: }
181:
182: /* Assign panes into cells. */
183: void
184: layout_assign(struct window_pane **wp, struct layout_cell *lc)
185: {
186: struct layout_cell *lcchild;
187:
188: switch (lc->type) {
189: case LAYOUT_WINDOWPANE:
190: layout_make_leaf(lc, *wp);
191: *wp = TAILQ_NEXT(*wp, entry);
192: return;
193: case LAYOUT_LEFTRIGHT:
194: case LAYOUT_TOPBOTTOM:
195: TAILQ_FOREACH(lcchild, &lc->cells, entry)
196: layout_assign(wp, lcchild);
197: return;
198: }
199: }
200:
201: /* Construct a cell from all or part of a layout tree. */
202: struct layout_cell *
203: layout_construct(struct layout_cell *lcparent, const char **layout)
204: {
205: struct layout_cell *lc, *lcchild;
206: u_int sx, sy, xoff, yoff;
207:
208: if (!isdigit((u_char) **layout))
209: return (NULL);
1.4 ! nicm 210: if (sscanf(*layout, "%ux%u,%u,%u,%*u", &sx, &sy, &xoff, &yoff) != 4 &&
1.3 nicm 211: sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4)
1.1 nicm 212: return (NULL);
213:
214: while (isdigit((u_char) **layout))
215: (*layout)++;
216: if (**layout != 'x')
217: return (NULL);
218: (*layout)++;
219: while (isdigit((u_char) **layout))
220: (*layout)++;
221: if (**layout != ',')
222: return (NULL);
223: (*layout)++;
224: while (isdigit((u_char) **layout))
225: (*layout)++;
226: if (**layout != ',')
227: return (NULL);
228: (*layout)++;
229: while (isdigit((u_char) **layout))
230: (*layout)++;
1.3 nicm 231: if (**layout == ',') {
232: (*layout)++;
233: while (isdigit((u_char) **layout))
234: (*layout)++;
235: }
1.1 nicm 236:
237: lc = layout_create_cell(lcparent);
238: lc->sx = sx;
239: lc->sy = sy;
240: lc->xoff = xoff;
241: lc->yoff = yoff;
242:
243: switch (**layout) {
244: case ',':
245: case '}':
246: case ']':
247: case '\0':
248: return (lc);
249: case '{':
250: lc->type = LAYOUT_LEFTRIGHT;
251: break;
252: case '[':
253: lc->type = LAYOUT_TOPBOTTOM;
254: break;
255: default:
256: goto fail;
257: }
258:
259: do {
260: (*layout)++;
261: lcchild = layout_construct(lc, layout);
262: if (lcchild == NULL)
263: goto fail;
264: TAILQ_INSERT_TAIL(&lc->cells, lcchild, entry);
265: } while (**layout == ',');
266:
267: switch (lc->type) {
268: case LAYOUT_LEFTRIGHT:
269: if (**layout != '}')
270: goto fail;
271: break;
272: case LAYOUT_TOPBOTTOM:
273: if (**layout != ']')
274: goto fail;
275: break;
276: default:
277: goto fail;
278: }
279: (*layout)++;
280:
281: return (lc);
282:
283: fail:
284: layout_free_cell(lc);
285: return (NULL);
286: }