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>
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. */
34 layout_find_bottomright(struct layout_cell
*lc
)
36 if (lc
->type
== LAYOUT_WINDOWPANE
)
38 lc
= TAILQ_LAST(&lc
->cells
, layout_cells
);
39 return (layout_find_bottomright(lc
));
42 /* Calculate layout checksum. */
44 layout_checksum(const char *layout
)
49 for (; *layout
!= '\0'; layout
++) {
50 csum
= (csum
>> 1) + ((csum
& 1) << 15);
56 /* Dump layout as a string. */
58 layout_dump(struct window
*w
)
60 char layout
[BUFSIZ
], *out
;
63 if (layout_append(w
->layout_root
, layout
, sizeof layout
) != 0)
66 xasprintf(&out
, "%04x,%s", layout_checksum(layout
), layout
);
70 /* Append information for a single cell. */
72 layout_append(struct layout_cell
*lc
, char *buf
, size_t len
)
74 struct layout_cell
*lcchild
;
77 const char *brackets
= "][";
83 tmplen
= xsnprintf(tmp
, sizeof tmp
, "%ux%u,%u,%u,%u",
84 lc
->sx
, lc
->sy
, lc
->xoff
, lc
->yoff
, lc
->wp
->id
);
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)
91 if (strlcat(buf
, tmp
, len
) >= len
)
95 case LAYOUT_LEFTRIGHT
:
98 case LAYOUT_TOPBOTTOM
:
99 if (strlcat(buf
, &brackets
[1], len
) >= len
)
101 TAILQ_FOREACH(lcchild
, &lc
->cells
, entry
) {
102 if (layout_append(lcchild
, buf
, len
) != 0)
104 if (strlcat(buf
, ",", len
) >= len
)
107 buf
[strlen(buf
) - 1] = brackets
[0];
109 case LAYOUT_WINDOWPANE
:
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
;
125 /* Check validity. */
126 if (sscanf(layout
, "%hx,", &csum
) != 1)
129 if (csum
!= layout_checksum(layout
))
132 /* Build the layout. */
133 lc
= layout_construct(NULL
, &layout
);
139 /* Check this window will fit into the layout. */
141 npanes
= window_count_panes(w
);
142 ncells
= layout_count_cells(lc
);
145 if (npanes
== ncells
)
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
);
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
);
180 layout_free_cell(lc
);
184 /* Assign panes into cells. */
186 layout_assign(struct window_pane
**wp
, struct layout_cell
*lc
)
188 struct layout_cell
*lcchild
;
191 case LAYOUT_WINDOWPANE
:
192 layout_make_leaf(lc
, *wp
);
193 *wp
= TAILQ_NEXT(*wp
, entry
);
195 case LAYOUT_LEFTRIGHT
:
196 case LAYOUT_TOPBOTTOM
:
197 TAILQ_FOREACH(lcchild
, &lc
->cells
, entry
)
198 layout_assign(wp
, lcchild
);
203 /* Construct a cell from all or part of a layout tree. */
205 layout_construct(struct layout_cell
*lcparent
, const char **layout
)
207 struct layout_cell
*lc
, *lcchild
;
208 u_int sx
, sy
, xoff
, yoff
;
211 if (!isdigit((u_char
) **layout
))
213 if (sscanf(*layout
, "%ux%u,%u,%u", &sx
, &sy
, &xoff
, &yoff
) != 4)
216 while (isdigit((u_char
) **layout
))
221 while (isdigit((u_char
) **layout
))
226 while (isdigit((u_char
) **layout
))
231 while (isdigit((u_char
) **layout
))
233 if (**layout
== ',') {
236 while (isdigit((u_char
) **layout
))
242 lc
= layout_create_cell(lcparent
);
255 lc
->type
= LAYOUT_LEFTRIGHT
;
258 lc
->type
= LAYOUT_TOPBOTTOM
;
266 lcchild
= layout_construct(lc
, layout
);
269 TAILQ_INSERT_TAIL(&lc
->cells
, lcchild
, entry
);
270 } while (**layout
== ',');
273 case LAYOUT_LEFTRIGHT
:
277 case LAYOUT_TOPBOTTOM
:
289 layout_free_cell(lc
);