diff options
Diffstat (limited to 'sway/layout.c')
-rw-r--r-- | sway/layout.c | 275 |
1 files changed, 72 insertions, 203 deletions
diff --git a/sway/layout.c b/sway/layout.c index ccf29f34..8b9315b4 100644 --- a/sway/layout.c +++ b/sway/layout.c | |||
@@ -9,25 +9,75 @@ | |||
9 | 9 | ||
10 | swayc_t root_container; | 10 | swayc_t root_container; |
11 | 11 | ||
12 | swayc_t *find_container(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data) { | 12 | void init_layout(void) { |
13 | if (!container->children) { | 13 | root_container.type = C_ROOT; |
14 | root_container.layout = L_NONE; | ||
15 | root_container.children = create_list(); | ||
16 | root_container.handle = -1; | ||
17 | } | ||
18 | |||
19 | static int index_child(swayc_t *parent, swayc_t *child) { | ||
20 | int i; | ||
21 | for (i = 0; i < parent->children->length; ++i) { | ||
22 | if (parent->children->items[i] == child) { | ||
23 | break; | ||
24 | } | ||
25 | } | ||
26 | return i; | ||
27 | } | ||
28 | |||
29 | void add_child(swayc_t *parent, swayc_t *child) { | ||
30 | sway_log(L_DEBUG, "Adding %p (%d, %dx%d) to %p (%d, %dx%d)", child, child->type, | ||
31 | child->width, child->height, parent, parent->type, parent->width, parent->height); | ||
32 | list_add(parent->children, child); | ||
33 | child->parent = parent; | ||
34 | if (parent->focused == NULL) { | ||
35 | parent->focused = child; | ||
36 | } | ||
37 | } | ||
38 | |||
39 | swayc_t *add_sibling(swayc_t *sibling, swayc_t *child) { | ||
40 | swayc_t *parent = sibling->parent; | ||
41 | int i = index_child(parent, sibling); | ||
42 | if (i == parent->children->length) { | ||
43 | --i; | ||
44 | } | ||
45 | list_insert(parent->children, i+1, child); | ||
46 | child->parent = parent; | ||
47 | return child->parent; | ||
48 | } | ||
49 | |||
50 | swayc_t *replace_child(swayc_t *child, swayc_t *new_child) { | ||
51 | swayc_t *parent = child->parent; | ||
52 | if (parent == NULL) { | ||
14 | return NULL; | 53 | return NULL; |
15 | } | 54 | } |
55 | int i = index_child(parent, child); | ||
56 | parent->children->items[i] = new_child; | ||
57 | new_child->parent = child->parent; | ||
58 | |||
59 | if (child->parent->focused == child) { | ||
60 | child->parent->focused = new_child; | ||
61 | } | ||
62 | child->parent = NULL; | ||
63 | return parent; | ||
64 | } | ||
65 | |||
66 | swayc_t *remove_child(swayc_t *parent, swayc_t *child) { | ||
16 | int i; | 67 | int i; |
17 | for (i = 0; i < container->children->length; ++i) { | 68 | for (i = 0; i < parent->children->length; ++i) { |
18 | swayc_t *child = container->children->items[i]; | 69 | if (parent->children->items[i] == child) { |
19 | if (test(child, data)) { | 70 | list_del(parent->children, i); |
20 | return child; | 71 | break; |
21 | } else { | ||
22 | swayc_t *_ = find_container(child, test, data); | ||
23 | if (_) { | ||
24 | return _; | ||
25 | } | ||
26 | } | 72 | } |
27 | } | 73 | } |
28 | return NULL; | 74 | if (parent->focused == child) { |
75 | parent->focused = NULL; | ||
76 | } | ||
77 | return parent; | ||
29 | } | 78 | } |
30 | 79 | ||
80 | |||
31 | void arrange_windows(swayc_t *container, int width, int height) { | 81 | void arrange_windows(swayc_t *container, int width, int height) { |
32 | int i; | 82 | int i; |
33 | if (width == -1 || height == -1) { | 83 | if (width == -1 || height == -1) { |
@@ -68,7 +118,7 @@ void arrange_windows(swayc_t *container, int width, int height) { | |||
68 | }; | 118 | }; |
69 | if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) { | 119 | if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) { |
70 | swayc_t *parent = container; | 120 | swayc_t *parent = container; |
71 | while(parent->type != C_OUTPUT) { | 121 | while (parent->type != C_OUTPUT) { |
72 | parent = parent->parent; | 122 | parent = parent->parent; |
73 | } | 123 | } |
74 | geometry.origin.x = 0; | 124 | geometry.origin.x = 0; |
@@ -131,25 +181,6 @@ void arrange_windows(swayc_t *container, int width, int height) { | |||
131 | } | 181 | } |
132 | } | 182 | } |
133 | 183 | ||
134 | void init_layout(void) { | ||
135 | root_container.type = C_ROOT; | ||
136 | root_container.layout = L_NONE; | ||
137 | root_container.children = create_list(); | ||
138 | root_container.handle = -1; | ||
139 | } | ||
140 | |||
141 | void free_swayc(swayc_t *container) { | ||
142 | // NOTE: Does not handle moving children into a different container | ||
143 | if (container->parent) { | ||
144 | remove_container_from_parent(container->parent, container); | ||
145 | } | ||
146 | list_free(container->children); | ||
147 | if (container->name) { | ||
148 | free(container->name); | ||
149 | } | ||
150 | free(container); | ||
151 | } | ||
152 | |||
153 | swayc_t *get_swayc_for_handle(wlc_handle handle, swayc_t *parent) { | 184 | swayc_t *get_swayc_for_handle(wlc_handle handle, swayc_t *parent) { |
154 | if (parent->children == NULL) { | 185 | if (parent->children == NULL) { |
155 | return NULL; | 186 | return NULL; |
@@ -176,99 +207,6 @@ swayc_t *get_focused_container(swayc_t *parent) { | |||
176 | return get_focused_container(parent->focused); | 207 | return get_focused_container(parent->focused); |
177 | } | 208 | } |
178 | 209 | ||
179 | void add_view(wlc_handle view_handle) { | ||
180 | const uint32_t type = wlc_view_get_type(view_handle); | ||
181 | const char *title = wlc_view_get_title(view_handle); | ||
182 | if ((type & WLC_BIT_OVERRIDE_REDIRECT) || (type & WLC_BIT_UNMANAGED) || (type & | ||
183 | WLC_BIT_POPUP) || (type & WLC_BIT_MODAL) || (type & WLC_BIT_SPLASH)) { | ||
184 | sway_log(L_DEBUG, "Leaving view %d:%s alone (unmanaged)", view_handle, title); | ||
185 | unfocus_all(&root_container); | ||
186 | wlc_view_set_state(view_handle, WLC_BIT_ACTIVATED, true); | ||
187 | wlc_view_focus(view_handle); | ||
188 | return; | ||
189 | } | ||
190 | |||
191 | swayc_t *parent = get_focused_container(&root_container); | ||
192 | sway_log(L_DEBUG, "Adding new view %d:%s:%d under container %p %d", view_handle, title, type, parent, parent->type); | ||
193 | |||
194 | while (parent->type == C_VIEW) { | ||
195 | parent = parent->parent; | ||
196 | } | ||
197 | |||
198 | swayc_t *view = calloc(1, sizeof(swayc_t)); | ||
199 | view->weight = 1; | ||
200 | view->layout = L_NONE; | ||
201 | view->handle = view_handle; | ||
202 | view->parent = parent; | ||
203 | view->type = C_VIEW; | ||
204 | view->visible = true; | ||
205 | if (title) { | ||
206 | view->name = malloc(strlen(title) + 1); | ||
207 | strcpy(view->name, title); | ||
208 | } | ||
209 | add_child(parent, view); | ||
210 | |||
211 | unfocus_all(&root_container); | ||
212 | focus_view(view); | ||
213 | |||
214 | arrange_windows(parent, -1, -1); | ||
215 | } | ||
216 | |||
217 | int remove_container_from_parent(swayc_t *parent, swayc_t *container) { | ||
218 | int i; | ||
219 | for (i = 0; i < parent->children->length; ++i) { | ||
220 | if (parent->children->items[i] == container) { | ||
221 | list_del(parent->children, i); | ||
222 | break; | ||
223 | } | ||
224 | } | ||
225 | |||
226 | if (parent->focused == container) { | ||
227 | parent->focused = NULL; | ||
228 | } | ||
229 | |||
230 | return i; | ||
231 | } | ||
232 | |||
233 | void destroy_view(swayc_t *view) { | ||
234 | if (view == NULL) { | ||
235 | sway_log(L_DEBUG, "Warning: NULL passed into destroy_view"); | ||
236 | return; | ||
237 | } | ||
238 | sway_log(L_DEBUG, "Destroying container %p", view); | ||
239 | swayc_t *parent = view->parent; | ||
240 | if (!parent) { | ||
241 | return; | ||
242 | } | ||
243 | |||
244 | int i; | ||
245 | for (i = 0; i < parent->children->length; ++i) { | ||
246 | if (parent->children->items[i] == view) { | ||
247 | list_del(parent->children, i); | ||
248 | break; | ||
249 | } | ||
250 | } | ||
251 | |||
252 | free_swayc(view); | ||
253 | |||
254 | if (parent->focused == view) { | ||
255 | parent->focused = NULL; | ||
256 | } | ||
257 | |||
258 | unfocus_all(&root_container); | ||
259 | if (parent->children->length != 0) { | ||
260 | focus_view(parent->children->items[0]); | ||
261 | } else { | ||
262 | focus_view(parent); | ||
263 | } | ||
264 | |||
265 | arrange_windows(parent, -1, -1); | ||
266 | |||
267 | if (parent->children->length == 0 && parent->type == C_CONTAINER) { | ||
268 | destroy_view(parent); | ||
269 | } | ||
270 | } | ||
271 | |||
272 | void unfocus_all(swayc_t *container) { | 210 | void unfocus_all(swayc_t *container) { |
273 | if (container->children == NULL) { | 211 | if (container->children == NULL) { |
274 | return; | 212 | return; |
@@ -285,85 +223,16 @@ void unfocus_all(swayc_t *container) { | |||
285 | } | 223 | } |
286 | 224 | ||
287 | void focus_view(swayc_t *view) { | 225 | void focus_view(swayc_t *view) { |
288 | sway_log(L_DEBUG, "Setting focus for %p", view); | 226 | sway_log(L_DEBUG, "Setting focus to %p", view); |
289 | if (view == &root_container) { | 227 | if (view->type == C_VIEW) { |
290 | // Propegate wayland focus down | 228 | wlc_view_set_state(view->handle, WLC_BIT_ACTIVATED, true); |
291 | swayc_t *child = view->focused; | 229 | wlc_view_bring_to_front(view->handle); |
292 | while (child && child->type != C_VIEW) { | 230 | wlc_view_focus(view->handle); |
293 | child = child->focused; | ||
294 | } | ||
295 | if (child) { | ||
296 | wlc_view_set_state(child->handle, WLC_BIT_ACTIVATED, true); | ||
297 | wlc_view_focus(child->handle); | ||
298 | } | ||
299 | return; | ||
300 | } | ||
301 | view->parent->focused = view; | ||
302 | focus_view(view->parent); | ||
303 | } | ||
304 | |||
305 | void add_child(swayc_t *parent, swayc_t *child) { | ||
306 | sway_log(L_DEBUG, "Adding %p (%d, %dx%d) to %p (%d, %dx%d)", child, child->type, | ||
307 | child->width, child->height, parent, parent->type, parent->width, parent->height); | ||
308 | list_add(parent->children, child); | ||
309 | } | ||
310 | |||
311 | swayc_t *create_container(swayc_t *parent, wlc_handle handle) { | ||
312 | swayc_t *c = calloc(1, sizeof(swayc_t)); | ||
313 | c->weight = 1; | ||
314 | c->handle = handle; | ||
315 | c->parent = parent; | ||
316 | c->layout = L_NONE; | ||
317 | c->type = C_CONTAINER; | ||
318 | c->children = create_list(); | ||
319 | return c; | ||
320 | } | ||
321 | |||
322 | void add_output_widths(swayc_t *container, void *_width) { | ||
323 | int *width = _width; | ||
324 | if (container->type == C_OUTPUT) { | ||
325 | *width += container->width; | ||
326 | } | 231 | } |
327 | } | 232 | // Propagete focus up |
328 | 233 | while (view != &root_container) { | |
329 | void add_output(wlc_handle output) { | 234 | view->parent->focused = view; |
330 | sway_log(L_DEBUG, "Adding output %d", output); | 235 | view = view->parent; |
331 | const struct wlc_size* size = wlc_output_get_resolution(output); | ||
332 | |||
333 | swayc_t *container = create_container(&root_container, output); | ||
334 | container->type = C_OUTPUT; | ||
335 | container->width = size->w; | ||
336 | container->height = size->h; | ||
337 | add_child(&root_container, container); | ||
338 | |||
339 | int total_width = 0; | ||
340 | container_map(&root_container, add_output_widths, &total_width); | ||
341 | |||
342 | swayc_t *workspace = create_container(container, -1); | ||
343 | workspace->type = C_WORKSPACE; | ||
344 | workspace->name = workspace_next_name(); | ||
345 | workspace->width = size->w; // TODO: gaps | ||
346 | workspace->height = size->h; | ||
347 | workspace->layout = L_HORIZ; // TODO: Get default layout from config | ||
348 | add_child(container, workspace); | ||
349 | sway_log(L_DEBUG, "Added workspace %s for output %d", workspace->name, output); | ||
350 | |||
351 | if (root_container.focused == NULL) { | ||
352 | workspace_switch(workspace); | ||
353 | unfocus_all(&root_container); | ||
354 | focus_view(workspace); | ||
355 | } | 236 | } |
356 | } | 237 | } |
357 | 238 | ||
358 | void destroy_output(wlc_handle output) { | ||
359 | sway_log(L_DEBUG, "Destroying output %d", output); | ||
360 | int i; | ||
361 | for (i = 0; i < root_container.children->length; ++i) { | ||
362 | swayc_t *c = root_container.children->items[i]; | ||
363 | if (c->handle == output) { | ||
364 | list_del(root_container.children, i); | ||
365 | free_swayc(c); | ||
366 | return; | ||
367 | } | ||
368 | } | ||
369 | } | ||