aboutsummaryrefslogtreecommitdiffstats
path: root/sway/tree/container.c
diff options
context:
space:
mode:
authorLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-08-30 21:00:10 +1000
committerLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-09-05 18:01:43 +1000
commit7586f150c058997d9dde387ea7c091ffa7a3c3c7 (patch)
tree63d19027974c1db62ce3a74ca1d2314eb6d5049b /sway/tree/container.c
parentMerge pull request #2569 from RyanDwyer/deny-reload-repeat (diff)
downloadsway-7586f150c058997d9dde387ea7c091ffa7a3c3c7.tar.gz
sway-7586f150c058997d9dde387ea7c091ffa7a3c3c7.tar.zst
sway-7586f150c058997d9dde387ea7c091ffa7a3c3c7.zip
Implement type safe arguments and demote sway_container
This commit changes the meaning of sway_container so that it only refers to layout containers and view containers. Workspaces, outputs and the root are no longer known as containers. Instead, root, outputs, workspaces and containers are all a type of node, and containers come in two types: layout containers and view containers. In addition to the above, this implements type safe variables. This means we use specific types such as sway_output and sway_workspace instead of generic containers or nodes. However, it's worth noting that in a few places places (eg. seat focus and transactions) referring to them in a generic way is unavoidable which is why we still use nodes in some places. If you want a TL;DR, look at node.h, as well as the struct definitions for root, output, workspace and container. Note that sway_output now contains a workspaces list, and workspaces now contain a tiling and floating list, and containers now contain a pointer back to the workspace. There are now functions for seat_get_focused_workspace and seat_get_focused_container. The latter will return NULL if a workspace itself is focused. Most other seat functions like seat_get_focus and seat_set_focus now accept and return nodes. In the config->handler_context struct, current_container has been replaced with three pointers: node, container and workspace. node is the same as what current_container was, while workspace is the workspace that the node resides on and container is the actual container, which may be NULL if a workspace itself is focused. The global root_container variable has been replaced with one simply called root, which is a pointer to the sway_root instance. The way outputs are created, enabled, disabled and destroyed has changed. Previously we'd wrap the sway_output in a container when it is enabled, but as we don't have containers any more it needs a different approach. The output_create and output_destroy functions previously created/destroyed the container, but now they create/destroy the sway_output. There is a new function output_disable to disable an output without destroying it. Containers have a new view property. If this is populated then the container is a view container, otherwise it's a layout container. Like before, this property is immutable for the life of the container. Containers have both a `sway_container *parent` and `sway_workspace *workspace`. As we use specific types now, parent cannot point to a workspace so it'll be NULL for containers which are direct children of the workspace. The workspace property is set for all containers, except those which are hidden in the scratchpad as they have no workspace. In some cases we need to refer to workspaces in a container-like way. For example, workspaces have layout and children, but when using specific types this makes it difficult. Likewise, it's difficult for a container to get its parent's layout when the parent could be another container or a workspace. To make it easier, some helper functions have been created: container_parent_layout and container_get_siblings. container_remove_child has been renamed to container_detach and container_replace_child has been renamed to container_replace. `container_handle_fullscreen_reparent(con, old_parent)` has had the old_parent removed. We now unfullscreen the workspace when detaching the container, so this function is simplified and only needs one argument now. container_notify_subtree_changed has been renamed to container_update_representation. This is more descriptive of its purpose. I also wanted to be able to call it with whatever container was changed rather than the container's parent, which makes bubbling up to the workspace easier. There are now state structs per node thing. ie. sway_output_state, sway_workspace_state and sway_container_state. The focus, move and layout commands have been completely refactored to work with the specific types. I considered making these a separate PR, but I'd be backporting my changes only to replace them again, and it's easier just to test everything at once.
Diffstat (limited to 'sway/tree/container.c')
-rw-r--r--sway/tree/container.c871
1 files changed, 314 insertions, 557 deletions
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 520b4566..0cb8d0a5 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -24,97 +24,39 @@
24#include "log.h" 24#include "log.h"
25#include "stringop.h" 25#include "stringop.h"
26 26
27const char *container_type_to_str(enum sway_container_type type) { 27struct sway_container *container_create(struct sway_view *view) {
28 switch (type) {
29 case C_ROOT:
30 return "C_ROOT";
31 case C_OUTPUT:
32 return "C_OUTPUT";
33 case C_WORKSPACE:
34 return "C_WORKSPACE";
35 case C_CONTAINER:
36 return "C_CONTAINER";
37 case C_VIEW:
38 return "C_VIEW";
39 default:
40 return "C_UNKNOWN";
41 }
42}
43
44void container_create_notify(struct sway_container *container) {
45 if (container->type == C_VIEW) {
46 ipc_event_window(container, "new");
47 } else if (container->type == C_WORKSPACE) {
48 ipc_event_workspace(NULL, container, "init");
49 }
50 wl_signal_emit(&root_container.sway_root->events.new_container, container);
51}
52
53void container_update_textures_recursive(struct sway_container *con) {
54 if (con->type == C_CONTAINER || con->type == C_VIEW) {
55 container_update_title_textures(con);
56 }
57
58 if (con->type == C_VIEW) {
59 view_update_marks_textures(con->sway_view);
60 } else {
61 for (int i = 0; i < con->children->length; ++i) {
62 struct sway_container *child = con->children->items[i];
63 container_update_textures_recursive(child);
64 }
65
66 if (con->type == C_WORKSPACE) {
67 for (int i = 0; i < con->sway_workspace->floating->length; ++i) {
68 struct sway_container *floater =
69 con->sway_workspace->floating->items[i];
70 container_update_textures_recursive(floater);
71 }
72 }
73 }
74}
75
76struct sway_container *container_create(enum sway_container_type type) {
77 // next id starts at 1 because 0 is assigned to root_container in layout.c
78 static size_t next_id = 1;
79 struct sway_container *c = calloc(1, sizeof(struct sway_container)); 28 struct sway_container *c = calloc(1, sizeof(struct sway_container));
80 if (!c) { 29 if (!c) {
30 wlr_log(WLR_ERROR, "Unable to allocate sway_container");
81 return NULL; 31 return NULL;
82 } 32 }
83 c->id = next_id++; 33 node_init(&c->node, N_CONTAINER, c);
84 c->layout = L_NONE; 34 c->layout = L_NONE;
85 c->type = type; 35 c->view = view;
86 c->alpha = 1.0f; 36 c->alpha = 1.0f;
87 37
88 if (type != C_VIEW) { 38 if (!view) {
89 c->children = create_list(); 39 c->children = create_list();
90 c->current.children = create_list(); 40 c->current.children = create_list();
91 } 41 }
92 c->outputs = create_list(); 42 c->outputs = create_list();
93 43
94 wl_signal_init(&c->events.destroy); 44 wl_signal_init(&c->events.destroy);
95 45 wl_signal_emit(&root->events.new_node, &c->node);
96 c->has_gaps = false;
97 c->gaps_inner = 0;
98 c->gaps_outer = 0;
99 c->current_gaps = 0;
100 46
101 return c; 47 return c;
102} 48}
103 49
104void container_destroy(struct sway_container *con) { 50void container_destroy(struct sway_container *con) {
105 if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW, 51 if (!sway_assert(con->node.destroying,
106 "Expected a container or view")) {
107 return;
108 }
109 if (!sway_assert(con->destroying,
110 "Tried to free container which wasn't marked as destroying")) { 52 "Tried to free container which wasn't marked as destroying")) {
111 return; 53 return;
112 } 54 }
113 if (!sway_assert(con->ntxnrefs == 0, "Tried to free container " 55 if (!sway_assert(con->node.ntxnrefs == 0, "Tried to free container "
114 "which is still referenced by transactions")) { 56 "which is still referenced by transactions")) {
115 return; 57 return;
116 } 58 }
117 free(con->name); 59 free(con->title);
118 free(con->formatted_title); 60 free(con->formatted_title);
119 wlr_texture_destroy(con->title_focused); 61 wlr_texture_destroy(con->title_focused);
120 wlr_texture_destroy(con->title_focused_inactive); 62 wlr_texture_destroy(con->title_focused_inactive);
@@ -124,14 +66,14 @@ void container_destroy(struct sway_container *con) {
124 list_free(con->current.children); 66 list_free(con->current.children);
125 list_free(con->outputs); 67 list_free(con->outputs);
126 68
127 if (con->type == C_VIEW) { 69 if (con->view) {
128 struct sway_view *view = con->sway_view; 70 struct sway_view *view = con->view;
129 view->swayc = NULL; 71 view->container = NULL;
130 free(view->title_format); 72 free(view->title_format);
131 view->title_format = NULL; 73 view->title_format = NULL;
132 74
133 if (view->destroying) { 75 if (view->destroying) {
134 view_destroy(view); 76 view_destroy(con->view);
135 } 77 }
136 } 78 }
137 79
@@ -139,115 +81,57 @@ void container_destroy(struct sway_container *con) {
139} 81}
140 82
141void container_begin_destroy(struct sway_container *con) { 83void container_begin_destroy(struct sway_container *con) {
142 if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW, 84 if (con->view) {
143 "Expected a container or view")) {
144 return;
145 }
146
147 if (con->type == C_VIEW) {
148 ipc_event_window(con, "close"); 85 ipc_event_window(con, "close");
149 } 86 }
150 wl_signal_emit(&con->events.destroy, con); 87 wl_signal_emit(&con->node.events.destroy, &con->node);
151 88
152 container_end_mouse_operation(con); 89 container_end_mouse_operation(con);
153 90
154 con->destroying = true; 91 con->node.destroying = true;
155 container_set_dirty(con); 92 node_set_dirty(&con->node);
156 93
157 if (con->scratchpad) { 94 if (con->scratchpad) {
158 root_scratchpad_remove_container(con); 95 root_scratchpad_remove_container(con);
159 } 96 }
160 97
161 if (con->parent) { 98 if (con->parent || con->workspace) {
162 container_remove_child(con); 99 container_detach(con);
163 } 100 }
164} 101}
165 102
166struct sway_container *container_reap_empty(struct sway_container *con) { 103void container_reap_empty(struct sway_container *con) {
167 while (con && con->type == C_CONTAINER) { 104 if (con->view) {
168 struct sway_container *next = con->parent; 105 return;
169 if (con->children->length == 0) {
170 container_begin_destroy(con);
171 }
172 con = next;
173 } 106 }
174 if (con && con->type == C_WORKSPACE) { 107 struct sway_workspace *ws = con->workspace;
175 workspace_consider_destroy(con); 108 while (con) {
176 if (con->destroying) { 109 if (con->children->length) {
177 con = con->parent; 110 return;
178 } 111 }
112 struct sway_container *parent = con->parent;
113 container_begin_destroy(con);
114 con = parent;
179 } 115 }
180 return con; 116 workspace_consider_destroy(ws);
181} 117}
182 118
183struct sway_container *container_flatten(struct sway_container *container) { 119struct sway_container *container_flatten(struct sway_container *container) {
184 while (container->type == C_CONTAINER && container->children->length == 1) { 120 if (container->view) {
121 return NULL;
122 }
123 while (container && container->children->length == 1) {
185 struct sway_container *child = container->children->items[0]; 124 struct sway_container *child = container->children->items[0];
186 struct sway_container *parent = container->parent; 125 struct sway_container *parent = container->parent;
187 container_replace_child(container, child); 126 container_replace(container, child);
188 container_begin_destroy(container); 127 container_begin_destroy(container);
189 container = parent; 128 container = parent;
190 } 129 }
191 return container; 130 return container;
192} 131}
193 132
194static void container_close_func(struct sway_container *container, void *data) {
195 if (container->type == C_VIEW) {
196 view_close(container->sway_view);
197 }
198}
199
200struct sway_container *container_close(struct sway_container *con) {
201 if (!sway_assert(con != NULL,
202 "container_close called with a NULL container")) {
203 return NULL;
204 }
205
206 struct sway_container *parent = con->parent;
207
208 if (con->type == C_VIEW) {
209 view_close(con->sway_view);
210 } else if (con->type == C_CONTAINER) {
211 container_for_each_child(con, container_close_func, NULL);
212 } else if (con->type == C_WORKSPACE) {
213 workspace_for_each_container(con, container_close_func, NULL);
214 }
215
216 return parent;
217}
218
219struct sway_container *container_view_create(struct sway_container *sibling,
220 struct sway_view *sway_view) {
221 if (!sway_assert(sibling,
222 "container_view_create called with NULL sibling/parent")) {
223 return NULL;
224 }
225 const char *title = view_get_title(sway_view);
226 struct sway_container *swayc = container_create(C_VIEW);
227 wlr_log(WLR_DEBUG, "Adding new view %p:%s to container %p %d %s",
228 swayc, title, sibling, sibling ? sibling->type : 0, sibling->name);
229 // Setup values
230 swayc->sway_view = sway_view;
231 swayc->width = 0;
232 swayc->height = 0;
233
234 if (sibling->type == C_WORKSPACE) {
235 // Case of focused workspace, just create as child of it
236 container_add_child(sibling, swayc);
237 } else {
238 // Regular case, create as sibling of current container
239 container_add_sibling(sibling, swayc);
240 }
241 container_create_notify(swayc);
242 return swayc;
243}
244
245struct sway_container *container_find_child(struct sway_container *container, 133struct sway_container *container_find_child(struct sway_container *container,
246 bool (*test)(struct sway_container *view, void *data), void *data) { 134 bool (*test)(struct sway_container *con, void *data), void *data) {
247 if (!sway_assert(container->type == C_CONTAINER ||
248 container->type == C_VIEW, "Expected a container or view")) {
249 return NULL;
250 }
251 if (!container->children) { 135 if (!container->children) {
252 return NULL; 136 return NULL;
253 } 137 }
@@ -264,46 +148,32 @@ struct sway_container *container_find_child(struct sway_container *container,
264 return NULL; 148 return NULL;
265} 149}
266 150
267struct sway_container *container_parent(struct sway_container *container, 151static void surface_at_view(struct sway_container *con, double lx, double ly,
268 enum sway_container_type type) {
269 if (!sway_assert(container, "container is NULL")) {
270 return NULL;
271 }
272 if (!sway_assert(type < C_TYPES && type >= C_ROOT, "invalid type")) {
273 return NULL;
274 }
275 do {
276 container = container->parent;
277 } while (container && container->type != type);
278 return container;
279}
280
281static void surface_at_view(struct sway_container *swayc, double lx, double ly,
282 struct wlr_surface **surface, double *sx, double *sy) { 152 struct wlr_surface **surface, double *sx, double *sy) {
283 if (!sway_assert(swayc->type == C_VIEW, "Expected a view")) { 153 if (!sway_assert(con->view, "Expected a view")) {
284 return; 154 return;
285 } 155 }
286 struct sway_view *sview = swayc->sway_view; 156 struct sway_view *view = con->view;
287 double view_sx = lx - sview->x + sview->geometry.x; 157 double view_sx = lx - view->x + view->geometry.x;
288 double view_sy = ly - sview->y + sview->geometry.y; 158 double view_sy = ly - view->y + view->geometry.y;
289 159
290 double _sx, _sy; 160 double _sx, _sy;
291 struct wlr_surface *_surface = NULL; 161 struct wlr_surface *_surface = NULL;
292 switch (sview->type) { 162 switch (view->type) {
293#ifdef HAVE_XWAYLAND 163#ifdef HAVE_XWAYLAND
294 case SWAY_VIEW_XWAYLAND: 164 case SWAY_VIEW_XWAYLAND:
295 _surface = wlr_surface_surface_at(sview->surface, 165 _surface = wlr_surface_surface_at(view->surface,
296 view_sx, view_sy, &_sx, &_sy); 166 view_sx, view_sy, &_sx, &_sy);
297 break; 167 break;
298#endif 168#endif
299 case SWAY_VIEW_XDG_SHELL_V6: 169 case SWAY_VIEW_XDG_SHELL_V6:
300 _surface = wlr_xdg_surface_v6_surface_at( 170 _surface = wlr_xdg_surface_v6_surface_at(
301 sview->wlr_xdg_surface_v6, 171 view->wlr_xdg_surface_v6,
302 view_sx, view_sy, &_sx, &_sy); 172 view_sx, view_sy, &_sx, &_sy);
303 break; 173 break;
304 case SWAY_VIEW_XDG_SHELL: 174 case SWAY_VIEW_XDG_SHELL:
305 _surface = wlr_xdg_surface_surface_at( 175 _surface = wlr_xdg_surface_surface_at(
306 sview->wlr_xdg_surface, 176 view->wlr_xdg_surface,
307 view_sx, view_sy, &_sx, &_sy); 177 view_sx, view_sy, &_sx, &_sy);
308 break; 178 break;
309 } 179 }
@@ -317,65 +187,72 @@ static void surface_at_view(struct sway_container *swayc, double lx, double ly,
317/** 187/**
318 * container_at for a container with layout L_TABBED. 188 * container_at for a container with layout L_TABBED.
319 */ 189 */
320static struct sway_container *container_at_tabbed(struct sway_container *parent, 190static struct sway_container *container_at_tabbed(struct sway_node *parent,
321 double lx, double ly, 191 double lx, double ly,
322 struct wlr_surface **surface, double *sx, double *sy) { 192 struct wlr_surface **surface, double *sx, double *sy) {
323 if (ly < parent->y || ly > parent->y + parent->height) { 193 struct wlr_box box;
194 node_get_box(parent, &box);
195 if (ly < box.y || ly > box.y + box.height) {
324 return NULL; 196 return NULL;
325 } 197 }
326 struct sway_seat *seat = input_manager_current_seat(input_manager); 198 struct sway_seat *seat = input_manager_current_seat(input_manager);
199 list_t *children = node_get_children(parent);
327 200
328 // Tab titles 201 // Tab titles
329 int title_height = container_titlebar_height(); 202 int title_height = container_titlebar_height();
330 if (ly < parent->y + title_height) { 203 if (ly < box.y + title_height) {
331 int tab_width = parent->width / parent->children->length; 204 int tab_width = box.width / children->length;
332 int child_index = (lx - parent->x) / tab_width; 205 int child_index = (lx - box.x) / tab_width;
333 if (child_index >= parent->children->length) { 206 if (child_index >= children->length) {
334 child_index = parent->children->length - 1; 207 child_index = children->length - 1;
335 } 208 }
336 struct sway_container *child = parent->children->items[child_index]; 209 struct sway_container *child = children->items[child_index];
337 return seat_get_focus_inactive(seat, child); 210 struct sway_node *node = seat_get_focus_inactive(seat, &child->node);
211 return node->sway_container;
338 } 212 }
339 213
340 // Surfaces 214 // Surfaces
341 struct sway_container *current = seat_get_active_child(seat, parent); 215 struct sway_node *current = seat_get_active_child(seat, parent);
342
343 return tiling_container_at(current, lx, ly, surface, sx, sy); 216 return tiling_container_at(current, lx, ly, surface, sx, sy);
344} 217}
345 218
346/** 219/**
347 * container_at for a container with layout L_STACKED. 220 * container_at for a container with layout L_STACKED.
348 */ 221 */
349static struct sway_container *container_at_stacked( 222static struct sway_container *container_at_stacked(struct sway_node *parent,
350 struct sway_container *parent, double lx, double ly, 223 double lx, double ly,
351 struct wlr_surface **surface, double *sx, double *sy) { 224 struct wlr_surface **surface, double *sx, double *sy) {
352 if (ly < parent->y || ly > parent->y + parent->height) { 225 struct wlr_box box;
226 node_get_box(parent, &box);
227 if (ly < box.y || ly > box.y + box.height) {
353 return NULL; 228 return NULL;
354 } 229 }
355 struct sway_seat *seat = input_manager_current_seat(input_manager); 230 struct sway_seat *seat = input_manager_current_seat(input_manager);
231 list_t *children = node_get_children(parent);
356 232
357 // Title bars 233 // Title bars
358 int title_height = container_titlebar_height(); 234 int title_height = container_titlebar_height();
359 int child_index = (ly - parent->y) / title_height; 235 int child_index = (ly - box.y) / title_height;
360 if (child_index < parent->children->length) { 236 if (child_index < children->length) {
361 struct sway_container *child = parent->children->items[child_index]; 237 struct sway_container *child = children->items[child_index];
362 return seat_get_focus_inactive(seat, child); 238 struct sway_node *node = seat_get_focus_inactive(seat, &child->node);
239 return node->sway_container;
363 } 240 }
364 241
365 // Surfaces 242 // Surfaces
366 struct sway_container *current = seat_get_active_child(seat, parent); 243 struct sway_node *current = seat_get_active_child(seat, parent);
367
368 return tiling_container_at(current, lx, ly, surface, sx, sy); 244 return tiling_container_at(current, lx, ly, surface, sx, sy);
369} 245}
370 246
371/** 247/**
372 * container_at for a container with layout L_HORIZ or L_VERT. 248 * container_at for a container with layout L_HORIZ or L_VERT.
373 */ 249 */
374static struct sway_container *container_at_linear(struct sway_container *parent, 250static struct sway_container *container_at_linear(struct sway_node *parent,
375 double lx, double ly, 251 double lx, double ly,
376 struct wlr_surface **surface, double *sx, double *sy) { 252 struct wlr_surface **surface, double *sx, double *sy) {
377 for (int i = 0; i < parent->children->length; ++i) { 253 list_t *children = node_get_children(parent);
378 struct sway_container *child = parent->children->items[i]; 254 for (int i = 0; i < children->length; ++i) {
255 struct sway_container *child = children->items[i];
379 struct wlr_box box = { 256 struct wlr_box box = {
380 .x = child->x, 257 .x = child->x,
381 .y = child->y, 258 .y = child->y,
@@ -383,7 +260,7 @@ static struct sway_container *container_at_linear(struct sway_container *parent,
383 .height = child->height, 260 .height = child->height,
384 }; 261 };
385 if (wlr_box_contains_point(&box, lx, ly)) { 262 if (wlr_box_contains_point(&box, lx, ly)) {
386 return tiling_container_at(child, lx, ly, surface, sx, sy); 263 return tiling_container_at(&child->node, lx, ly, surface, sx, sy);
387 } 264 }
388 } 265 }
389 return NULL; 266 return NULL;
@@ -391,12 +268,11 @@ static struct sway_container *container_at_linear(struct sway_container *parent,
391 268
392static struct sway_container *floating_container_at(double lx, double ly, 269static struct sway_container *floating_container_at(double lx, double ly,
393 struct wlr_surface **surface, double *sx, double *sy) { 270 struct wlr_surface **surface, double *sx, double *sy) {
394 for (int i = 0; i < root_container.children->length; ++i) { 271 for (int i = 0; i < root->outputs->length; ++i) {
395 struct sway_container *output = root_container.children->items[i]; 272 struct sway_output *output = root->outputs->items[i];
396 for (int j = 0; j < output->children->length; ++j) { 273 for (int j = 0; j < output->workspaces->length; ++j) {
397 struct sway_container *workspace = output->children->items[j]; 274 struct sway_workspace *ws = output->workspaces->items[j];
398 struct sway_workspace *ws = workspace->sway_workspace; 275 if (!workspace_is_visible(ws)) {
399 if (!workspace_is_visible(workspace)) {
400 continue; 276 continue;
401 } 277 }
402 // Items at the end of the list are on top, so iterate the list in 278 // Items at the end of the list are on top, so iterate the list in
@@ -410,7 +286,7 @@ static struct sway_container *floating_container_at(double lx, double ly,
410 .height = floater->height, 286 .height = floater->height,
411 }; 287 };
412 if (wlr_box_contains_point(&box, lx, ly)) { 288 if (wlr_box_contains_point(&box, lx, ly)) {
413 return tiling_container_at(floater, lx, ly, 289 return tiling_container_at(&floater->node, lx, ly,
414 surface, sx, sy); 290 surface, sx, sy);
415 } 291 }
416 } 292 }
@@ -419,25 +295,24 @@ static struct sway_container *floating_container_at(double lx, double ly,
419 return NULL; 295 return NULL;
420} 296}
421 297
422struct sway_container *tiling_container_at( 298struct sway_container *tiling_container_at(struct sway_node *parent,
423 struct sway_container *con, double lx, double ly, 299 double lx, double ly,
424 struct wlr_surface **surface, double *sx, double *sy) { 300 struct wlr_surface **surface, double *sx, double *sy) {
425 if (con->type == C_VIEW) { 301 if (node_is_view(parent)) {
426 surface_at_view(con, lx, ly, surface, sx, sy); 302 surface_at_view(parent->sway_container, lx, ly, surface, sx, sy);
427 return con; 303 return parent->sway_container;
428 } 304 }
429 if (!con->children->length) { 305 if (!node_get_children(parent)) {
430 return NULL; 306 return NULL;
431 } 307 }
432 308 switch (node_get_layout(parent)) {
433 switch (con->layout) {
434 case L_HORIZ: 309 case L_HORIZ:
435 case L_VERT: 310 case L_VERT:
436 return container_at_linear(con, lx, ly, surface, sx, sy); 311 return container_at_linear(parent, lx, ly, surface, sx, sy);
437 case L_TABBED: 312 case L_TABBED:
438 return container_at_tabbed(con, lx, ly, surface, sx, sy); 313 return container_at_tabbed(parent, lx, ly, surface, sx, sy);
439 case L_STACKED: 314 case L_STACKED:
440 return container_at_stacked(con, lx, ly, surface, sx, sy); 315 return container_at_stacked(parent, lx, ly, surface, sx, sy);
441 case L_NONE: 316 case L_NONE:
442 return NULL; 317 return NULL;
443 } 318 }
@@ -472,19 +347,16 @@ static bool surface_is_popup(struct wlr_surface *surface) {
472 return false; 347 return false;
473} 348}
474 349
475struct sway_container *container_at(struct sway_container *workspace, 350struct sway_container *container_at(struct sway_workspace *workspace,
476 double lx, double ly, 351 double lx, double ly,
477 struct wlr_surface **surface, double *sx, double *sy) { 352 struct wlr_surface **surface, double *sx, double *sy) {
478 if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) {
479 return NULL;
480 }
481 struct sway_container *c; 353 struct sway_container *c;
354 // Focused view's popups
482 struct sway_seat *seat = input_manager_current_seat(input_manager); 355 struct sway_seat *seat = input_manager_current_seat(input_manager);
483 struct sway_container *focus = 356 struct sway_container *focus = seat_get_focused_container(seat);
484 seat_get_focus_inactive(seat, &root_container);
485 bool is_floating = focus && container_is_floating_or_child(focus); 357 bool is_floating = focus && container_is_floating_or_child(focus);
486 // Focused view's popups 358 // Focused view's popups
487 if (focus && focus->type == C_VIEW) { 359 if (focus && focus->view) {
488 surface_at_view(focus, lx, ly, surface, sx, sy); 360 surface_at_view(focus, lx, ly, surface, sx, sy);
489 if (*surface && surface_is_popup(*surface)) { 361 if (*surface && surface_is_popup(*surface)) {
490 return focus; 362 return focus;
@@ -492,7 +364,7 @@ struct sway_container *container_at(struct sway_container *workspace,
492 *surface = NULL; 364 *surface = NULL;
493 } 365 }
494 // If focused is floating, focused view's non-popups 366 // If focused is floating, focused view's non-popups
495 if (focus && focus->type == C_VIEW && is_floating) { 367 if (focus && focus->view && is_floating) {
496 surface_at_view(focus, lx, ly, surface, sx, sy); 368 surface_at_view(focus, lx, ly, surface, sx, sy);
497 if (*surface) { 369 if (*surface) {
498 return focus; 370 return focus;
@@ -504,7 +376,7 @@ struct sway_container *container_at(struct sway_container *workspace,
504 return c; 376 return c;
505 } 377 }
506 // If focused is tiling, focused view's non-popups 378 // If focused is tiling, focused view's non-popups
507 if (focus && focus->type == C_VIEW && !is_floating) { 379 if (focus && focus->view && !is_floating) {
508 surface_at_view(focus, lx, ly, surface, sx, sy); 380 surface_at_view(focus, lx, ly, surface, sx, sy);
509 if (*surface) { 381 if (*surface) {
510 return focus; 382 return focus;
@@ -512,7 +384,7 @@ struct sway_container *container_at(struct sway_container *workspace,
512 *surface = NULL; 384 *surface = NULL;
513 } 385 }
514 // Tiling (non-focused) 386 // Tiling (non-focused)
515 if ((c = tiling_container_at(workspace, lx, ly, surface, sx, sy))) { 387 if ((c = tiling_container_at(&workspace->node, lx, ly, surface, sx, sy))) {
516 return c; 388 return c;
517 } 389 }
518 return NULL; 390 return NULL;
@@ -521,10 +393,6 @@ struct sway_container *container_at(struct sway_container *workspace,
521void container_for_each_child(struct sway_container *container, 393void container_for_each_child(struct sway_container *container,
522 void (*f)(struct sway_container *container, void *data), 394 void (*f)(struct sway_container *container, void *data),
523 void *data) { 395 void *data) {
524 if (!sway_assert(container->type == C_CONTAINER ||
525 container->type == C_VIEW, "Expected a container or view")) {
526 return;
527 }
528 if (container->children) { 396 if (container->children) {
529 for (int i = 0; i < container->children->length; ++i) { 397 for (int i = 0; i < container->children->length; ++i) {
530 struct sway_container *child = container->children->items[i]; 398 struct sway_container *child = container->children->items[i];
@@ -536,7 +404,7 @@ void container_for_each_child(struct sway_container *container,
536 404
537bool container_has_ancestor(struct sway_container *descendant, 405bool container_has_ancestor(struct sway_container *descendant,
538 struct sway_container *ancestor) { 406 struct sway_container *ancestor) {
539 while (descendant && descendant->type != C_ROOT) { 407 while (descendant) {
540 descendant = descendant->parent; 408 descendant = descendant->parent;
541 if (descendant == ancestor) { 409 if (descendant == ancestor) {
542 return true; 410 return true;
@@ -545,27 +413,10 @@ bool container_has_ancestor(struct sway_container *descendant,
545 return false; 413 return false;
546} 414}
547 415
548int container_count_descendants_of_type(struct sway_container *con,
549 enum sway_container_type type) {
550 int children = 0;
551 if (con->type == type) {
552 children++;
553 }
554 if (con->children) {
555 for (int i = 0; i < con->children->length; i++) {
556 struct sway_container *child = con->children->items[i];
557 children += container_count_descendants_of_type(child, type);
558 }
559 }
560 return children;
561}
562
563void container_damage_whole(struct sway_container *container) { 416void container_damage_whole(struct sway_container *container) {
564 for (int i = 0; i < root_container.children->length; ++i) { 417 for (int i = 0; i < root->outputs->length; ++i) {
565 struct sway_container *cont = root_container.children->items[i]; 418 struct sway_output *output = root->outputs->items[i];
566 if (cont->type == C_OUTPUT) { 419 output_damage_whole_container(output, container);
567 output_damage_whole_container(cont->sway_output, container);
568 }
569 } 420 }
570} 421}
571 422
@@ -582,10 +433,6 @@ struct sway_output *container_get_effective_output(struct sway_container *con) {
582 433
583static void update_title_texture(struct sway_container *con, 434static void update_title_texture(struct sway_container *con,
584 struct wlr_texture **texture, struct border_colors *class) { 435 struct wlr_texture **texture, struct border_colors *class) {
585 if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW,
586 "Unexpected type %s", container_type_to_str(con->type))) {
587 return;
588 }
589 struct sway_output *output = container_get_effective_output(con); 436 struct sway_output *output = container_get_effective_output(con);
590 if (!output) { 437 if (!output) {
591 return; 438 return;
@@ -664,9 +511,10 @@ void container_calculate_title_height(struct sway_container *container) {
664 * An example tree representation is: V[Terminal, Firefox] 511 * An example tree representation is: V[Terminal, Firefox]
665 * If buffer is not NULL, also populate the buffer with the representation. 512 * If buffer is not NULL, also populate the buffer with the representation.
666 */ 513 */
667static size_t get_tree_representation(struct sway_container *parent, char *buffer) { 514size_t container_build_representation(enum sway_container_layout layout,
515 list_t *children, char *buffer) {
668 size_t len = 2; 516 size_t len = 2;
669 switch (parent->layout) { 517 switch (layout) {
670 case L_VERT: 518 case L_VERT:
671 lenient_strcat(buffer, "V["); 519 lenient_strcat(buffer, "V[");
672 break; 520 break;
@@ -683,17 +531,17 @@ static size_t get_tree_representation(struct sway_container *parent, char *buffe
683 lenient_strcat(buffer, "D["); 531 lenient_strcat(buffer, "D[");
684 break; 532 break;
685 } 533 }
686 for (int i = 0; i < parent->children->length; ++i) { 534 for (int i = 0; i < children->length; ++i) {
687 if (i != 0) { 535 if (i != 0) {
688 ++len; 536 ++len;
689 lenient_strcat(buffer, " "); 537 lenient_strcat(buffer, " ");
690 } 538 }
691 struct sway_container *child = parent->children->items[i]; 539 struct sway_container *child = children->items[i];
692 const char *identifier = NULL; 540 const char *identifier = NULL;
693 if (child->type == C_VIEW) { 541 if (child->view) {
694 identifier = view_get_class(child->sway_view); 542 identifier = view_get_class(child->view);
695 if (!identifier) { 543 if (!identifier) {
696 identifier = view_get_app_id(child->sway_view); 544 identifier = view_get_app_id(child->view);
697 } 545 }
698 } else { 546 } else {
699 identifier = child->formatted_title; 547 identifier = child->formatted_title;
@@ -711,25 +559,25 @@ static size_t get_tree_representation(struct sway_container *parent, char *buffe
711 return len; 559 return len;
712} 560}
713 561
714void container_notify_subtree_changed(struct sway_container *container) { 562void container_update_representation(struct sway_container *con) {
715 if (!container || container->type < C_WORKSPACE) { 563 if (!con->view) {
716 return; 564 size_t len = container_build_representation(con->layout,
717 } 565 con->children, NULL);
718 free(container->formatted_title); 566 free(con->formatted_title);
719 container->formatted_title = NULL; 567 con->formatted_title = calloc(len + 1, sizeof(char));
720 568 if (!sway_assert(con->formatted_title,
721 size_t len = get_tree_representation(container, NULL); 569 "Unable to allocate title string")) {
722 char *buffer = calloc(len + 1, sizeof(char)); 570 return;
723 if (!sway_assert(buffer, "Unable to allocate title string")) { 571 }
724 return; 572 container_build_representation(con->layout, con->children,
573 con->formatted_title);
574 container_calculate_title_height(con);
575 container_update_title_textures(con);
725 } 576 }
726 get_tree_representation(container, buffer); 577 if (con->parent) {
727 578 container_update_representation(con->parent);
728 container->formatted_title = buffer; 579 } else if (con->workspace) {
729 if (container->type != C_WORKSPACE) { 580 workspace_update_representation(con->workspace);
730 container_calculate_title_height(container);
731 container_update_title_textures(container);
732 container_notify_subtree_changed(container->parent);
733 } 581 }
734} 582}
735 583
@@ -738,11 +586,7 @@ size_t container_titlebar_height() {
738} 586}
739 587
740void container_init_floating(struct sway_container *con) { 588void container_init_floating(struct sway_container *con) {
741 if (!sway_assert(con->type == C_VIEW || con->type == C_CONTAINER, 589 struct sway_workspace *ws = con->workspace;
742 "Expected a view or container")) {
743 return;
744 }
745 struct sway_container *ws = container_parent(con, C_WORKSPACE);
746 int min_width, min_height; 590 int min_width, min_height;
747 int max_width, max_height; 591 int max_width, max_height;
748 592
@@ -778,13 +622,13 @@ void container_init_floating(struct sway_container *con) {
778 max_height = config->floating_maximum_height; 622 max_height = config->floating_maximum_height;
779 } 623 }
780 624
781 if (con->type == C_CONTAINER) { 625 if (!con->view) {
782 con->width = max_width; 626 con->width = max_width;
783 con->height = max_height; 627 con->height = max_height;
784 con->x = ws->x + (ws->width - con->width) / 2; 628 con->x = ws->x + (ws->width - con->width) / 2;
785 con->y = ws->y + (ws->height - con->height) / 2; 629 con->y = ws->y + (ws->height - con->height) / 2;
786 } else { 630 } else {
787 struct sway_view *view = con->sway_view; 631 struct sway_view *view = con->view;
788 view->width = fmax(min_width, fmin(view->natural_width, max_width)); 632 view->width = fmax(min_width, fmin(view->natural_width, max_width));
789 view->height = fmax(min_height, fmin(view->natural_height, max_height)); 633 view->height = fmax(min_height, fmin(view->natural_height, max_height));
790 view->x = ws->x + (ws->width - view->width) / 2; 634 view->x = ws->x + (ws->width - view->width) / 2;
@@ -794,7 +638,7 @@ void container_init_floating(struct sway_container *con) {
794 view->border_top = view->border_bottom = true; 638 view->border_top = view->border_bottom = true;
795 view->border_left = view->border_right = true; 639 view->border_left = view->border_right = true;
796 640
797 container_set_geometry_from_floating_view(view->swayc); 641 container_set_geometry_from_floating_view(con);
798 } 642 }
799} 643}
800 644
@@ -804,32 +648,41 @@ void container_set_floating(struct sway_container *container, bool enable) {
804 } 648 }
805 649
806 struct sway_seat *seat = input_manager_current_seat(input_manager); 650 struct sway_seat *seat = input_manager_current_seat(input_manager);
807 struct sway_container *workspace = container_parent(container, C_WORKSPACE); 651 struct sway_workspace *workspace = container->workspace;
808 652
809 if (enable) { 653 if (enable) {
810 struct sway_container *old_parent = container_remove_child(container); 654 struct sway_container *old_parent = container->parent;
655 container_detach(container);
811 workspace_add_floating(workspace, container); 656 workspace_add_floating(workspace, container);
812 container_init_floating(container); 657 container_init_floating(container);
813 if (container->type == C_VIEW) { 658 if (container->view) {
814 view_set_tiled(container->sway_view, false); 659 view_set_tiled(container->view, false);
660 }
661 if (old_parent) {
662 container_reap_empty(old_parent);
815 } 663 }
816 container_reap_empty(old_parent);
817 } else { 664 } else {
818 // Returning to tiled 665 // Returning to tiled
819 if (container->scratchpad) { 666 if (container->scratchpad) {
820 root_scratchpad_remove_container(container); 667 root_scratchpad_remove_container(container);
821 } 668 }
822 container_remove_child(container); 669 container_detach(container);
823 struct sway_container *reference = 670 struct sway_container *reference =
824 seat_get_focus_inactive_tiling(seat, workspace); 671 seat_get_focus_inactive_tiling(seat, workspace);
825 if (reference->type == C_VIEW) { 672 if (reference && reference->view) {
826 reference = reference->parent; 673 reference = reference->parent;
827 } 674 }
828 container_add_child(reference, container); 675 if (reference) {
829 container->width = container->parent->width; 676 container_add_child(reference, container);
830 container->height = container->parent->height; 677 container->width = reference->width;
831 if (container->type == C_VIEW) { 678 container->height = reference->height;
832 view_set_tiled(container->sway_view, true); 679 } else {
680 workspace_add_tiling(workspace, container);
681 container->width = workspace->width;
682 container->height = workspace->height;
683 }
684 if (container->view) {
685 view_set_tiled(container->view, true);
833 } 686 }
834 container->is_sticky = false; 687 container->is_sticky = false;
835 } 688 }
@@ -840,14 +693,13 @@ void container_set_floating(struct sway_container *container, bool enable) {
840} 693}
841 694
842void container_set_geometry_from_floating_view(struct sway_container *con) { 695void container_set_geometry_from_floating_view(struct sway_container *con) {
843 if (!sway_assert(con->type == C_VIEW, "Expected a view")) { 696 if (!sway_assert(con->view, "Expected a view")) {
844 return; 697 return;
845 } 698 }
846 if (!sway_assert(container_is_floating(con), 699 if (!sway_assert(container_is_floating(con), "Expected a floating view")) {
847 "Expected a floating view")) {
848 return; 700 return;
849 } 701 }
850 struct sway_view *view = con->sway_view; 702 struct sway_view *view = con->view;
851 size_t border_width = 0; 703 size_t border_width = 0;
852 size_t top = 0; 704 size_t top = 0;
853 705
@@ -861,12 +713,12 @@ void container_set_geometry_from_floating_view(struct sway_container *con) {
861 con->y = view->y - top; 713 con->y = view->y - top;
862 con->width = view->width + border_width * 2; 714 con->width = view->width + border_width * 2;
863 con->height = top + view->height + border_width; 715 con->height = top + view->height + border_width;
864 container_set_dirty(con); 716 node_set_dirty(&con->node);
865} 717}
866 718
867bool container_is_floating(struct sway_container *container) { 719bool container_is_floating(struct sway_container *container) {
868 return container->parent && container->parent->type == C_WORKSPACE && 720 return !container->parent && container->workspace &&
869 list_find(container->parent->sway_workspace->floating, container) != -1; 721 list_find(container->workspace->floating, container) != -1;
870} 722}
871 723
872void container_get_box(struct sway_container *container, struct wlr_box *box) { 724void container_get_box(struct sway_container *container, struct wlr_box *box) {
@@ -883,16 +735,16 @@ void container_floating_translate(struct sway_container *con,
883 double x_amount, double y_amount) { 735 double x_amount, double y_amount) {
884 con->x += x_amount; 736 con->x += x_amount;
885 con->y += y_amount; 737 con->y += y_amount;
886 if (con->type == C_VIEW) { 738 if (con->view) {
887 con->sway_view->x += x_amount; 739 con->view->x += x_amount;
888 con->sway_view->y += y_amount; 740 con->view->y += y_amount;
889 } else { 741 } else {
890 for (int i = 0; i < con->children->length; ++i) { 742 for (int i = 0; i < con->children->length; ++i) {
891 struct sway_container *child = con->children->items[i]; 743 struct sway_container *child = con->children->items[i];
892 container_floating_translate(child, x_amount, y_amount); 744 container_floating_translate(child, x_amount, y_amount);
893 } 745 }
894 } 746 }
895 container_set_dirty(con); 747 node_set_dirty(&con->node);
896} 748}
897 749
898/** 750/**
@@ -902,17 +754,16 @@ void container_floating_translate(struct sway_container *con,
902 * one, otherwise we'll choose whichever output is closest to the container's 754 * one, otherwise we'll choose whichever output is closest to the container's
903 * center. 755 * center.
904 */ 756 */
905struct sway_container *container_floating_find_output( 757struct sway_output *container_floating_find_output(struct sway_container *con) {
906 struct sway_container *con) {
907 double center_x = con->x + con->width / 2; 758 double center_x = con->x + con->width / 2;
908 double center_y = con->y + con->height / 2; 759 double center_y = con->y + con->height / 2;
909 struct sway_container *closest_output = NULL; 760 struct sway_output *closest_output = NULL;
910 double closest_distance = DBL_MAX; 761 double closest_distance = DBL_MAX;
911 for (int i = 0; i < root_container.children->length; ++i) { 762 for (int i = 0; i < root->outputs->length; ++i) {
912 struct sway_container *output = root_container.children->items[i]; 763 struct sway_output *output = root->outputs->items[i];
913 struct wlr_box output_box; 764 struct wlr_box output_box;
914 double closest_x, closest_y; 765 double closest_x, closest_y;
915 container_get_box(output, &output_box); 766 output_get_box(output, &output_box);
916 wlr_box_closest_point(&output_box, center_x, center_y, 767 wlr_box_closest_point(&output_box, center_x, center_y,
917 &closest_x, &closest_y); 768 &closest_x, &closest_y);
918 if (center_x == closest_x && center_y == closest_y) { 769 if (center_x == closest_x && center_y == closest_y) {
@@ -937,18 +788,18 @@ void container_floating_move_to(struct sway_container *con,
937 return; 788 return;
938 } 789 }
939 container_floating_translate(con, lx - con->x, ly - con->y); 790 container_floating_translate(con, lx - con->x, ly - con->y);
940 struct sway_container *old_workspace = container_parent(con, C_WORKSPACE); 791 struct sway_workspace *old_workspace = con->workspace;
941 struct sway_container *new_output = container_floating_find_output(con); 792 struct sway_output *new_output = container_floating_find_output(con);
942 if (!sway_assert(new_output, "Unable to find any output")) { 793 if (!sway_assert(new_output, "Unable to find any output")) {
943 return; 794 return;
944 } 795 }
945 struct sway_container *new_workspace = 796 struct sway_workspace *new_workspace =
946 output_get_active_workspace(new_output->sway_output); 797 output_get_active_workspace(new_output);
947 if (old_workspace != new_workspace) { 798 if (old_workspace != new_workspace) {
948 container_remove_child(con); 799 container_detach(con);
949 workspace_add_floating(new_workspace, con); 800 workspace_add_floating(new_workspace, con);
950 arrange_windows(old_workspace); 801 arrange_workspace(old_workspace);
951 arrange_windows(new_workspace); 802 arrange_workspace(new_workspace);
952 workspace_detect_urgent(old_workspace); 803 workspace_detect_urgent(old_workspace);
953 workspace_detect_urgent(new_workspace); 804 workspace_detect_urgent(new_workspace);
954 } 805 }
@@ -959,22 +810,14 @@ void container_floating_move_to_center(struct sway_container *con) {
959 "Expected a floating container")) { 810 "Expected a floating container")) {
960 return; 811 return;
961 } 812 }
962 struct sway_container *ws = container_parent(con, C_WORKSPACE); 813 struct sway_workspace *ws = con->workspace;
963 double new_lx = ws->x + (ws->width - con->width) / 2; 814 double new_lx = ws->x + (ws->width - con->width) / 2;
964 double new_ly = ws->y + (ws->height - con->height) / 2; 815 double new_ly = ws->y + (ws->height - con->height) / 2;
965 container_floating_translate(con, new_lx - con->x, new_ly - con->y); 816 container_floating_translate(con, new_lx - con->x, new_ly - con->y);
966} 817}
967 818
968void container_set_dirty(struct sway_container *container) {
969 if (container->dirty) {
970 return;
971 }
972 container->dirty = true;
973 list_add(server.dirty_containers, container);
974}
975
976static bool find_urgent_iterator(struct sway_container *con, void *data) { 819static bool find_urgent_iterator(struct sway_container *con, void *data) {
977 return con->type == C_VIEW && view_is_urgent(con->sway_view); 820 return con->view && view_is_urgent(con->view);
978} 821}
979 822
980bool container_has_urgent_child(struct sway_container *container) { 823bool container_has_urgent_child(struct sway_container *container) {
@@ -991,12 +834,12 @@ void container_end_mouse_operation(struct sway_container *container) {
991} 834}
992 835
993static void set_fullscreen_iterator(struct sway_container *con, void *data) { 836static void set_fullscreen_iterator(struct sway_container *con, void *data) {
994 if (con->type != C_VIEW) { 837 if (!con->view) {
995 return; 838 return;
996 } 839 }
997 if (con->sway_view->impl->set_fullscreen) { 840 if (con->view->impl->set_fullscreen) {
998 bool *enable = data; 841 bool *enable = data;
999 con->sway_view->impl->set_fullscreen(con->sway_view, *enable); 842 con->view->impl->set_fullscreen(con->view, *enable);
1000 } 843 }
1001} 844}
1002 845
@@ -1005,9 +848,9 @@ void container_set_fullscreen(struct sway_container *container, bool enable) {
1005 return; 848 return;
1006 } 849 }
1007 850
1008 struct sway_container *workspace = container_parent(container, C_WORKSPACE); 851 struct sway_workspace *workspace = container->workspace;
1009 if (enable && workspace->sway_workspace->fullscreen) { 852 if (enable && workspace->fullscreen) {
1010 container_set_fullscreen(workspace->sway_workspace->fullscreen, false); 853 container_set_fullscreen(workspace->fullscreen, false);
1011 } 854 }
1012 855
1013 set_fullscreen_iterator(container, &enable); 856 set_fullscreen_iterator(container, &enable);
@@ -1016,36 +859,32 @@ void container_set_fullscreen(struct sway_container *container, bool enable) {
1016 container->is_fullscreen = enable; 859 container->is_fullscreen = enable;
1017 860
1018 if (enable) { 861 if (enable) {
1019 workspace->sway_workspace->fullscreen = container; 862 workspace->fullscreen = container;
1020 container->saved_x = container->x; 863 container->saved_x = container->x;
1021 container->saved_y = container->y; 864 container->saved_y = container->y;
1022 container->saved_width = container->width; 865 container->saved_width = container->width;
1023 container->saved_height = container->height; 866 container->saved_height = container->height;
1024 867
1025 struct sway_seat *seat; 868 struct sway_seat *seat;
1026 struct sway_container *focus, *focus_ws; 869 struct sway_workspace *focus_ws;
1027 wl_list_for_each(seat, &input_manager->seats, link) { 870 wl_list_for_each(seat, &input_manager->seats, link) {
1028 focus = seat_get_focus(seat); 871 focus_ws = seat_get_focused_workspace(seat);
1029 if (focus) { 872 if (focus_ws) {
1030 focus_ws = focus;
1031 if (focus_ws->type != C_WORKSPACE) {
1032 focus_ws = container_parent(focus_ws, C_WORKSPACE);
1033 }
1034 if (focus_ws == workspace) { 873 if (focus_ws == workspace) {
1035 seat_set_focus(seat, container); 874 seat_set_focus(seat, &container->node);
1036 } 875 }
1037 } 876 }
1038 } 877 }
1039 } else { 878 } else {
1040 workspace->sway_workspace->fullscreen = NULL; 879 workspace->fullscreen = NULL;
1041 if (container_is_floating(container)) { 880 if (container_is_floating(container)) {
1042 container->x = container->saved_x; 881 container->x = container->saved_x;
1043 container->y = container->saved_y; 882 container->y = container->saved_y;
1044 container->width = container->saved_width; 883 container->width = container->saved_width;
1045 container->height = container->saved_height; 884 container->height = container->saved_height;
1046 struct sway_container *output = 885 struct sway_output *output =
1047 container_floating_find_output(container); 886 container_floating_find_output(container);
1048 if (!container_has_ancestor(container, output)) { 887 if (workspace->output != output) {
1049 container_floating_move_to_center(container); 888 container_floating_move_to_center(container);
1050 } 889 }
1051 } else { 890 } else {
@@ -1060,7 +899,7 @@ void container_set_fullscreen(struct sway_container *container, bool enable) {
1060} 899}
1061 900
1062bool container_is_floating_or_child(struct sway_container *container) { 901bool container_is_floating_or_child(struct sway_container *container) {
1063 while (container->parent && container->parent->type != C_WORKSPACE) { 902 while (container->parent) {
1064 container = container->parent; 903 container = container->parent;
1065 } 904 }
1066 return container_is_floating(container); 905 return container_is_floating(container);
@@ -1072,7 +911,7 @@ bool container_is_fullscreen_or_child(struct sway_container *container) {
1072 return true; 911 return true;
1073 } 912 }
1074 container = container->parent; 913 container = container->parent;
1075 } while (container && container->type != C_WORKSPACE); 914 } while (container);
1076 915
1077 return false; 916 return false;
1078} 917}
@@ -1090,42 +929,37 @@ static void surface_send_leave_iterator(struct wlr_surface *surface,
1090} 929}
1091 930
1092void container_discover_outputs(struct sway_container *con) { 931void container_discover_outputs(struct sway_container *con) {
1093 if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW,
1094 "Expected a container or view")) {
1095 return;
1096 }
1097 struct wlr_box con_box = { 932 struct wlr_box con_box = {
1098 .x = con->current.swayc_x, 933 .x = con->current.con_x,
1099 .y = con->current.swayc_y, 934 .y = con->current.con_y,
1100 .width = con->current.swayc_width, 935 .width = con->current.con_width,
1101 .height = con->current.swayc_height, 936 .height = con->current.con_height,
1102 }; 937 };
1103 struct sway_output *old_output = container_get_effective_output(con); 938 struct sway_output *old_output = container_get_effective_output(con);
1104 939
1105 for (int i = 0; i < root_container.children->length; ++i) { 940 for (int i = 0; i < root->outputs->length; ++i) {
1106 struct sway_container *output = root_container.children->items[i]; 941 struct sway_output *output = root->outputs->items[i];
1107 struct sway_output *sway_output = output->sway_output;
1108 struct wlr_box output_box; 942 struct wlr_box output_box;
1109 container_get_box(output, &output_box); 943 output_get_box(output, &output_box);
1110 struct wlr_box intersection; 944 struct wlr_box intersection;
1111 bool intersects = 945 bool intersects =
1112 wlr_box_intersection(&con_box, &output_box, &intersection); 946 wlr_box_intersection(&con_box, &output_box, &intersection);
1113 int index = list_find(con->outputs, sway_output); 947 int index = list_find(con->outputs, output);
1114 948
1115 if (intersects && index == -1) { 949 if (intersects && index == -1) {
1116 // Send enter 950 // Send enter
1117 wlr_log(WLR_DEBUG, "Con %p entered output %p", con, sway_output); 951 wlr_log(WLR_DEBUG, "Container %p entered output %p", con, output);
1118 if (con->type == C_VIEW) { 952 if (con->view) {
1119 view_for_each_surface(con->sway_view, 953 view_for_each_surface(con->view,
1120 surface_send_enter_iterator, sway_output->wlr_output); 954 surface_send_enter_iterator, output->wlr_output);
1121 } 955 }
1122 list_add(con->outputs, sway_output); 956 list_add(con->outputs, output);
1123 } else if (!intersects && index != -1) { 957 } else if (!intersects && index != -1) {
1124 // Send leave 958 // Send leave
1125 wlr_log(WLR_DEBUG, "Con %p left output %p", con, sway_output); 959 wlr_log(WLR_DEBUG, "Container %p left output %p", con, output);
1126 if (con->type == C_VIEW) { 960 if (con->view) {
1127 view_for_each_surface(con->sway_view, 961 view_for_each_surface(con->view,
1128 surface_send_leave_iterator, sway_output->wlr_output); 962 surface_send_leave_iterator, output->wlr_output);
1129 } 963 }
1130 list_del(con->outputs, index); 964 list_del(con->outputs, index);
1131 } 965 }
@@ -1135,17 +969,13 @@ void container_discover_outputs(struct sway_container *con) {
1135 double new_scale = new_output ? new_output->wlr_output->scale : -1; 969 double new_scale = new_output ? new_output->wlr_output->scale : -1;
1136 if (old_scale != new_scale) { 970 if (old_scale != new_scale) {
1137 container_update_title_textures(con); 971 container_update_title_textures(con);
1138 if (con->type == C_VIEW) { 972 if (con->view) {
1139 view_update_marks_textures(con->sway_view); 973 view_update_marks_textures(con->view);
1140 } 974 }
1141 } 975 }
1142} 976}
1143 977
1144void container_remove_gaps(struct sway_container *c) { 978void container_remove_gaps(struct sway_container *c) {
1145 if (!sway_assert(c->type == C_CONTAINER || c->type == C_VIEW,
1146 "Expected a container or view")) {
1147 return;
1148 }
1149 if (c->current_gaps == 0) { 979 if (c->current_gaps == 0) {
1150 return; 980 return;
1151 } 981 }
@@ -1158,25 +988,20 @@ void container_remove_gaps(struct sway_container *c) {
1158} 988}
1159 989
1160void container_add_gaps(struct sway_container *c) { 990void container_add_gaps(struct sway_container *c) {
1161 if (!sway_assert(c->type == C_CONTAINER || c->type == C_VIEW,
1162 "Expected a container or view")) {
1163 return;
1164 }
1165 if (c->current_gaps > 0) { 991 if (c->current_gaps > 0) {
1166 return; 992 return;
1167 } 993 }
1168 // Linear containers don't have gaps because it'd create double gaps 994 // Linear containers don't have gaps because it'd create double gaps
1169 if (c->type == C_CONTAINER && 995 if (!c->view && c->layout != L_TABBED && c->layout != L_STACKED) {
1170 c->layout != L_TABBED && c->layout != L_STACKED) {
1171 return; 996 return;
1172 } 997 }
1173 // Children of tabbed/stacked containers re-use the gaps of the container 998 // Children of tabbed/stacked containers re-use the gaps of the container
1174 enum sway_container_layout layout = c->parent->layout; 999 enum sway_container_layout layout = container_parent_layout(c);
1175 if (layout == L_TABBED || layout == L_STACKED) { 1000 if (layout == L_TABBED || layout == L_STACKED) {
1176 return; 1001 return;
1177 } 1002 }
1178 1003
1179 struct sway_container *ws = container_parent(c, C_WORKSPACE); 1004 struct sway_workspace *ws = c->workspace;
1180 1005
1181 c->current_gaps = ws->has_gaps ? ws->gaps_inner : config->gaps_inner; 1006 c->current_gaps = ws->has_gaps ? ws->gaps_inner : config->gaps_inner;
1182 c->x += c->current_gaps; 1007 c->x += c->current_gaps;
@@ -1185,222 +1010,154 @@ void container_add_gaps(struct sway_container *c) {
1185 c->height -= 2 * c->current_gaps; 1010 c->height -= 2 * c->current_gaps;
1186} 1011}
1187 1012
1188int container_sibling_index(const struct sway_container *child) { 1013enum sway_container_layout container_parent_layout(struct sway_container *con) {
1189 return list_find(child->parent->children, child); 1014 if (con->parent) {
1015 return con->parent->layout;
1016 }
1017 return con->workspace->layout;
1190} 1018}
1191 1019
1192void container_handle_fullscreen_reparent(struct sway_container *con, 1020enum sway_container_layout container_current_parent_layout(
1193 struct sway_container *old_parent) { 1021 struct sway_container *con) {
1194 if (!con->is_fullscreen) { 1022 if (con->current.parent) {
1195 return; 1023 return con->current.parent->current.layout;
1196 } 1024 }
1197 struct sway_container *old_workspace = old_parent; 1025 return con->current.workspace->current.layout;
1198 if (old_workspace && old_workspace->type != C_WORKSPACE) { 1026}
1199 old_workspace = container_parent(old_workspace, C_WORKSPACE); 1027
1028list_t *container_get_siblings(const struct sway_container *container) {
1029 if (container->parent) {
1030 return container->parent->children;
1200 } 1031 }
1201 struct sway_container *new_workspace = container_parent(con, C_WORKSPACE); 1032 if (!container->workspace) {
1202 if (old_workspace == new_workspace) { 1033 return NULL;
1203 return;
1204 } 1034 }
1205 // Unmark the old workspace as fullscreen 1035 if (list_find(container->workspace->tiling, container) != -1) {
1206 if (old_workspace) { 1036 return container->workspace->tiling;
1207 old_workspace->sway_workspace->fullscreen = NULL;
1208 } 1037 }
1038 return container->workspace->floating;
1039}
1209 1040
1210 // Mark the new workspace as fullscreen 1041int container_sibling_index(const struct sway_container *child) {
1211 if (new_workspace->sway_workspace->fullscreen) { 1042 return list_find(container_get_siblings(child), child);
1212 container_set_fullscreen( 1043}
1213 new_workspace->sway_workspace->fullscreen, false);
1214 }
1215 new_workspace->sway_workspace->fullscreen = con;
1216 1044
1217 // Resize container to new output dimensions 1045list_t *container_get_current_siblings(struct sway_container *container) {
1218 struct sway_container *output = new_workspace->parent; 1046 if (container->current.parent) {
1219 con->x = output->x; 1047 return container->current.parent->current.children;
1220 con->y = output->y; 1048 }
1221 con->width = output->width; 1049 return container->current.workspace->current.tiling;
1222 con->height = output->height; 1050}
1223 1051
1224 if (con->type == C_VIEW) { 1052void container_handle_fullscreen_reparent(struct sway_container *con) {
1225 struct sway_view *view = con->sway_view; 1053 if (!con->is_fullscreen || con->workspace->fullscreen == con) {
1226 view->x = output->x; 1054 return;
1227 view->y = output->y;
1228 view->width = output->width;
1229 view->height = output->height;
1230 } else {
1231 arrange_windows(new_workspace);
1232 } 1055 }
1056 if (con->workspace->fullscreen) {
1057 container_set_fullscreen(con->workspace->fullscreen, false);
1058 }
1059 con->workspace->fullscreen = con;
1060
1061 arrange_workspace(con->workspace);
1062}
1063
1064static void set_workspace(struct sway_container *container, void *data) {
1065 container->workspace = container->parent->workspace;
1233} 1066}
1234 1067
1235void container_insert_child(struct sway_container *parent, 1068void container_insert_child(struct sway_container *parent,
1236 struct sway_container *child, int i) { 1069 struct sway_container *child, int i) {
1237 struct sway_container *old_parent = child->parent; 1070 if (child->workspace) {
1238 if (old_parent) { 1071 container_detach(child);
1239 container_remove_child(child);
1240 } 1072 }
1241 wlr_log(WLR_DEBUG, "Inserting id:%zd at index %d", child->id, i);
1242 list_insert(parent->children, i, child); 1073 list_insert(parent->children, i, child);
1243 child->parent = parent; 1074 child->parent = parent;
1244 container_handle_fullscreen_reparent(child, old_parent); 1075 child->workspace = parent->workspace;
1076 container_for_each_child(child, set_workspace, NULL);
1077 container_handle_fullscreen_reparent(child);
1078 container_update_representation(parent);
1245} 1079}
1246 1080
1247struct sway_container *container_add_sibling(struct sway_container *fixed, 1081void container_add_sibling(struct sway_container *fixed,
1248 struct sway_container *active) { 1082 struct sway_container *active, int offset) {
1249 // TODO handle floating 1083 if (active->workspace) {
1250 struct sway_container *old_parent = NULL; 1084 container_detach(active);
1251 if (active->parent) { 1085 }
1252 old_parent = active->parent; 1086 list_t *siblings = container_get_siblings(fixed);
1253 container_remove_child(active); 1087 int index = list_find(siblings, fixed);
1254 } 1088 list_insert(siblings, index + offset, active);
1255 struct sway_container *parent = fixed->parent; 1089 active->parent = fixed->parent;
1256 int i = container_sibling_index(fixed); 1090 active->workspace = fixed->workspace;
1257 list_insert(parent->children, i + 1, active); 1091 container_for_each_child(active, set_workspace, NULL);
1258 active->parent = parent; 1092 container_handle_fullscreen_reparent(active);
1259 container_handle_fullscreen_reparent(active, old_parent); 1093 container_update_representation(active);
1260 return active->parent;
1261} 1094}
1262 1095
1263void container_add_child(struct sway_container *parent, 1096void container_add_child(struct sway_container *parent,
1264 struct sway_container *child) { 1097 struct sway_container *child) {
1265 wlr_log(WLR_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)", 1098 if (child->workspace) {
1266 child, child->type, child->width, child->height, 1099 container_detach(child);
1267 parent, parent->type, parent->width, parent->height); 1100 }
1268 struct sway_container *old_parent = child->parent;
1269 list_add(parent->children, child); 1101 list_add(parent->children, child);
1270 child->parent = parent; 1102 child->parent = parent;
1271 container_handle_fullscreen_reparent(child, old_parent); 1103 child->workspace = parent->workspace;
1272 if (old_parent) { 1104 container_for_each_child(child, set_workspace, NULL);
1273 container_set_dirty(old_parent); 1105 container_handle_fullscreen_reparent(child);
1274 } 1106 container_update_representation(parent);
1275 container_set_dirty(child); 1107 node_set_dirty(&child->node);
1108 node_set_dirty(&parent->node);
1276} 1109}
1277 1110
1278struct sway_container *container_remove_child(struct sway_container *child) { 1111void container_detach(struct sway_container *child) {
1279 if (child->is_fullscreen) { 1112 if (child->is_fullscreen) {
1280 struct sway_container *workspace = container_parent(child, C_WORKSPACE); 1113 child->workspace->fullscreen = NULL;
1281 workspace->sway_workspace->fullscreen = NULL;
1282 } 1114 }
1283 1115
1284 struct sway_container *parent = child->parent; 1116 struct sway_container *old_parent = child->parent;
1285 list_t *list = container_is_floating(child) ? 1117 struct sway_workspace *old_workspace = child->workspace;
1286 parent->sway_workspace->floating : parent->children; 1118 list_t *siblings = container_get_siblings(child);
1287 int index = list_find(list, child); 1119 int index = list_find(siblings, child);
1288 if (index != -1) { 1120 if (index != -1) {
1289 list_del(list, index); 1121 list_del(siblings, index);
1290 } 1122 }
1291 child->parent = NULL; 1123 child->parent = NULL;
1292 container_notify_subtree_changed(parent); 1124 child->workspace = NULL;
1293 1125 container_for_each_child(child, set_workspace, NULL);
1294 container_set_dirty(parent);
1295 container_set_dirty(child);
1296
1297 return parent;
1298}
1299
1300enum sway_container_layout container_get_default_layout(
1301 struct sway_container *con) {
1302 if (con->type != C_OUTPUT) {
1303 con = container_parent(con, C_OUTPUT);
1304 }
1305 1126
1306 if (!sway_assert(con != NULL, 1127 if (old_parent) {
1307 "container_get_default_layout must be called on an attached" 1128 container_update_representation(old_parent);
1308 " container below the root container")) { 1129 node_set_dirty(&old_parent->node);
1309 return 0;
1310 }
1311
1312 if (config->default_layout != L_NONE) {
1313 return config->default_layout;
1314 } else if (config->default_orientation != L_NONE) {
1315 return config->default_orientation;
1316 } else if (con->width >= con->height) {
1317 return L_HORIZ;
1318 } else { 1130 } else {
1319 return L_VERT; 1131 workspace_update_representation(old_workspace);
1132 node_set_dirty(&old_workspace->node);
1320 } 1133 }
1134 node_set_dirty(&child->node);
1321} 1135}
1322 1136
1323struct sway_container *container_replace_child(struct sway_container *child, 1137void container_replace(struct sway_container *container,
1324 struct sway_container *new_child) { 1138 struct sway_container *replacement) {
1325 struct sway_container *parent = child->parent; 1139 container_add_sibling(container, replacement, 1);
1326 if (parent == NULL) { 1140 container_detach(container);
1327 return NULL;
1328 }
1329
1330 list_t *list = container_is_floating(child) ?
1331 parent->sway_workspace->floating : parent->children;
1332 int i = list_find(list, child);
1333
1334 if (new_child->parent) {
1335 container_remove_child(new_child);
1336 }
1337 list->items[i] = new_child;
1338 new_child->parent = parent;
1339 child->parent = NULL;
1340
1341 // Set geometry for new child
1342 new_child->x = child->x;
1343 new_child->y = child->y;
1344 new_child->width = child->width;
1345 new_child->height = child->height;
1346
1347 // reset geometry for child
1348 child->width = 0;
1349 child->height = 0;
1350
1351 return parent;
1352} 1141}
1353 1142
1354struct sway_container *container_split(struct sway_container *child, 1143struct sway_container *container_split(struct sway_container *child,
1355 enum sway_container_layout layout) { 1144 enum sway_container_layout layout) {
1356 // TODO floating: cannot split a floating container 1145 struct sway_seat *seat = input_manager_get_default_seat(input_manager);
1357 if (!sway_assert(child, "child cannot be null")) { 1146 bool set_focus = (seat_get_focus(seat) == &child->node);
1358 return NULL;
1359 }
1360 if (child->type == C_WORKSPACE && child->children->length == 0) {
1361 // Special case: this just behaves like splitt
1362 child->prev_split_layout = child->layout;
1363 child->layout = layout;
1364 return child;
1365 }
1366
1367 struct sway_container *cont = container_create(C_CONTAINER);
1368
1369 wlr_log(WLR_DEBUG, "creating container %p around %p", cont, child);
1370 1147
1371 cont->prev_split_layout = L_NONE; 1148 struct sway_container *cont = container_create(NULL);
1372 cont->width = child->width; 1149 cont->width = child->width;
1373 cont->height = child->height; 1150 cont->height = child->height;
1374 cont->x = child->x;
1375 cont->y = child->y;
1376 cont->current_gaps = child->current_gaps; 1151 cont->current_gaps = child->current_gaps;
1152 cont->layout = layout;
1377 1153
1378 struct sway_seat *seat = input_manager_get_default_seat(input_manager); 1154 container_replace(child, cont);
1379 bool set_focus = (seat_get_focus(seat) == child); 1155 container_add_child(cont, child);
1380
1381 if (child->type == C_WORKSPACE) {
1382 struct sway_container *workspace = child;
1383 while (workspace->children->length) {
1384 struct sway_container *ws_child = workspace->children->items[0];
1385 container_remove_child(ws_child);
1386 container_add_child(cont, ws_child);
1387 }
1388
1389 container_add_child(workspace, cont);
1390 enum sway_container_layout old_layout = workspace->layout;
1391 workspace->layout = layout;
1392 cont->layout = old_layout;
1393 } else {
1394 cont->layout = layout;
1395 container_replace_child(child, cont);
1396 container_add_child(cont, child);
1397 }
1398 1156
1399 if (set_focus) { 1157 if (set_focus) {
1400 seat_set_focus(seat, cont); 1158 seat_set_focus(seat, &cont->node);
1401 seat_set_focus(seat, child); 1159 seat_set_focus(seat, &child->node);
1402 } 1160 }
1403 1161
1404 container_notify_subtree_changed(cont);
1405 return cont; 1162 return cont;
1406} 1163}