Flag to flush all key bindings from Rob Paisley.
[tmux-openbsd.git] / layout-custom.c
blob617e3170a8cb77343acd3ce0607598828cb6c95b
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 u_short layout_checksum(const char *);
27 int layout_append(struct layout_cell *, char *, size_t);
28 struct layout_cell *layout_construct(struct layout_cell *, const char **);
29 void layout_assign(struct window_pane **, struct layout_cell *);
31 /* Calculate layout checksum. */
32 u_short
33 layout_checksum(const char *layout)
35 u_short csum;
37 csum = 0;
38 for (; *layout != '\0'; layout++) {
39 csum = (csum >> 1) + ((csum & 1) << 15);
40 csum += *layout;
42 return (csum);
45 /* Dump layout as a string. */
46 char *
47 layout_dump(struct window *w)
49 char layout[BUFSIZ], *out;
51 *layout = '\0';
52 if (layout_append(w->layout_root, layout, sizeof layout) != 0)
53 return (NULL);
55 xasprintf(&out, "%4x,%s", layout_checksum(layout), layout);
56 return (out);
59 /* Append information for a single cell. */
60 int
61 layout_append(struct layout_cell *lc, char *buf, size_t len)
63 struct layout_cell *lcchild;
64 char tmp[64];
65 size_t tmplen;
66 const char *brackets = "][";
68 if (len == 0)
69 return (-1);
71 tmplen = xsnprintf(tmp, sizeof tmp,
72 "%ux%u,%u,%u", lc->sx, lc->sy, lc->xoff, lc->yoff);
73 if (tmplen > (sizeof tmp) - 1)
74 return (-1);
75 if (strlcat(buf, tmp, len) >= len)
76 return (-1);
78 switch (lc->type) {
79 case LAYOUT_LEFTRIGHT:
80 brackets = "}{";
81 /* FALLTHROUGH */
82 case LAYOUT_TOPBOTTOM:
83 if (strlcat(buf, &brackets[1], len) >= len)
84 return (-1);
85 TAILQ_FOREACH(lcchild, &lc->cells, entry) {
86 if (layout_append(lcchild, buf, len) != 0)
87 return (-1);
88 if (strlcat(buf, ",", len) >= len)
89 return (-1);
91 buf[strlen(buf) - 1] = brackets[0];
92 break;
93 case LAYOUT_WINDOWPANE:
94 break;
97 return (0);
100 /* Parse a layout string and arrange window as layout. */
102 layout_parse(struct window *w, const char *layout)
104 struct layout_cell *lc, *lcchild;
105 struct window_pane *wp;
106 u_int npanes, ncells, sx, sy;
107 u_short csum;
109 /* Check validity. */
110 if (sscanf(layout, "%hx,", &csum) != 1)
111 return (-1);
112 layout += 5;
113 if (csum != layout_checksum(layout))
114 return (-1);
116 /* Build the layout. */
117 lc = layout_construct(NULL, &layout);
118 if (lc == NULL)
119 return (-1);
120 if (*layout != '\0')
121 goto fail;
123 /* Check this window will fit into the layout. */
124 for (;;) {
125 npanes = window_count_panes(w);
126 ncells = layout_count_cells(lc);
127 if (npanes > ncells)
128 goto fail;
129 if (npanes == ncells)
130 break;
132 /* Fewer panes than cells - close the bottom right. */
133 lcchild = layout_find_bottomright(lc);
134 layout_destroy_cell(lcchild, &lc);
137 /* Save the old window size and resize to the layout size. */
138 sx = w->sx; sy = w->sy;
139 window_resize(w, lc->sx, lc->sy);
141 /* Destroy the old layout and swap to the new. */
142 layout_free_cell(w->layout_root);
143 w->layout_root = lc;
145 /* Assign the panes into the cells. */
146 wp = TAILQ_FIRST(&w->panes);
147 layout_assign(&wp, lc);
149 /* Update pane offsets and sizes. */
150 layout_fix_offsets(lc);
151 layout_fix_panes(w, lc->sx, lc->sy);
153 /* Then resize the layout back to the original window size. */
154 layout_resize(w, sx, sy);
155 window_resize(w, sx, sy);
157 layout_print_cell(lc, __func__, 0);
159 return (0);
161 fail:
162 layout_free_cell(lc);
163 return (-1);
166 /* Assign panes into cells. */
167 void
168 layout_assign(struct window_pane **wp, struct layout_cell *lc)
170 struct layout_cell *lcchild;
172 switch (lc->type) {
173 case LAYOUT_WINDOWPANE:
174 layout_make_leaf(lc, *wp);
175 *wp = TAILQ_NEXT(*wp, entry);
176 return;
177 case LAYOUT_LEFTRIGHT:
178 case LAYOUT_TOPBOTTOM:
179 TAILQ_FOREACH(lcchild, &lc->cells, entry)
180 layout_assign(wp, lcchild);
181 return;
185 /* Construct a cell from all or part of a layout tree. */
186 struct layout_cell *
187 layout_construct(struct layout_cell *lcparent, const char **layout)
189 struct layout_cell *lc, *lcchild;
190 u_int sx, sy, xoff, yoff;
192 if (!isdigit((u_char) **layout))
193 return (NULL);
194 if (sscanf(*layout, "%ux%u,%u,%u", &sx, &sy, &xoff, &yoff) != 4)
195 return (NULL);
197 while (isdigit((u_char) **layout))
198 (*layout)++;
199 if (**layout != 'x')
200 return (NULL);
201 (*layout)++;
202 while (isdigit((u_char) **layout))
203 (*layout)++;
204 if (**layout != ',')
205 return (NULL);
206 (*layout)++;
207 while (isdigit((u_char) **layout))
208 (*layout)++;
209 if (**layout != ',')
210 return (NULL);
211 (*layout)++;
212 while (isdigit((u_char) **layout))
213 (*layout)++;
215 lc = layout_create_cell(lcparent);
216 lc->sx = sx;
217 lc->sy = sy;
218 lc->xoff = xoff;
219 lc->yoff = yoff;
221 switch (**layout) {
222 case ',':
223 case '}':
224 case ']':
225 case '\0':
226 return (lc);
227 case '{':
228 lc->type = LAYOUT_LEFTRIGHT;
229 break;
230 case '[':
231 lc->type = LAYOUT_TOPBOTTOM;
232 break;
233 default:
234 goto fail;
237 do {
238 (*layout)++;
239 lcchild = layout_construct(lc, layout);
240 if (lcchild == NULL)
241 goto fail;
242 TAILQ_INSERT_TAIL(&lc->cells, lcchild, entry);
243 } while (**layout == ',');
245 switch (lc->type) {
246 case LAYOUT_LEFTRIGHT:
247 if (**layout != '}')
248 goto fail;
249 break;
250 case LAYOUT_TOPBOTTOM:
251 if (**layout != ']')
252 goto fail;
253 break;
254 default:
255 goto fail;
257 (*layout)++;
259 return (lc);
261 fail:
262 layout_free_cell(lc);
263 return (NULL);