Change terminal-overrides to a server option (now that we have them), it
[tmux-openbsd.git] / layout-custom.c
blobc9cf49c2d8cb3bb47dd630e10ebca4c739b947a1
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
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.
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.
19 #include <sys/types.h>
21 #include <ctype.h>
22 #include <string.h>
24 #include "tmux.h"
26 struct layout_cell *layout_find_bottomright(struct layout_cell *);
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 *);
32 /* Find the bottom-right cell. */
33 struct layout_cell *
34 layout_find_bottomright(struct layout_cell *lc)
36 if (lc->type == LAYOUT_WINDOWPANE)
37 return (lc);
38 lc = TAILQ_LAST(&lc->cells, layout_cells);
39 return (layout_find_bottomright(lc));
42 /* Calculate layout checksum. */
43 u_short
44 layout_checksum(const char *layout)
46 u_short csum;
48 csum = 0;
49 for (; *layout != '\0'; layout++) {
50 csum = (csum >> 1) + ((csum & 1) << 15);
51 csum += *layout;
53 return (csum);
56 /* Dump layout as a string. */
57 char *
58 layout_dump(struct window *w)
60 char layout[BUFSIZ], *out;
62 *layout = '\0';
63 if (layout_append(w->layout_root, layout, sizeof layout) != 0)
64 return (NULL);
66 xasprintf(&out, "%04x,%s", layout_checksum(layout), layout);
67 return (out);
70 /* Append information for a single cell. */
71 int
72 layout_append(struct layout_cell *lc, char *buf, size_t len)
74 struct layout_cell *lcchild;
75 char tmp[64];
76 size_t tmplen;
77 const char *brackets = "][";
79 if (len == 0)
80 return (-1);
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);
89 if (tmplen > (sizeof tmp) - 1)
90 return (-1);
91 if (strlcat(buf, tmp, len) >= len)
92 return (-1);
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);
107 buf[strlen(buf) - 1] = brackets[0];
108 break;
109 case LAYOUT_WINDOWPANE:
110 break;
113 return (0);
116 /* Parse a layout string and arrange window as layout. */
118 layout_parse(struct window *w, const char *layout)
120 struct layout_cell *lc, *lcchild;
121 struct window_pane *wp;
122 u_int npanes, ncells, sx, sy;
123 u_short csum;
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);
132 /* Build the layout. */
133 lc = layout_construct(NULL, &layout);
134 if (lc == NULL)
135 return (-1);
136 if (*layout != '\0')
137 goto fail;
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;
148 /* Fewer panes than cells - close the bottom right. */
149 lcchild = layout_find_bottomright(lc);
150 layout_destroy_cell(lcchild, &lc);
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);
157 /* Destroy the old layout and swap to the new. */
158 layout_free_cell(w->layout_root);
159 w->layout_root = lc;
161 /* Assign the panes into the cells. */
162 wp = TAILQ_FIRST(&w->panes);
163 layout_assign(&wp, lc);
165 /* Update pane offsets and sizes. */
166 layout_fix_offsets(lc);
167 layout_fix_panes(w, lc->sx, lc->sy);
169 /* Then resize the layout back to the original window size. */
170 layout_resize(w, sx, sy);
171 window_resize(w, sx, sy);
173 layout_print_cell(lc, __func__, 0);
175 notify_window_layout_changed(w);
177 return (0);
179 fail:
180 layout_free_cell(lc);
181 return (-1);
184 /* Assign panes into cells. */
185 void
186 layout_assign(struct window_pane **wp, struct layout_cell *lc)
188 struct layout_cell *lcchild;
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;
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)
207 struct layout_cell *lc, *lcchild;
208 u_int sx, sy, xoff, yoff;
209 const char *saved;
211 if (!isdigit((u_char) **layout))
212 return (NULL);
213 if (sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4)
214 return (NULL);
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)++;
233 if (**layout == ',') {
234 saved = *layout;
235 (*layout)++;
236 while (isdigit((u_char) **layout))
237 (*layout)++;
238 if (**layout == 'x')
239 *layout = saved;
242 lc = layout_create_cell(lcparent);
243 lc->sx = sx;
244 lc->sy = sy;
245 lc->xoff = xoff;
246 lc->yoff = yoff;
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;
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 == ',');
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;
284 (*layout)++;
286 return (lc);
288 fail:
289 layout_free_cell(lc);
290 return (NULL);