Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 276 lines (235 sloc) 6.259 kB
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
1 /* $Id: layout-custom.c 2553 2011-07-09 09:42:33Z tcunha $ */
fb53a63 @kfebert Imported Upstream version 1.3
kfebert authored
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
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
26 struct layout_cell *layout_find_bottomright(struct layout_cell *);
fb53a63 @kfebert Imported Upstream version 1.3
kfebert authored
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 *);
31
7216c39 @kfebert Imported Upstream version 1.5
kfebert authored
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 }
41
fb53a63 @kfebert Imported Upstream version 1.3
kfebert authored
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
82 tmplen = xsnprintf(tmp, sizeof tmp,
83 "%ux%u,%u,%u", lc->sx, lc->sy, lc->xoff, lc->yoff);
84 if (tmplen > (sizeof tmp) - 1)
85 return (-1);
86 if (strlcat(buf, tmp, len) >= len)
87 return (-1);
88
89 switch (lc->type) {
90 case LAYOUT_LEFTRIGHT:
91 brackets = "}{";
92 /* FALLTHROUGH */
93 case LAYOUT_TOPBOTTOM:
94 if (strlcat(buf, &brackets[1], len) >= len)
95 return (-1);
96 TAILQ_FOREACH(lcchild, &lc->cells, entry) {
97 if (layout_append(lcchild, buf, len) != 0)
98 return (-1);
99 if (strlcat(buf, ",", len) >= len)
100 return (-1);
101 }
102 buf[strlen(buf) - 1] = brackets[0];
103 break;
104 case LAYOUT_WINDOWPANE:
105 break;
106 }
107
108 return (0);
109 }
110
111 /* Parse a layout string and arrange window as layout. */
112 int
113 layout_parse(struct window *w, const char *layout)
114 {
115 struct layout_cell *lc, *lcchild;
116 struct window_pane *wp;
117 u_int npanes, ncells, sx, sy;
118 u_short csum;
119
120 /* Check validity. */
121 if (sscanf(layout, "%hx,", &csum) != 1)
122 return (-1);
123 layout += 5;
124 if (csum != layout_checksum(layout))
125 return (-1);
126
127 /* Build the layout. */
128 lc = layout_construct(NULL, &layout);
129 if (lc == NULL)
130 return (-1);
131 if (*layout != '\0')
132 goto fail;
133
134 /* Check this window will fit into the layout. */
135 for (;;) {
136 npanes = window_count_panes(w);
137 ncells = layout_count_cells(lc);
138 if (npanes > ncells)
139 goto fail;
140 if (npanes == ncells)
141 break;
142
143 /* Fewer panes than cells - close the bottom right. */
144 lcchild = layout_find_bottomright(lc);
145 layout_destroy_cell(lcchild, &lc);
146 }
147
148 /* Save the old window size and resize to the layout size. */
149 sx = w->sx; sy = w->sy;
150 window_resize(w, lc->sx, lc->sy);
151
152 /* Destroy the old layout and swap to the new. */
153 layout_free_cell(w->layout_root);
154 w->layout_root = lc;
155
156 /* Assign the panes into the cells. */
157 wp = TAILQ_FIRST(&w->panes);
158 layout_assign(&wp, lc);
159
160 /* Update pane offsets and sizes. */
161 layout_fix_offsets(lc);
162 layout_fix_panes(w, lc->sx, lc->sy);
163
164 /* Then resize the layout back to the original window size. */
165 layout_resize(w, sx, sy);
166 window_resize(w, sx, sy);
167
168 layout_print_cell(lc, __func__, 0);
169
170 return (0);
171
172 fail:
173 layout_free_cell(lc);
174 return (-1);
175 }
176
177 /* Assign panes into cells. */
178 void
179 layout_assign(struct window_pane **wp, struct layout_cell *lc)
180 {
181 struct layout_cell *lcchild;
182
183 switch (lc->type) {
184 case LAYOUT_WINDOWPANE:
185 layout_make_leaf(lc, *wp);
186 *wp = TAILQ_NEXT(*wp, entry);
187 return;
188 case LAYOUT_LEFTRIGHT:
189 case LAYOUT_TOPBOTTOM:
190 TAILQ_FOREACH(lcchild, &lc->cells, entry)
191 layout_assign(wp, lcchild);
192 return;
193 }
194 }
195
196 /* Construct a cell from all or part of a layout tree. */
197 struct layout_cell *
198 layout_construct(struct layout_cell *lcparent, const char **layout)
199 {
200 struct layout_cell *lc, *lcchild;
201 u_int sx, sy, xoff, yoff;
202
203 if (!isdigit((u_char) **layout))
204 return (NULL);
205 if (sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4)
206 return (NULL);
207
208 while (isdigit((u_char) **layout))
209 (*layout)++;
210 if (**layout != 'x')
211 return (NULL);
212 (*layout)++;
213 while (isdigit((u_char) **layout))
214 (*layout)++;
215 if (**layout != ',')
216 return (NULL);
217 (*layout)++;
218 while (isdigit((u_char) **layout))
219 (*layout)++;
220 if (**layout != ',')
221 return (NULL);
222 (*layout)++;
223 while (isdigit((u_char) **layout))
224 (*layout)++;
225
226 lc = layout_create_cell(lcparent);
227 lc->sx = sx;
228 lc->sy = sy;
229 lc->xoff = xoff;
230 lc->yoff = yoff;
231
232 switch (**layout) {
233 case ',':
234 case '}':
235 case ']':
236 case '\0':
237 return (lc);
238 case '{':
239 lc->type = LAYOUT_LEFTRIGHT;
240 break;
241 case '[':
242 lc->type = LAYOUT_TOPBOTTOM;
243 break;
244 default:
245 goto fail;
246 }
247
248 do {
249 (*layout)++;
250 lcchild = layout_construct(lc, layout);
251 if (lcchild == NULL)
252 goto fail;
253 TAILQ_INSERT_TAIL(&lc->cells, lcchild, entry);
254 } while (**layout == ',');
255
256 switch (lc->type) {
257 case LAYOUT_LEFTRIGHT:
258 if (**layout != '}')
259 goto fail;
260 break;
261 case LAYOUT_TOPBOTTOM:
262 if (**layout != ']')
263 goto fail;
264 break;
265 default:
266 goto fail;
267 }
268 (*layout)++;
269
270 return (lc);
271
272 fail:
273 layout_free_cell(lc);
274 return (NULL);
275 }
Something went wrong with that request. Please try again.