Change the way the working directory for new processes is discovered. If
[tmux-openbsd.git] / layout-custom.c
blob9fb9cebd1dac5a2ad450616ffd759fc5050a0806
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, "%4x,%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 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);
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);
102 buf[strlen(buf) - 1] = brackets[0];
103 break;
104 case LAYOUT_WINDOWPANE:
105 break;
108 return (0);
111 /* Parse a layout string and arrange window as layout. */
113 layout_parse(struct window *w, const char *layout)
115 struct layout_cell *lc, *lcchild;
116 struct window_pane *wp;
117 u_int npanes, ncells, sx, sy;
118 u_short csum;
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);
127 /* Build the layout. */
128 lc = layout_construct(NULL, &layout);
129 if (lc == NULL)
130 return (-1);
131 if (*layout != '\0')
132 goto fail;
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;
143 /* Fewer panes than cells - close the bottom right. */
144 lcchild = layout_find_bottomright(lc);
145 layout_destroy_cell(lcchild, &lc);
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);
152 /* Destroy the old layout and swap to the new. */
153 layout_free_cell(w->layout_root);
154 w->layout_root = lc;
156 /* Assign the panes into the cells. */
157 wp = TAILQ_FIRST(&w->panes);
158 layout_assign(&wp, lc);
160 /* Update pane offsets and sizes. */
161 layout_fix_offsets(lc);
162 layout_fix_panes(w, lc->sx, lc->sy);
164 /* Then resize the layout back to the original window size. */
165 layout_resize(w, sx, sy);
166 window_resize(w, sx, sy);
168 layout_print_cell(lc, __func__, 0);
170 return (0);
172 fail:
173 layout_free_cell(lc);
174 return (-1);
177 /* Assign panes into cells. */
178 void
179 layout_assign(struct window_pane **wp, struct layout_cell *lc)
181 struct layout_cell *lcchild;
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;
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)
200 struct layout_cell *lc, *lcchild;
201 u_int sx, sy, xoff, yoff;
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);
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)++;
226 lc = layout_create_cell(lcparent);
227 lc->sx = sx;
228 lc->sy = sy;
229 lc->xoff = xoff;
230 lc->yoff = yoff;
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;
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 == ',');
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;
268 (*layout)++;
270 return (lc);
272 fail:
273 layout_free_cell(lc);
274 return (NULL);