Annotation of src/usr.bin/tmux/layout-custom.c, Revision 1.6
1.6 ! nicm 1: /* $OpenBSD: layout-custom.c,v 1.5 2012/03/17 22:35:09 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:
1.6 ! nicm 66: xasprintf(&out, "%04x,%s", layout_checksum(layout), layout);
1.1 nicm 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);
1.5 nicm 174:
175: notify_window_layout_changed(w);
1.1 nicm 176:
177: return (0);
178:
179: fail:
180: layout_free_cell(lc);
181: return (-1);
182: }
183:
184: /* Assign panes into cells. */
185: void
186: layout_assign(struct window_pane **wp, struct layout_cell *lc)
187: {
188: struct layout_cell *lcchild;
189:
190: switch (lc->type) {
191: case LAYOUT_WINDOWPANE:
192: layout_make_leaf(lc, *wp);
193: *wp = TAILQ_NEXT(*wp, entry);
194: return;
195: case LAYOUT_LEFTRIGHT:
196: case LAYOUT_TOPBOTTOM:
197: TAILQ_FOREACH(lcchild, &lc->cells, entry)
198: layout_assign(wp, lcchild);
199: return;
200: }
201: }
202:
203: /* Construct a cell from all or part of a layout tree. */
204: struct layout_cell *
205: layout_construct(struct layout_cell *lcparent, const char **layout)
206: {
207: struct layout_cell *lc, *lcchild;
208: u_int sx, sy, xoff, yoff;
1.6 ! nicm 209: const char *saved;
1.1 nicm 210:
211: if (!isdigit((u_char) **layout))
212: return (NULL);
1.6 ! nicm 213: if (sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4)
1.1 nicm 214: return (NULL);
215:
216: while (isdigit((u_char) **layout))
217: (*layout)++;
218: if (**layout != 'x')
219: return (NULL);
220: (*layout)++;
221: while (isdigit((u_char) **layout))
222: (*layout)++;
223: if (**layout != ',')
224: return (NULL);
225: (*layout)++;
226: while (isdigit((u_char) **layout))
227: (*layout)++;
228: if (**layout != ',')
229: return (NULL);
230: (*layout)++;
231: while (isdigit((u_char) **layout))
232: (*layout)++;
1.3 nicm 233: if (**layout == ',') {
1.6 ! nicm 234: saved = *layout;
1.3 nicm 235: (*layout)++;
236: while (isdigit((u_char) **layout))
237: (*layout)++;
1.6 ! nicm 238: if (**layout == 'x')
! 239: *layout = saved;
1.3 nicm 240: }
1.1 nicm 241:
242: lc = layout_create_cell(lcparent);
243: lc->sx = sx;
244: lc->sy = sy;
245: lc->xoff = xoff;
246: lc->yoff = yoff;
247:
248: switch (**layout) {
249: case ',':
250: case '}':
251: case ']':
252: case '\0':
253: return (lc);
254: case '{':
255: lc->type = LAYOUT_LEFTRIGHT;
256: break;
257: case '[':
258: lc->type = LAYOUT_TOPBOTTOM;
259: break;
260: default:
261: goto fail;
262: }
263:
264: do {
265: (*layout)++;
266: lcchild = layout_construct(lc, layout);
267: if (lcchild == NULL)
268: goto fail;
269: TAILQ_INSERT_TAIL(&lc->cells, lcchild, entry);
270: } while (**layout == ',');
271:
272: switch (lc->type) {
273: case LAYOUT_LEFTRIGHT:
274: if (**layout != '}')
275: goto fail;
276: break;
277: case LAYOUT_TOPBOTTOM:
278: if (**layout != ']')
279: goto fail;
280: break;
281: default:
282: goto fail;
283: }
284: (*layout)++;
285:
286: return (lc);
287:
288: fail:
289: layout_free_cell(lc);
290: return (NULL);
291: }