diff options
Diffstat (limited to 'sway/tree')
-rw-r--r-- | sway/tree/arrange.c | 110 | ||||
-rw-r--r-- | sway/tree/container.c | 871 | ||||
-rw-r--r-- | sway/tree/node.c | 151 | ||||
-rw-r--r-- | sway/tree/output.c | 348 | ||||
-rw-r--r-- | sway/tree/root.c | 186 | ||||
-rw-r--r-- | sway/tree/view.c | 277 | ||||
-rw-r--r-- | sway/tree/workspace.c | 493 |
7 files changed, 1164 insertions, 1272 deletions
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index 92f20fcc..f86d4a74 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c | |||
@@ -166,29 +166,23 @@ void arrange_container(struct sway_container *container) { | |||
166 | if (config->reloading) { | 166 | if (config->reloading) { |
167 | return; | 167 | return; |
168 | } | 168 | } |
169 | if (container->type == C_VIEW) { | 169 | if (container->view) { |
170 | view_autoconfigure(container->sway_view); | 170 | view_autoconfigure(container->view); |
171 | container_set_dirty(container); | 171 | node_set_dirty(&container->node); |
172 | return; | ||
173 | } | ||
174 | if (!sway_assert(container->type == C_CONTAINER, "Expected a container")) { | ||
175 | return; | 172 | return; |
176 | } | 173 | } |
177 | struct wlr_box box; | 174 | struct wlr_box box; |
178 | container_get_box(container, &box); | 175 | container_get_box(container, &box); |
179 | arrange_children(container->children, container->layout, &box); | 176 | arrange_children(container->children, container->layout, &box); |
180 | container_set_dirty(container); | 177 | node_set_dirty(&container->node); |
181 | } | 178 | } |
182 | 179 | ||
183 | void arrange_workspace(struct sway_container *workspace) { | 180 | void arrange_workspace(struct sway_workspace *workspace) { |
184 | if (config->reloading) { | 181 | if (config->reloading) { |
185 | return; | 182 | return; |
186 | } | 183 | } |
187 | if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { | 184 | struct sway_output *output = workspace->output; |
188 | return; | 185 | struct wlr_box *area = &output->usable_area; |
189 | } | ||
190 | struct sway_container *output = workspace->parent; | ||
191 | struct wlr_box *area = &output->sway_output->usable_area; | ||
192 | wlr_log(WLR_DEBUG, "Usable area for ws: %dx%d@%d,%d", | 186 | wlr_log(WLR_DEBUG, "Usable area for ws: %dx%d@%d,%d", |
193 | area->width, area->height, area->x, area->y); | 187 | area->width, area->height, area->x, area->y); |
194 | workspace_remove_gaps(workspace); | 188 | workspace_remove_gaps(workspace); |
@@ -197,21 +191,20 @@ void arrange_workspace(struct sway_container *workspace) { | |||
197 | double prev_y = workspace->y; | 191 | double prev_y = workspace->y; |
198 | workspace->width = area->width; | 192 | workspace->width = area->width; |
199 | workspace->height = area->height; | 193 | workspace->height = area->height; |
200 | workspace->x = output->x + area->x; | 194 | workspace->x = output->wlr_output->lx + area->x; |
201 | workspace->y = output->y + area->y; | 195 | workspace->y = output->wlr_output->ly + area->y; |
202 | 196 | ||
203 | // Adjust any floating containers | 197 | // Adjust any floating containers |
204 | double diff_x = workspace->x - prev_x; | 198 | double diff_x = workspace->x - prev_x; |
205 | double diff_y = workspace->y - prev_y; | 199 | double diff_y = workspace->y - prev_y; |
206 | if (diff_x != 0 || diff_y != 0) { | 200 | if (diff_x != 0 || diff_y != 0) { |
207 | for (int i = 0; i < workspace->sway_workspace->floating->length; ++i) { | 201 | for (int i = 0; i < workspace->floating->length; ++i) { |
208 | struct sway_container *floater = | 202 | struct sway_container *floater = workspace->floating->items[i]; |
209 | workspace->sway_workspace->floating->items[i]; | ||
210 | container_floating_translate(floater, diff_x, diff_y); | 203 | container_floating_translate(floater, diff_x, diff_y); |
211 | double center_x = floater->x + floater->width / 2; | 204 | double center_x = floater->x + floater->width / 2; |
212 | double center_y = floater->y + floater->height / 2; | 205 | double center_y = floater->y + floater->height / 2; |
213 | struct wlr_box workspace_box; | 206 | struct wlr_box workspace_box; |
214 | container_get_box(workspace, &workspace_box); | 207 | workspace_get_box(workspace, &workspace_box); |
215 | if (!wlr_box_contains_point(&workspace_box, center_x, center_y)) { | 208 | if (!wlr_box_contains_point(&workspace_box, center_x, center_y)) { |
216 | container_floating_move_to_center(floater); | 209 | container_floating_move_to_center(floater); |
217 | } | 210 | } |
@@ -219,43 +212,32 @@ void arrange_workspace(struct sway_container *workspace) { | |||
219 | } | 212 | } |
220 | 213 | ||
221 | workspace_add_gaps(workspace); | 214 | workspace_add_gaps(workspace); |
222 | container_set_dirty(workspace); | 215 | node_set_dirty(&workspace->node); |
223 | wlr_log(WLR_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name, | 216 | wlr_log(WLR_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name, |
224 | workspace->x, workspace->y); | 217 | workspace->x, workspace->y); |
225 | if (workspace->sway_workspace->fullscreen) { | 218 | if (workspace->fullscreen) { |
226 | struct sway_container *fs = workspace->sway_workspace->fullscreen; | 219 | struct sway_container *fs = workspace->fullscreen; |
227 | fs->x = workspace->parent->x; | 220 | fs->x = output->wlr_output->lx; |
228 | fs->y = workspace->parent->y; | 221 | fs->y = output->wlr_output->ly; |
229 | fs->width = workspace->parent->width; | 222 | fs->width = output->wlr_output->width; |
230 | fs->height = workspace->parent->height; | 223 | fs->height = output->wlr_output->height; |
231 | arrange_container(fs); | 224 | arrange_container(fs); |
232 | } else { | 225 | } else { |
233 | struct wlr_box box; | 226 | struct wlr_box box; |
234 | container_get_box(workspace, &box); | 227 | workspace_get_box(workspace, &box); |
235 | arrange_children(workspace->children, workspace->layout, &box); | 228 | arrange_children(workspace->tiling, workspace->layout, &box); |
236 | arrange_floating(workspace->sway_workspace->floating); | 229 | arrange_floating(workspace->floating); |
237 | } | 230 | } |
238 | } | 231 | } |
239 | 232 | ||
240 | void arrange_output(struct sway_container *output) { | 233 | void arrange_output(struct sway_output *output) { |
241 | if (config->reloading) { | 234 | if (config->reloading) { |
242 | return; | 235 | return; |
243 | } | 236 | } |
244 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | 237 | // Outputs have no pending x/y/width/height, |
245 | return; | 238 | // so all we do here is arrange the workspaces. |
246 | } | 239 | for (int i = 0; i < output->workspaces->length; ++i) { |
247 | const struct wlr_box *output_box = wlr_output_layout_get_box( | 240 | struct sway_workspace *workspace = output->workspaces->items[i]; |
248 | root_container.sway_root->output_layout, | ||
249 | output->sway_output->wlr_output); | ||
250 | output->x = output_box->x; | ||
251 | output->y = output_box->y; | ||
252 | output->width = output_box->width; | ||
253 | output->height = output_box->height; | ||
254 | container_set_dirty(output); | ||
255 | wlr_log(WLR_DEBUG, "Arranging output '%s' at %f,%f", | ||
256 | output->name, output->x, output->y); | ||
257 | for (int i = 0; i < output->children->length; ++i) { | ||
258 | struct sway_container *workspace = output->children->items[i]; | ||
259 | arrange_workspace(workspace); | 241 | arrange_workspace(workspace); |
260 | } | 242 | } |
261 | } | 243 | } |
@@ -264,37 +246,31 @@ void arrange_root(void) { | |||
264 | if (config->reloading) { | 246 | if (config->reloading) { |
265 | return; | 247 | return; |
266 | } | 248 | } |
267 | struct wlr_output_layout *output_layout = | ||
268 | root_container.sway_root->output_layout; | ||
269 | const struct wlr_box *layout_box = | 249 | const struct wlr_box *layout_box = |
270 | wlr_output_layout_get_box(output_layout, NULL); | 250 | wlr_output_layout_get_box(root->output_layout, NULL); |
271 | root_container.x = layout_box->x; | 251 | root->x = layout_box->x; |
272 | root_container.y = layout_box->y; | 252 | root->y = layout_box->y; |
273 | root_container.width = layout_box->width; | 253 | root->width = layout_box->width; |
274 | root_container.height = layout_box->height; | 254 | root->height = layout_box->height; |
275 | container_set_dirty(&root_container); | 255 | for (int i = 0; i < root->outputs->length; ++i) { |
276 | for (int i = 0; i < root_container.children->length; ++i) { | 256 | struct sway_output *output = root->outputs->items[i]; |
277 | struct sway_container *output = root_container.children->items[i]; | ||
278 | arrange_output(output); | 257 | arrange_output(output); |
279 | } | 258 | } |
280 | } | 259 | } |
281 | 260 | ||
282 | void arrange_windows(struct sway_container *container) { | 261 | void arrange_node(struct sway_node *node) { |
283 | switch (container->type) { | 262 | switch (node->type) { |
284 | case C_ROOT: | 263 | case N_ROOT: |
285 | arrange_root(); | 264 | arrange_root(); |
286 | break; | 265 | break; |
287 | case C_OUTPUT: | 266 | case N_OUTPUT: |
288 | arrange_output(container); | 267 | arrange_output(node->sway_output); |
289 | break; | ||
290 | case C_WORKSPACE: | ||
291 | arrange_workspace(container); | ||
292 | break; | 268 | break; |
293 | case C_CONTAINER: | 269 | case N_WORKSPACE: |
294 | case C_VIEW: | 270 | arrange_workspace(node->sway_workspace); |
295 | arrange_container(container); | ||
296 | break; | 271 | break; |
297 | case C_TYPES: | 272 | case N_CONTAINER: |
273 | arrange_container(node->sway_container); | ||
298 | break; | 274 | break; |
299 | } | 275 | } |
300 | } | 276 | } |
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 | ||
27 | const char *container_type_to_str(enum sway_container_type type) { | 27 | struct 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 | |||
44 | void 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 | |||
53 | void 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 | |||
76 | struct 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 | ||
104 | void container_destroy(struct sway_container *con) { | 50 | void 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 | ||
141 | void container_begin_destroy(struct sway_container *con) { | 83 | void 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 | ||
166 | struct sway_container *container_reap_empty(struct sway_container *con) { | 103 | void 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 | ||
183 | struct sway_container *container_flatten(struct sway_container *container) { | 119 | struct 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 | ||
194 | static 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 | |||
200 | struct 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 | |||
219 | struct 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 | |||
245 | struct sway_container *container_find_child(struct sway_container *container, | 133 | struct 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 | ||
267 | struct sway_container *container_parent(struct sway_container *container, | 151 | static 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 | |||
281 | static 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 | */ |
320 | static struct sway_container *container_at_tabbed(struct sway_container *parent, | 190 | static 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 | */ |
349 | static struct sway_container *container_at_stacked( | 222 | static 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 | */ |
374 | static struct sway_container *container_at_linear(struct sway_container *parent, | 250 | static 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 | ||
392 | static struct sway_container *floating_container_at(double lx, double ly, | 269 | static 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 | ||
422 | struct sway_container *tiling_container_at( | 298 | struct 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 | ||
475 | struct sway_container *container_at(struct sway_container *workspace, | 350 | struct 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, | |||
521 | void container_for_each_child(struct sway_container *container, | 393 | void 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 | ||
537 | bool container_has_ancestor(struct sway_container *descendant, | 405 | bool 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 | ||
548 | int 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 | |||
563 | void container_damage_whole(struct sway_container *container) { | 416 | void 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 | ||
583 | static void update_title_texture(struct sway_container *con, | 434 | static 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 | */ |
667 | static size_t get_tree_representation(struct sway_container *parent, char *buffer) { | 514 | size_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 | ||
714 | void container_notify_subtree_changed(struct sway_container *container) { | 562 | void 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 | ||
740 | void container_init_floating(struct sway_container *con) { | 588 | void 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 | ||
842 | void container_set_geometry_from_floating_view(struct sway_container *con) { | 695 | void 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 | ||
867 | bool container_is_floating(struct sway_container *container) { | 719 | bool 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 | ||
872 | void container_get_box(struct sway_container *container, struct wlr_box *box) { | 724 | void 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 | */ |
905 | struct sway_container *container_floating_find_output( | 757 | struct 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 | ||
968 | void 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 | |||
976 | static bool find_urgent_iterator(struct sway_container *con, void *data) { | 819 | static 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 | ||
980 | bool container_has_urgent_child(struct sway_container *container) { | 823 | bool 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 | ||
993 | static void set_fullscreen_iterator(struct sway_container *con, void *data) { | 836 | static 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 | ||
1062 | bool container_is_floating_or_child(struct sway_container *container) { | 901 | bool 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 | ||
1092 | void container_discover_outputs(struct sway_container *con) { | 931 | void 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 | ||
1144 | void container_remove_gaps(struct sway_container *c) { | 978 | void 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 | ||
1160 | void container_add_gaps(struct sway_container *c) { | 990 | void 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 | ||
1188 | int container_sibling_index(const struct sway_container *child) { | 1013 | enum 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 | ||
1192 | void container_handle_fullscreen_reparent(struct sway_container *con, | 1020 | enum 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 | |
1028 | list_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 | 1041 | int 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 | 1045 | list_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) { | 1052 | void 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 | |||
1064 | static void set_workspace(struct sway_container *container, void *data) { | ||
1065 | container->workspace = container->parent->workspace; | ||
1233 | } | 1066 | } |
1234 | 1067 | ||
1235 | void container_insert_child(struct sway_container *parent, | 1068 | void 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 | ||
1247 | struct sway_container *container_add_sibling(struct sway_container *fixed, | 1081 | void 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 | ||
1263 | void container_add_child(struct sway_container *parent, | 1096 | void 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 | ||
1278 | struct sway_container *container_remove_child(struct sway_container *child) { | 1111 | void 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 | |||
1300 | enum 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 | ||
1323 | struct sway_container *container_replace_child(struct sway_container *child, | 1137 | void 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 | ||
1354 | struct sway_container *container_split(struct sway_container *child, | 1143 | struct 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 | } |
diff --git a/sway/tree/node.c b/sway/tree/node.c new file mode 100644 index 00000000..74661c1a --- /dev/null +++ b/sway/tree/node.c | |||
@@ -0,0 +1,151 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include "sway/output.h" | ||
3 | #include "sway/server.h" | ||
4 | #include "sway/tree/container.h" | ||
5 | #include "sway/tree/node.h" | ||
6 | #include "sway/tree/root.h" | ||
7 | #include "sway/tree/workspace.h" | ||
8 | #include "log.h" | ||
9 | |||
10 | void node_init(struct sway_node *node, enum sway_node_type type, void *thing) { | ||
11 | static size_t next_id = 1; | ||
12 | node->id = next_id++; | ||
13 | node->type = type; | ||
14 | node->sway_root = thing; | ||
15 | wl_signal_init(&node->events.destroy); | ||
16 | } | ||
17 | |||
18 | const char *node_type_to_str(enum sway_node_type type) { | ||
19 | switch (type) { | ||
20 | case N_ROOT: | ||
21 | return "N_ROOT"; | ||
22 | case N_OUTPUT: | ||
23 | return "N_OUTPUT"; | ||
24 | case N_WORKSPACE: | ||
25 | return "N_WORKSPACE"; | ||
26 | case N_CONTAINER: | ||
27 | return "N_CONTAINER"; | ||
28 | } | ||
29 | return ""; | ||
30 | } | ||
31 | |||
32 | void node_set_dirty(struct sway_node *node) { | ||
33 | if (node->dirty) { | ||
34 | return; | ||
35 | } | ||
36 | node->dirty = true; | ||
37 | list_add(server.dirty_nodes, node); | ||
38 | } | ||
39 | |||
40 | bool node_is_view(struct sway_node *node) { | ||
41 | return node->type == N_CONTAINER && node->sway_container->view; | ||
42 | } | ||
43 | |||
44 | char *node_get_name(struct sway_node *node) { | ||
45 | switch (node->type) { | ||
46 | case N_ROOT: | ||
47 | return "root"; | ||
48 | case N_OUTPUT: | ||
49 | return node->sway_output->wlr_output->name; | ||
50 | case N_WORKSPACE: | ||
51 | return node->sway_workspace->name; | ||
52 | case N_CONTAINER: | ||
53 | return node->sway_container->title; | ||
54 | } | ||
55 | return NULL; | ||
56 | } | ||
57 | |||
58 | void node_get_box(struct sway_node *node, struct wlr_box *box) { | ||
59 | switch (node->type) { | ||
60 | case N_ROOT: | ||
61 | root_get_box(root, box); | ||
62 | break; | ||
63 | case N_OUTPUT: | ||
64 | output_get_box(node->sway_output, box); | ||
65 | break; | ||
66 | case N_WORKSPACE: | ||
67 | workspace_get_box(node->sway_workspace, box); | ||
68 | break; | ||
69 | case N_CONTAINER: | ||
70 | container_get_box(node->sway_container, box); | ||
71 | break; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | struct sway_output *node_get_output(struct sway_node *node) { | ||
76 | switch (node->type) { | ||
77 | case N_CONTAINER: | ||
78 | return node->sway_container->workspace->output; | ||
79 | case N_WORKSPACE: | ||
80 | return node->sway_workspace->output; | ||
81 | case N_OUTPUT: | ||
82 | return node->sway_output; | ||
83 | case N_ROOT: | ||
84 | return NULL; | ||
85 | } | ||
86 | return NULL; | ||
87 | } | ||
88 | |||
89 | enum sway_container_layout node_get_layout(struct sway_node *node) { | ||
90 | switch (node->type) { | ||
91 | case N_CONTAINER: | ||
92 | return node->sway_container->layout; | ||
93 | case N_WORKSPACE: | ||
94 | return node->sway_workspace->layout; | ||
95 | case N_OUTPUT: | ||
96 | case N_ROOT: | ||
97 | return L_NONE; | ||
98 | } | ||
99 | return L_NONE; | ||
100 | } | ||
101 | |||
102 | struct sway_node *node_get_parent(struct sway_node *node) { | ||
103 | switch (node->type) { | ||
104 | case N_CONTAINER: { | ||
105 | struct sway_container *con = node->sway_container; | ||
106 | if (con->parent) { | ||
107 | return &con->parent->node; | ||
108 | } | ||
109 | if (con->workspace) { | ||
110 | return &con->workspace->node; | ||
111 | } | ||
112 | } | ||
113 | return NULL; | ||
114 | case N_WORKSPACE: { | ||
115 | struct sway_workspace *ws = node->sway_workspace; | ||
116 | if (ws->output) { | ||
117 | return &ws->output->node; | ||
118 | } | ||
119 | } | ||
120 | return NULL; | ||
121 | case N_OUTPUT: | ||
122 | return &root->node; | ||
123 | case N_ROOT: | ||
124 | return NULL; | ||
125 | } | ||
126 | return NULL; | ||
127 | } | ||
128 | |||
129 | list_t *node_get_children(struct sway_node *node) { | ||
130 | switch (node->type) { | ||
131 | case N_CONTAINER: | ||
132 | return node->sway_container->children; | ||
133 | case N_WORKSPACE: | ||
134 | return node->sway_workspace->tiling; | ||
135 | case N_OUTPUT: | ||
136 | case N_ROOT: | ||
137 | return NULL; | ||
138 | } | ||
139 | return NULL; | ||
140 | } | ||
141 | |||
142 | bool node_has_ancestor(struct sway_node *node, struct sway_node *ancestor) { | ||
143 | struct sway_node *parent = node_get_parent(node); | ||
144 | while (parent) { | ||
145 | if (parent == ancestor) { | ||
146 | return true; | ||
147 | } | ||
148 | parent = node_get_parent(parent); | ||
149 | } | ||
150 | return false; | ||
151 | } | ||
diff --git a/sway/tree/output.c b/sway/tree/output.c index 6601220b..d72eb1a1 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c | |||
@@ -2,28 +2,31 @@ | |||
2 | #include <ctype.h> | 2 | #include <ctype.h> |
3 | #include <string.h> | 3 | #include <string.h> |
4 | #include <strings.h> | 4 | #include <strings.h> |
5 | #include <wlr/types/wlr_output_damage.h> | ||
5 | #include "sway/ipc-server.h" | 6 | #include "sway/ipc-server.h" |
7 | #include "sway/layers.h" | ||
6 | #include "sway/output.h" | 8 | #include "sway/output.h" |
7 | #include "sway/tree/arrange.h" | 9 | #include "sway/tree/arrange.h" |
8 | #include "sway/tree/output.h" | 10 | #include "sway/tree/output.h" |
9 | #include "sway/tree/workspace.h" | 11 | #include "sway/tree/workspace.h" |
10 | #include "log.h" | 12 | #include "log.h" |
13 | #include "util.h" | ||
11 | 14 | ||
12 | static void restore_workspaces(struct sway_container *output) { | 15 | static void restore_workspaces(struct sway_output *output) { |
13 | // Workspace output priority | 16 | // Workspace output priority |
14 | for (int i = 0; i < root_container.children->length; i++) { | 17 | for (int i = 0; i < root->outputs->length; i++) { |
15 | struct sway_container *other = root_container.children->items[i]; | 18 | struct sway_output *other = root->outputs->items[i]; |
16 | if (other == output) { | 19 | if (other == output) { |
17 | continue; | 20 | continue; |
18 | } | 21 | } |
19 | 22 | ||
20 | for (int j = 0; j < other->children->length; j++) { | 23 | for (int j = 0; j < other->workspaces->length; j++) { |
21 | struct sway_container *ws = other->children->items[j]; | 24 | struct sway_workspace *ws = other->workspaces->items[j]; |
22 | struct sway_container *highest = | 25 | struct sway_output *highest = |
23 | workspace_output_get_highest_available(ws, NULL); | 26 | workspace_output_get_highest_available(ws, NULL); |
24 | if (highest == output) { | 27 | if (highest == output) { |
25 | container_remove_child(ws); | 28 | workspace_detach(ws); |
26 | container_add_child(output, ws); | 29 | output_add_workspace(output, ws); |
27 | ipc_event_workspace(NULL, ws, "move"); | 30 | ipc_event_workspace(NULL, ws, "move"); |
28 | j--; | 31 | j--; |
29 | } | 32 | } |
@@ -31,111 +34,111 @@ static void restore_workspaces(struct sway_container *output) { | |||
31 | } | 34 | } |
32 | 35 | ||
33 | // Saved workspaces | 36 | // Saved workspaces |
34 | list_t *saved = root_container.sway_root->saved_workspaces; | 37 | for (int i = 0; i < root->saved_workspaces->length; ++i) { |
35 | for (int i = 0; i < saved->length; ++i) { | 38 | struct sway_workspace *ws = root->saved_workspaces->items[i]; |
36 | struct sway_container *ws = saved->items[i]; | 39 | output_add_workspace(output, ws); |
37 | container_add_child(output, ws); | ||
38 | ipc_event_workspace(NULL, ws, "move"); | 40 | ipc_event_workspace(NULL, ws, "move"); |
39 | } | 41 | } |
40 | saved->length = 0; | 42 | root->saved_workspaces->length = 0; |
41 | 43 | ||
42 | output_sort_workspaces(output); | 44 | output_sort_workspaces(output); |
43 | } | 45 | } |
44 | 46 | ||
45 | struct sway_container *output_create( | 47 | struct sway_output *output_create(struct wlr_output *wlr_output) { |
46 | struct sway_output *sway_output) { | 48 | struct sway_output *output = calloc(1, sizeof(struct sway_output)); |
47 | const char *name = sway_output->wlr_output->name; | 49 | node_init(&output->node, N_OUTPUT, output); |
48 | char identifier[128]; | 50 | output->wlr_output = wlr_output; |
49 | output_get_identifier(identifier, sizeof(identifier), sway_output); | 51 | wlr_output->data = output; |
50 | 52 | ||
51 | struct output_config *oc = NULL, *all = NULL; | 53 | wl_signal_add(&wlr_output->events.destroy, &output->destroy); |
52 | for (int i = 0; i < config->output_configs->length; ++i) { | ||
53 | struct output_config *cur = config->output_configs->items[i]; | ||
54 | 54 | ||
55 | if (strcasecmp(name, cur->name) == 0 || | 55 | wl_list_insert(&root->all_outputs, &output->link); |
56 | strcasecmp(identifier, cur->name) == 0) { | ||
57 | wlr_log(WLR_DEBUG, "Matched output config for %s", name); | ||
58 | oc = cur; | ||
59 | } | ||
60 | if (strcasecmp("*", cur->name) == 0) { | ||
61 | wlr_log(WLR_DEBUG, "Matched wildcard output config for %s", name); | ||
62 | all = cur; | ||
63 | } | ||
64 | 56 | ||
65 | if (oc && all) { | 57 | if (!wl_list_empty(&wlr_output->modes)) { |
66 | break; | 58 | struct wlr_output_mode *mode = |
67 | } | 59 | wl_container_of(wlr_output->modes.prev, mode, link); |
68 | } | 60 | wlr_output_set_mode(wlr_output, mode); |
69 | if (!oc) { | ||
70 | oc = all; | ||
71 | } | 61 | } |
72 | 62 | ||
73 | if (oc && !oc->enabled) { | 63 | output->workspaces = create_list(); |
74 | return NULL; | 64 | output->current.workspaces = create_list(); |
75 | } | ||
76 | 65 | ||
77 | struct sway_container *output = container_create(C_OUTPUT); | 66 | return output; |
78 | output->sway_output = sway_output; | 67 | } |
79 | output->name = strdup(name); | ||
80 | if (output->name == NULL) { | ||
81 | output_begin_destroy(output); | ||
82 | return NULL; | ||
83 | } | ||
84 | 68 | ||
69 | void output_enable(struct sway_output *output, struct output_config *oc) { | ||
70 | if (!sway_assert(!output->enabled, "output is already enabled")) { | ||
71 | return; | ||
72 | } | ||
73 | struct wlr_output *wlr_output = output->wlr_output; | ||
74 | output->enabled = true; | ||
85 | apply_output_config(oc, output); | 75 | apply_output_config(oc, output); |
86 | container_add_child(&root_container, output); | 76 | list_add(root->outputs, output); |
87 | load_swaybars(); | ||
88 | |||
89 | struct wlr_box size; | ||
90 | wlr_output_effective_resolution(sway_output->wlr_output, &size.width, | ||
91 | &size.height); | ||
92 | output->width = size.width; | ||
93 | output->height = size.height; | ||
94 | 77 | ||
95 | restore_workspaces(output); | 78 | restore_workspaces(output); |
96 | 79 | ||
97 | if (!output->children->length) { | 80 | if (!output->workspaces->length) { |
98 | // Create workspace | 81 | // Create workspace |
99 | char *ws_name = workspace_next_name(output->name); | 82 | char *ws_name = workspace_next_name(wlr_output->name); |
100 | wlr_log(WLR_DEBUG, "Creating default workspace %s", ws_name); | 83 | wlr_log(WLR_DEBUG, "Creating default workspace %s", ws_name); |
101 | struct sway_container *ws = workspace_create(output, ws_name); | 84 | struct sway_workspace *ws = workspace_create(output, ws_name); |
102 | // Set each seat's focus if not already set | 85 | // Set each seat's focus if not already set |
103 | struct sway_seat *seat = NULL; | 86 | struct sway_seat *seat = NULL; |
104 | wl_list_for_each(seat, &input_manager->seats, link) { | 87 | wl_list_for_each(seat, &input_manager->seats, link) { |
105 | if (!seat->has_focus) { | 88 | if (!seat->has_focus) { |
106 | seat_set_focus(seat, ws); | 89 | seat_set_focus(seat, &ws->node); |
107 | } | 90 | } |
108 | } | 91 | } |
109 | free(ws_name); | 92 | free(ws_name); |
110 | } | 93 | } |
111 | 94 | ||
112 | container_create_notify(output); | 95 | size_t len = sizeof(output->layers) / sizeof(output->layers[0]); |
113 | return output; | 96 | for (size_t i = 0; i < len; ++i) { |
97 | wl_list_init(&output->layers[i]); | ||
98 | } | ||
99 | wl_signal_init(&output->events.destroy); | ||
100 | |||
101 | input_manager_configure_xcursor(input_manager); | ||
102 | |||
103 | wl_signal_add(&wlr_output->events.mode, &output->mode); | ||
104 | wl_signal_add(&wlr_output->events.transform, &output->transform); | ||
105 | wl_signal_add(&wlr_output->events.scale, &output->scale); | ||
106 | wl_signal_add(&output->damage->events.frame, &output->damage_frame); | ||
107 | wl_signal_add(&output->damage->events.destroy, &output->damage_destroy); | ||
108 | |||
109 | output_add_listeners(output); | ||
110 | |||
111 | wl_signal_emit(&root->events.new_node, &output->node); | ||
112 | |||
113 | load_swaybars(); | ||
114 | |||
115 | arrange_layers(output); | ||
116 | arrange_root(); | ||
114 | } | 117 | } |
115 | 118 | ||
116 | static void output_evacuate(struct sway_container *output) { | 119 | static void output_evacuate(struct sway_output *output) { |
117 | if (!output->children->length) { | 120 | if (!output->workspaces->length) { |
118 | return; | 121 | return; |
119 | } | 122 | } |
120 | struct sway_container *fallback_output = NULL; | 123 | struct sway_output *fallback_output = NULL; |
121 | if (root_container.children->length > 1) { | 124 | if (root->outputs->length > 1) { |
122 | fallback_output = root_container.children->items[0]; | 125 | fallback_output = root->outputs->items[0]; |
123 | if (fallback_output == output) { | 126 | if (fallback_output == output) { |
124 | fallback_output = root_container.children->items[1]; | 127 | fallback_output = root->outputs->items[1]; |
125 | } | 128 | } |
126 | } | 129 | } |
127 | 130 | ||
128 | while (output->children->length) { | 131 | while (output->workspaces->length) { |
129 | struct sway_container *workspace = output->children->items[0]; | 132 | struct sway_workspace *workspace = output->workspaces->items[0]; |
130 | 133 | ||
131 | container_remove_child(workspace); | 134 | workspace_detach(workspace); |
132 | 135 | ||
133 | if (workspace_is_empty(workspace)) { | 136 | if (workspace_is_empty(workspace)) { |
134 | workspace_begin_destroy(workspace); | 137 | workspace_begin_destroy(workspace); |
135 | continue; | 138 | continue; |
136 | } | 139 | } |
137 | 140 | ||
138 | struct sway_container *new_output = | 141 | struct sway_output *new_output = |
139 | workspace_output_get_highest_available(workspace, output); | 142 | workspace_output_get_highest_available(workspace, output); |
140 | if (!new_output) { | 143 | if (!new_output) { |
141 | new_output = fallback_output; | 144 | new_output = fallback_output; |
@@ -143,39 +146,31 @@ static void output_evacuate(struct sway_container *output) { | |||
143 | 146 | ||
144 | if (new_output) { | 147 | if (new_output) { |
145 | workspace_output_add_priority(workspace, new_output); | 148 | workspace_output_add_priority(workspace, new_output); |
146 | container_add_child(new_output, workspace); | 149 | output_add_workspace(new_output, workspace); |
147 | output_sort_workspaces(new_output); | 150 | output_sort_workspaces(new_output); |
148 | ipc_event_workspace(NULL, workspace, "move"); | 151 | ipc_event_workspace(NULL, workspace, "move"); |
149 | } else { | 152 | } else { |
150 | list_add(root_container.sway_root->saved_workspaces, workspace); | 153 | list_add(root->saved_workspaces, workspace); |
151 | } | 154 | } |
152 | } | 155 | } |
153 | } | 156 | } |
154 | 157 | ||
155 | void output_destroy(struct sway_container *output) { | 158 | void output_destroy(struct sway_output *output) { |
156 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | 159 | if (!sway_assert(output->node.destroying, |
160 | "Tried to free output which wasn't marked as destroying")) { | ||
157 | return; | 161 | return; |
158 | } | 162 | } |
159 | if (!sway_assert(output->destroying, | 163 | if (!sway_assert(output->wlr_output == NULL, |
160 | "Tried to free output which wasn't marked as destroying")) { | 164 | "Tried to free output which still had a wlr_output")) { |
161 | return; | 165 | return; |
162 | } | 166 | } |
163 | if (!sway_assert(output->ntxnrefs == 0, "Tried to free output " | 167 | if (!sway_assert(output->node.ntxnrefs == 0, "Tried to free output " |
164 | "which is still referenced by transactions")) { | 168 | "which is still referenced by transactions")) { |
165 | return; | 169 | return; |
166 | } | 170 | } |
167 | free(output->name); | 171 | list_free(output->workspaces); |
168 | free(output->formatted_title); | 172 | list_free(output->current.workspaces); |
169 | wlr_texture_destroy(output->title_focused); | ||
170 | wlr_texture_destroy(output->title_focused_inactive); | ||
171 | wlr_texture_destroy(output->title_unfocused); | ||
172 | wlr_texture_destroy(output->title_urgent); | ||
173 | list_free(output->children); | ||
174 | list_free(output->current.children); | ||
175 | list_free(output->outputs); | ||
176 | free(output); | 173 | free(output); |
177 | |||
178 | // NOTE: We don't actually destroy the sway_output here | ||
179 | } | 174 | } |
180 | 175 | ||
181 | static void untrack_output(struct sway_container *con, void *data) { | 176 | static void untrack_output(struct sway_container *con, void *data) { |
@@ -186,76 +181,131 @@ static void untrack_output(struct sway_container *con, void *data) { | |||
186 | } | 181 | } |
187 | } | 182 | } |
188 | 183 | ||
189 | void output_begin_destroy(struct sway_container *output) { | 184 | void output_disable(struct sway_output *output) { |
190 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | 185 | if (!sway_assert(output->enabled, "Expected an enabled output")) { |
191 | return; | 186 | return; |
192 | } | 187 | } |
193 | wlr_log(WLR_DEBUG, "OUTPUT: Destroying output '%s'", output->name); | 188 | wlr_log(WLR_DEBUG, "Disabling output '%s'", output->wlr_output->name); |
194 | wl_signal_emit(&output->events.destroy, output); | 189 | wl_signal_emit(&output->events.destroy, output); |
195 | 190 | ||
196 | output_evacuate(output); | 191 | output_evacuate(output); |
197 | 192 | ||
198 | output->destroying = true; | 193 | root_for_each_container(untrack_output, output); |
199 | container_set_dirty(output); | 194 | |
195 | int index = list_find(root->outputs, output); | ||
196 | list_del(root->outputs, index); | ||
200 | 197 | ||
201 | root_for_each_container(untrack_output, output->sway_output); | 198 | wl_list_remove(&output->mode.link); |
199 | wl_list_remove(&output->transform.link); | ||
200 | wl_list_remove(&output->scale.link); | ||
201 | wl_list_remove(&output->damage_destroy.link); | ||
202 | wl_list_remove(&output->damage_frame.link); | ||
202 | 203 | ||
203 | wl_list_remove(&output->sway_output->mode.link); | 204 | output->enabled = false; |
204 | wl_list_remove(&output->sway_output->transform.link); | ||
205 | wl_list_remove(&output->sway_output->scale.link); | ||
206 | wl_list_remove(&output->sway_output->damage_destroy.link); | ||
207 | wl_list_remove(&output->sway_output->damage_frame.link); | ||
208 | 205 | ||
209 | output->sway_output->swayc = NULL; | 206 | arrange_root(); |
210 | output->sway_output = NULL; | 207 | } |
211 | 208 | ||
212 | if (output->parent) { | 209 | void output_begin_destroy(struct sway_output *output) { |
213 | container_remove_child(output); | 210 | if (!sway_assert(!output->enabled, "Expected a disabled output")) { |
211 | return; | ||
214 | } | 212 | } |
213 | wlr_log(WLR_DEBUG, "Destroying output '%s'", output->wlr_output->name); | ||
214 | |||
215 | output->node.destroying = true; | ||
216 | node_set_dirty(&output->node); | ||
217 | |||
218 | wl_list_remove(&output->link); | ||
219 | wl_list_remove(&output->destroy.link); | ||
220 | output->wlr_output->data = NULL; | ||
221 | output->wlr_output = NULL; | ||
215 | } | 222 | } |
216 | 223 | ||
217 | struct sway_container *output_from_wlr_output(struct wlr_output *output) { | 224 | struct output_config *output_find_config(struct sway_output *output) { |
218 | if (output == NULL) { | 225 | const char *name = output->wlr_output->name; |
226 | char identifier[128]; | ||
227 | output_get_identifier(identifier, sizeof(identifier), output); | ||
228 | |||
229 | struct output_config *oc = NULL, *all = NULL; | ||
230 | for (int i = 0; i < config->output_configs->length; ++i) { | ||
231 | struct output_config *cur = config->output_configs->items[i]; | ||
232 | |||
233 | if (strcasecmp(name, cur->name) == 0 || | ||
234 | strcasecmp(identifier, cur->name) == 0) { | ||
235 | wlr_log(WLR_DEBUG, "Matched output config for %s", name); | ||
236 | oc = cur; | ||
237 | } | ||
238 | if (strcasecmp("*", cur->name) == 0) { | ||
239 | wlr_log(WLR_DEBUG, "Matched wildcard output config for %s", name); | ||
240 | all = cur; | ||
241 | } | ||
242 | |||
243 | if (oc && all) { | ||
244 | break; | ||
245 | } | ||
246 | } | ||
247 | if (!oc) { | ||
248 | oc = all; | ||
249 | } | ||
250 | |||
251 | if (oc && !oc->enabled) { | ||
219 | return NULL; | 252 | return NULL; |
220 | } | 253 | } |
221 | for (int i = 0; i < root_container.children->length; ++i) { | 254 | return oc; |
222 | struct sway_container *o = root_container.children->items[i]; | 255 | } |
223 | if (o->type == C_OUTPUT && o->sway_output->wlr_output == output) { | 256 | |
224 | return o; | 257 | struct sway_output *output_from_wlr_output(struct wlr_output *output) { |
225 | } | 258 | return output->data; |
259 | } | ||
260 | |||
261 | struct sway_output *output_get_in_direction(struct sway_output *reference, | ||
262 | enum movement_direction direction) { | ||
263 | enum wlr_direction wlr_dir = 0; | ||
264 | if (!sway_assert(sway_dir_to_wlr(direction, &wlr_dir), | ||
265 | "got invalid direction: %d", direction)) { | ||
266 | return NULL; | ||
226 | } | 267 | } |
227 | return NULL; | 268 | int lx = reference->wlr_output->lx + reference->wlr_output->width / 2; |
269 | int ly = reference->wlr_output->ly + reference->wlr_output->height / 2; | ||
270 | struct wlr_output *wlr_adjacent = wlr_output_layout_adjacent_output( | ||
271 | root->output_layout, wlr_dir, reference->wlr_output, lx, ly); | ||
272 | if (!wlr_adjacent) { | ||
273 | return NULL; | ||
274 | } | ||
275 | return output_from_wlr_output(wlr_adjacent); | ||
228 | } | 276 | } |
229 | 277 | ||
230 | void output_for_each_workspace(struct sway_container *output, | 278 | void output_add_workspace(struct sway_output *output, |
231 | void (*f)(struct sway_container *con, void *data), void *data) { | 279 | struct sway_workspace *workspace) { |
232 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | 280 | if (workspace->output) { |
233 | return; | 281 | workspace_detach(workspace); |
234 | } | 282 | } |
235 | for (int i = 0; i < output->children->length; ++i) { | 283 | list_add(output->workspaces, workspace); |
236 | struct sway_container *workspace = output->children->items[i]; | 284 | workspace->output = output; |
285 | node_set_dirty(&output->node); | ||
286 | node_set_dirty(&workspace->node); | ||
287 | } | ||
288 | |||
289 | void output_for_each_workspace(struct sway_output *output, | ||
290 | void (*f)(struct sway_workspace *ws, void *data), void *data) { | ||
291 | for (int i = 0; i < output->workspaces->length; ++i) { | ||
292 | struct sway_workspace *workspace = output->workspaces->items[i]; | ||
237 | f(workspace, data); | 293 | f(workspace, data); |
238 | } | 294 | } |
239 | } | 295 | } |
240 | 296 | ||
241 | void output_for_each_container(struct sway_container *output, | 297 | void output_for_each_container(struct sway_output *output, |
242 | void (*f)(struct sway_container *con, void *data), void *data) { | 298 | void (*f)(struct sway_container *con, void *data), void *data) { |
243 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | 299 | for (int i = 0; i < output->workspaces->length; ++i) { |
244 | return; | 300 | struct sway_workspace *workspace = output->workspaces->items[i]; |
245 | } | ||
246 | for (int i = 0; i < output->children->length; ++i) { | ||
247 | struct sway_container *workspace = output->children->items[i]; | ||
248 | workspace_for_each_container(workspace, f, data); | 301 | workspace_for_each_container(workspace, f, data); |
249 | } | 302 | } |
250 | } | 303 | } |
251 | 304 | ||
252 | struct sway_container *output_find_workspace(struct sway_container *output, | 305 | struct sway_workspace *output_find_workspace(struct sway_output *output, |
253 | bool (*test)(struct sway_container *con, void *data), void *data) { | 306 | bool (*test)(struct sway_workspace *ws, void *data), void *data) { |
254 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | 307 | for (int i = 0; i < output->workspaces->length; ++i) { |
255 | return NULL; | 308 | struct sway_workspace *workspace = output->workspaces->items[i]; |
256 | } | ||
257 | for (int i = 0; i < output->children->length; ++i) { | ||
258 | struct sway_container *workspace = output->children->items[i]; | ||
259 | if (test(workspace, data)) { | 309 | if (test(workspace, data)) { |
260 | return workspace; | 310 | return workspace; |
261 | } | 311 | } |
@@ -263,14 +313,11 @@ struct sway_container *output_find_workspace(struct sway_container *output, | |||
263 | return NULL; | 313 | return NULL; |
264 | } | 314 | } |
265 | 315 | ||
266 | struct sway_container *output_find_container(struct sway_container *output, | 316 | struct sway_container *output_find_container(struct sway_output *output, |
267 | bool (*test)(struct sway_container *con, void *data), void *data) { | 317 | bool (*test)(struct sway_container *con, void *data), void *data) { |
268 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | ||
269 | return NULL; | ||
270 | } | ||
271 | struct sway_container *result = NULL; | 318 | struct sway_container *result = NULL; |
272 | for (int i = 0; i < output->children->length; ++i) { | 319 | for (int i = 0; i < output->workspaces->length; ++i) { |
273 | struct sway_container *workspace = output->children->items[i]; | 320 | struct sway_workspace *workspace = output->workspaces->items[i]; |
274 | if ((result = workspace_find_container(workspace, test, data))) { | 321 | if ((result = workspace_find_container(workspace, test, data))) { |
275 | return result; | 322 | return result; |
276 | } | 323 | } |
@@ -279,8 +326,8 @@ struct sway_container *output_find_container(struct sway_container *output, | |||
279 | } | 326 | } |
280 | 327 | ||
281 | static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { | 328 | static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { |
282 | struct sway_container *a = *(void **)_a; | 329 | struct sway_workspace *a = *(void **)_a; |
283 | struct sway_container *b = *(void **)_b; | 330 | struct sway_workspace *b = *(void **)_b; |
284 | 331 | ||
285 | if (isdigit(a->name[0]) && isdigit(b->name[0])) { | 332 | if (isdigit(a->name[0]) && isdigit(b->name[0])) { |
286 | int a_num = strtol(a->name, NULL, 10); | 333 | int a_num = strtol(a->name, NULL, 10); |
@@ -294,6 +341,27 @@ static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { | |||
294 | return 0; | 341 | return 0; |
295 | } | 342 | } |
296 | 343 | ||
297 | void output_sort_workspaces(struct sway_container *output) { | 344 | void output_sort_workspaces(struct sway_output *output) { |
298 | list_stable_sort(output->children, sort_workspace_cmp_qsort); | 345 | list_stable_sort(output->workspaces, sort_workspace_cmp_qsort); |
346 | } | ||
347 | |||
348 | void output_get_box(struct sway_output *output, struct wlr_box *box) { | ||
349 | box->x = output->wlr_output->lx; | ||
350 | box->y = output->wlr_output->ly; | ||
351 | box->width = output->wlr_output->width; | ||
352 | box->height = output->wlr_output->height; | ||
353 | } | ||
354 | |||
355 | enum sway_container_layout output_get_default_layout( | ||
356 | struct sway_output *output) { | ||
357 | if (config->default_layout != L_NONE) { | ||
358 | return config->default_layout; | ||
359 | } | ||
360 | if (config->default_orientation != L_NONE) { | ||
361 | return config->default_orientation; | ||
362 | } | ||
363 | if (output->wlr_output->height > output->wlr_output->width) { | ||
364 | return L_VERT; | ||
365 | } | ||
366 | return L_HORIZ; | ||
299 | } | 367 | } |
diff --git a/sway/tree/root.c b/sway/tree/root.c index b42371de..ecc04ddb 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c | |||
@@ -14,54 +14,45 @@ | |||
14 | #include "log.h" | 14 | #include "log.h" |
15 | #include "util.h" | 15 | #include "util.h" |
16 | 16 | ||
17 | struct sway_container root_container; | 17 | struct sway_root *root; |
18 | 18 | ||
19 | static void output_layout_handle_change(struct wl_listener *listener, | 19 | static void output_layout_handle_change(struct wl_listener *listener, |
20 | void *data) { | 20 | void *data) { |
21 | arrange_windows(&root_container); | 21 | arrange_root(); |
22 | transaction_commit_dirty(); | 22 | transaction_commit_dirty(); |
23 | } | 23 | } |
24 | 24 | ||
25 | void root_create(void) { | 25 | struct sway_root *root_create(void) { |
26 | root_container.id = 0; // normally assigned in new_swayc() | 26 | struct sway_root *root = calloc(1, sizeof(struct sway_root)); |
27 | root_container.type = C_ROOT; | 27 | if (!root) { |
28 | root_container.layout = L_NONE; | 28 | wlr_log(WLR_ERROR, "Unable to allocate sway_root"); |
29 | root_container.name = strdup("root"); | 29 | return NULL; |
30 | root_container.children = create_list(); | 30 | } |
31 | root_container.current.children = create_list(); | 31 | node_init(&root->node, N_ROOT, root); |
32 | wl_signal_init(&root_container.events.destroy); | 32 | root->output_layout = wlr_output_layout_create(); |
33 | 33 | wl_list_init(&root->all_outputs); | |
34 | root_container.sway_root = calloc(1, sizeof(*root_container.sway_root)); | ||
35 | root_container.sway_root->output_layout = wlr_output_layout_create(); | ||
36 | wl_list_init(&root_container.sway_root->all_outputs); | ||
37 | #ifdef HAVE_XWAYLAND | 34 | #ifdef HAVE_XWAYLAND |
38 | wl_list_init(&root_container.sway_root->xwayland_unmanaged); | 35 | wl_list_init(&root->xwayland_unmanaged); |
39 | #endif | 36 | #endif |
40 | wl_list_init(&root_container.sway_root->drag_icons); | 37 | wl_list_init(&root->drag_icons); |
41 | wl_signal_init(&root_container.sway_root->events.new_container); | 38 | wl_signal_init(&root->events.new_node); |
42 | root_container.sway_root->scratchpad = create_list(); | 39 | root->outputs = create_list(); |
43 | root_container.sway_root->saved_workspaces = create_list(); | 40 | root->scratchpad = create_list(); |
44 | 41 | root->saved_workspaces = create_list(); | |
45 | root_container.sway_root->output_layout_change.notify = | 42 | |
46 | output_layout_handle_change; | 43 | root->output_layout_change.notify = output_layout_handle_change; |
47 | wl_signal_add(&root_container.sway_root->output_layout->events.change, | 44 | wl_signal_add(&root->output_layout->events.change, |
48 | &root_container.sway_root->output_layout_change); | 45 | &root->output_layout_change); |
46 | return root; | ||
49 | } | 47 | } |
50 | 48 | ||
51 | void root_destroy(void) { | 49 | void root_destroy(struct sway_root *root) { |
52 | // sway_root | 50 | wl_list_remove(&root->output_layout_change.link); |
53 | wl_list_remove(&root_container.sway_root->output_layout_change.link); | 51 | list_free(root->scratchpad); |
54 | list_free(root_container.sway_root->scratchpad); | 52 | list_free(root->saved_workspaces); |
55 | list_free(root_container.sway_root->saved_workspaces); | 53 | list_free(root->outputs); |
56 | wlr_output_layout_destroy(root_container.sway_root->output_layout); | 54 | wlr_output_layout_destroy(root->output_layout); |
57 | free(root_container.sway_root); | 55 | free(root); |
58 | |||
59 | // root_container | ||
60 | list_free(root_container.children); | ||
61 | list_free(root_container.current.children); | ||
62 | free(root_container.name); | ||
63 | |||
64 | memset(&root_container, 0, sizeof(root_container)); | ||
65 | } | 56 | } |
66 | 57 | ||
67 | void root_scratchpad_add_container(struct sway_container *con) { | 58 | void root_scratchpad_add_container(struct sway_container *con) { |
@@ -69,15 +60,21 @@ void root_scratchpad_add_container(struct sway_container *con) { | |||
69 | return; | 60 | return; |
70 | } | 61 | } |
71 | con->scratchpad = true; | 62 | con->scratchpad = true; |
72 | list_add(root_container.sway_root->scratchpad, con); | 63 | list_add(root->scratchpad, con); |
73 | 64 | ||
74 | struct sway_container *parent = con->parent; | 65 | struct sway_container *parent = con->parent; |
66 | struct sway_workspace *workspace = con->workspace; | ||
75 | container_set_floating(con, true); | 67 | container_set_floating(con, true); |
76 | container_remove_child(con); | 68 | container_detach(con); |
77 | arrange_windows(parent); | ||
78 | 69 | ||
79 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 70 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
80 | seat_set_focus(seat, seat_get_focus_inactive(seat, parent)); | 71 | if (parent) { |
72 | arrange_container(parent); | ||
73 | seat_set_focus(seat, seat_get_focus_inactive(seat, &parent->node)); | ||
74 | } else { | ||
75 | arrange_workspace(workspace); | ||
76 | seat_set_focus(seat, seat_get_focus_inactive(seat, &workspace->node)); | ||
77 | } | ||
81 | } | 78 | } |
82 | 79 | ||
83 | void root_scratchpad_remove_container(struct sway_container *con) { | 80 | void root_scratchpad_remove_container(struct sway_container *con) { |
@@ -85,28 +82,25 @@ void root_scratchpad_remove_container(struct sway_container *con) { | |||
85 | return; | 82 | return; |
86 | } | 83 | } |
87 | con->scratchpad = false; | 84 | con->scratchpad = false; |
88 | int index = list_find(root_container.sway_root->scratchpad, con); | 85 | int index = list_find(root->scratchpad, con); |
89 | if (index != -1) { | 86 | if (index != -1) { |
90 | list_del(root_container.sway_root->scratchpad, index); | 87 | list_del(root->scratchpad, index); |
91 | } | 88 | } |
92 | } | 89 | } |
93 | 90 | ||
94 | void root_scratchpad_show(struct sway_container *con) { | 91 | void root_scratchpad_show(struct sway_container *con) { |
95 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 92 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
96 | struct sway_container *ws = seat_get_focus(seat); | 93 | struct sway_workspace *ws = seat_get_focused_workspace(seat); |
97 | if (ws->type != C_WORKSPACE) { | ||
98 | ws = container_parent(ws, C_WORKSPACE); | ||
99 | } | ||
100 | 94 | ||
101 | // If the current con or any of its parents are in fullscreen mode, we | 95 | // If the current con or any of its parents are in fullscreen mode, we |
102 | // first need to disable it before showing the scratchpad con. | 96 | // first need to disable it before showing the scratchpad con. |
103 | if (ws->sway_workspace->fullscreen) { | 97 | if (ws->fullscreen) { |
104 | container_set_fullscreen(ws->sway_workspace->fullscreen, false); | 98 | container_set_fullscreen(ws->fullscreen, false); |
105 | } | 99 | } |
106 | 100 | ||
107 | // Show the container | 101 | // Show the container |
108 | if (con->parent) { | 102 | if (con->workspace) { |
109 | container_remove_child(con); | 103 | container_detach(con); |
110 | } | 104 | } |
111 | workspace_add_floating(ws, con); | 105 | workspace_add_floating(ws, con); |
112 | 106 | ||
@@ -115,7 +109,7 @@ void root_scratchpad_show(struct sway_container *con) { | |||
115 | double center_ly = con->y + con->height / 2; | 109 | double center_ly = con->y + con->height / 2; |
116 | 110 | ||
117 | struct wlr_box workspace_box; | 111 | struct wlr_box workspace_box; |
118 | container_get_box(ws, &workspace_box); | 112 | workspace_get_box(ws, &workspace_box); |
119 | if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) { | 113 | if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) { |
120 | // Maybe resize it | 114 | // Maybe resize it |
121 | if (con->width > ws->width || con->height > ws->height) { | 115 | if (con->width > ws->width || con->height > ws->height) { |
@@ -128,23 +122,21 @@ void root_scratchpad_show(struct sway_container *con) { | |||
128 | container_floating_move_to(con, new_lx, new_ly); | 122 | container_floating_move_to(con, new_lx, new_ly); |
129 | } | 123 | } |
130 | 124 | ||
131 | arrange_windows(ws); | 125 | arrange_workspace(ws); |
132 | seat_set_focus(seat, seat_get_focus_inactive(seat, con)); | 126 | seat_set_focus(seat, seat_get_focus_inactive(seat, &con->node)); |
133 | |||
134 | container_set_dirty(con->parent); | ||
135 | } | 127 | } |
136 | 128 | ||
137 | void root_scratchpad_hide(struct sway_container *con) { | 129 | void root_scratchpad_hide(struct sway_container *con) { |
138 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 130 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
139 | struct sway_container *focus = seat_get_focus(seat); | 131 | struct sway_node *focus = seat_get_focus(seat); |
140 | struct sway_container *ws = container_parent(con, C_WORKSPACE); | 132 | struct sway_workspace *ws = con->workspace; |
141 | 133 | ||
142 | container_remove_child(con); | 134 | container_detach(con); |
143 | arrange_windows(ws); | 135 | arrange_workspace(ws); |
144 | if (con == focus) { | 136 | if (&con->node == focus) { |
145 | seat_set_focus(seat, seat_get_focus_inactive(seat, ws)); | 137 | seat_set_focus(seat, seat_get_focus_inactive(seat, &ws->node)); |
146 | } | 138 | } |
147 | list_move_to_end(root_container.sway_root->scratchpad, con); | 139 | list_move_to_end(root->scratchpad, con); |
148 | } | 140 | } |
149 | 141 | ||
150 | struct pid_workspace { | 142 | struct pid_workspace { |
@@ -152,7 +144,7 @@ struct pid_workspace { | |||
152 | char *workspace; | 144 | char *workspace; |
153 | struct timespec time_added; | 145 | struct timespec time_added; |
154 | 146 | ||
155 | struct sway_container *output; | 147 | struct sway_output *output; |
156 | struct wl_listener output_destroy; | 148 | struct wl_listener output_destroy; |
157 | 149 | ||
158 | struct wl_list link; | 150 | struct wl_list link; |
@@ -160,13 +152,13 @@ struct pid_workspace { | |||
160 | 152 | ||
161 | static struct wl_list pid_workspaces; | 153 | static struct wl_list pid_workspaces; |
162 | 154 | ||
163 | struct sway_container *root_workspace_for_pid(pid_t pid) { | 155 | struct sway_workspace *root_workspace_for_pid(pid_t pid) { |
164 | if (!pid_workspaces.prev && !pid_workspaces.next) { | 156 | if (!pid_workspaces.prev && !pid_workspaces.next) { |
165 | wl_list_init(&pid_workspaces); | 157 | wl_list_init(&pid_workspaces); |
166 | return NULL; | 158 | return NULL; |
167 | } | 159 | } |
168 | 160 | ||
169 | struct sway_container *ws = NULL; | 161 | struct sway_workspace *ws = NULL; |
170 | struct pid_workspace *pw = NULL; | 162 | struct pid_workspace *pw = NULL; |
171 | 163 | ||
172 | wlr_log(WLR_DEBUG, "Looking up workspace for pid %d", pid); | 164 | wlr_log(WLR_DEBUG, "Looking up workspace for pid %d", pid); |
@@ -219,16 +211,12 @@ void root_record_workspace_pid(pid_t pid) { | |||
219 | } | 211 | } |
220 | 212 | ||
221 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 213 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
222 | struct sway_container *ws = | 214 | struct sway_workspace *ws = seat_get_focused_workspace(seat); |
223 | seat_get_focus_inactive(seat, &root_container); | ||
224 | if (ws && ws->type != C_WORKSPACE) { | ||
225 | ws = container_parent(ws, C_WORKSPACE); | ||
226 | } | ||
227 | if (!ws) { | 215 | if (!ws) { |
228 | wlr_log(WLR_DEBUG, "Bailing out, no workspace"); | 216 | wlr_log(WLR_DEBUG, "Bailing out, no workspace"); |
229 | return; | 217 | return; |
230 | } | 218 | } |
231 | struct sway_container *output = ws->parent; | 219 | struct sway_output *output = ws->output; |
232 | if (!output) { | 220 | if (!output) { |
233 | wlr_log(WLR_DEBUG, "Bailing out, no output"); | 221 | wlr_log(WLR_DEBUG, "Bailing out, no output"); |
234 | return; | 222 | return; |
@@ -255,30 +243,28 @@ void root_record_workspace_pid(pid_t pid) { | |||
255 | pw->pid = pid; | 243 | pw->pid = pid; |
256 | memcpy(&pw->time_added, &now, sizeof(struct timespec)); | 244 | memcpy(&pw->time_added, &now, sizeof(struct timespec)); |
257 | pw->output_destroy.notify = pw_handle_output_destroy; | 245 | pw->output_destroy.notify = pw_handle_output_destroy; |
258 | wl_signal_add(&output->sway_output->wlr_output->events.destroy, | 246 | wl_signal_add(&output->wlr_output->events.destroy, &pw->output_destroy); |
259 | &pw->output_destroy); | ||
260 | wl_list_insert(&pid_workspaces, &pw->link); | 247 | wl_list_insert(&pid_workspaces, &pw->link); |
261 | } | 248 | } |
262 | 249 | ||
263 | void root_for_each_workspace(void (*f)(struct sway_container *con, void *data), | 250 | void root_for_each_workspace(void (*f)(struct sway_workspace *ws, void *data), |
264 | void *data) { | 251 | void *data) { |
265 | for (int i = 0; i < root_container.children->length; ++i) { | 252 | for (int i = 0; i < root->outputs->length; ++i) { |
266 | struct sway_container *output = root_container.children->items[i]; | 253 | struct sway_output *output = root->outputs->items[i]; |
267 | output_for_each_workspace(output, f, data); | 254 | output_for_each_workspace(output, f, data); |
268 | } | 255 | } |
269 | } | 256 | } |
270 | 257 | ||
271 | void root_for_each_container(void (*f)(struct sway_container *con, void *data), | 258 | void root_for_each_container(void (*f)(struct sway_container *con, void *data), |
272 | void *data) { | 259 | void *data) { |
273 | for (int i = 0; i < root_container.children->length; ++i) { | 260 | for (int i = 0; i < root->outputs->length; ++i) { |
274 | struct sway_container *output = root_container.children->items[i]; | 261 | struct sway_output *output = root->outputs->items[i]; |
275 | output_for_each_container(output, f, data); | 262 | output_for_each_container(output, f, data); |
276 | } | 263 | } |
277 | 264 | ||
278 | // Scratchpad | 265 | // Scratchpad |
279 | for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) { | 266 | for (int i = 0; i < root->scratchpad->length; ++i) { |
280 | struct sway_container *container = | 267 | struct sway_container *container = root->scratchpad->items[i]; |
281 | root_container.sway_root->scratchpad->items[i]; | ||
282 | // If the container has a parent then it's visible on a workspace | 268 | // If the container has a parent then it's visible on a workspace |
283 | // and will have been iterated in the previous for loop. So we only | 269 | // and will have been iterated in the previous for loop. So we only |
284 | // iterate the hidden scratchpad containers here. | 270 | // iterate the hidden scratchpad containers here. |
@@ -289,10 +275,10 @@ void root_for_each_container(void (*f)(struct sway_container *con, void *data), | |||
289 | } | 275 | } |
290 | } | 276 | } |
291 | 277 | ||
292 | struct sway_container *root_find_output( | 278 | struct sway_output *root_find_output( |
293 | bool (*test)(struct sway_container *con, void *data), void *data) { | 279 | bool (*test)(struct sway_output *output, void *data), void *data) { |
294 | for (int i = 0; i < root_container.children->length; ++i) { | 280 | for (int i = 0; i < root->outputs->length; ++i) { |
295 | struct sway_container *output = root_container.children->items[i]; | 281 | struct sway_output *output = root->outputs->items[i]; |
296 | if (test(output, data)) { | 282 | if (test(output, data)) { |
297 | return output; | 283 | return output; |
298 | } | 284 | } |
@@ -300,11 +286,11 @@ struct sway_container *root_find_output( | |||
300 | return NULL; | 286 | return NULL; |
301 | } | 287 | } |
302 | 288 | ||
303 | struct sway_container *root_find_workspace( | 289 | struct sway_workspace *root_find_workspace( |
304 | bool (*test)(struct sway_container *con, void *data), void *data) { | 290 | bool (*test)(struct sway_workspace *ws, void *data), void *data) { |
305 | struct sway_container *result = NULL; | 291 | struct sway_workspace *result = NULL; |
306 | for (int i = 0; i < root_container.children->length; ++i) { | 292 | for (int i = 0; i < root->outputs->length; ++i) { |
307 | struct sway_container *output = root_container.children->items[i]; | 293 | struct sway_output *output = root->outputs->items[i]; |
308 | if ((result = output_find_workspace(output, test, data))) { | 294 | if ((result = output_find_workspace(output, test, data))) { |
309 | return result; | 295 | return result; |
310 | } | 296 | } |
@@ -315,17 +301,16 @@ struct sway_container *root_find_workspace( | |||
315 | struct sway_container *root_find_container( | 301 | struct sway_container *root_find_container( |
316 | bool (*test)(struct sway_container *con, void *data), void *data) { | 302 | bool (*test)(struct sway_container *con, void *data), void *data) { |
317 | struct sway_container *result = NULL; | 303 | struct sway_container *result = NULL; |
318 | for (int i = 0; i < root_container.children->length; ++i) { | 304 | for (int i = 0; i < root->outputs->length; ++i) { |
319 | struct sway_container *output = root_container.children->items[i]; | 305 | struct sway_output *output = root->outputs->items[i]; |
320 | if ((result = output_find_container(output, test, data))) { | 306 | if ((result = output_find_container(output, test, data))) { |
321 | return result; | 307 | return result; |
322 | } | 308 | } |
323 | } | 309 | } |
324 | 310 | ||
325 | // Scratchpad | 311 | // Scratchpad |
326 | for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) { | 312 | for (int i = 0; i < root->scratchpad->length; ++i) { |
327 | struct sway_container *container = | 313 | struct sway_container *container = root->scratchpad->items[i]; |
328 | root_container.sway_root->scratchpad->items[i]; | ||
329 | if (!container->parent) { | 314 | if (!container->parent) { |
330 | if (test(container, data)) { | 315 | if (test(container, data)) { |
331 | return container; | 316 | return container; |
@@ -337,3 +322,10 @@ struct sway_container *root_find_container( | |||
337 | } | 322 | } |
338 | return NULL; | 323 | return NULL; |
339 | } | 324 | } |
325 | |||
326 | void root_get_box(struct sway_root *root, struct wlr_box *box) { | ||
327 | box->x = root->x; | ||
328 | box->y = root->y; | ||
329 | box->width = root->width; | ||
330 | box->height = root->height; | ||
331 | } | ||
diff --git a/sway/tree/view.c b/sway/tree/view.c index 6bd0ef67..452c2bd1 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -33,6 +33,8 @@ void view_init(struct sway_view *view, enum sway_view_type type, | |||
33 | view->marks = create_list(); | 33 | view->marks = create_list(); |
34 | view->allow_request_urgent = true; | 34 | view->allow_request_urgent = true; |
35 | wl_signal_init(&view->events.unmap); | 35 | wl_signal_init(&view->events.unmap); |
36 | |||
37 | view->container = container_create(view); | ||
36 | } | 38 | } |
37 | 39 | ||
38 | void view_destroy(struct sway_view *view) { | 40 | void view_destroy(struct sway_view *view) { |
@@ -43,8 +45,8 @@ void view_destroy(struct sway_view *view) { | |||
43 | "Tried to free view which wasn't marked as destroying")) { | 45 | "Tried to free view which wasn't marked as destroying")) { |
44 | return; | 46 | return; |
45 | } | 47 | } |
46 | if (!sway_assert(view->swayc == NULL, | 48 | if (!sway_assert(view->container == NULL, |
47 | "Tried to free view which still has a swayc " | 49 | "Tried to free view which still has a container " |
48 | "(might have a pending transaction?)")) { | 50 | "(might have a pending transaction?)")) { |
49 | return; | 51 | return; |
50 | } | 52 | } |
@@ -57,6 +59,7 @@ void view_destroy(struct sway_view *view) { | |||
57 | wlr_texture_destroy(view->marks_focused_inactive); | 59 | wlr_texture_destroy(view->marks_focused_inactive); |
58 | wlr_texture_destroy(view->marks_unfocused); | 60 | wlr_texture_destroy(view->marks_unfocused); |
59 | wlr_texture_destroy(view->marks_urgent); | 61 | wlr_texture_destroy(view->marks_urgent); |
62 | free(view->title_format); | ||
60 | 63 | ||
61 | if (view->impl->destroy) { | 64 | if (view->impl->destroy) { |
62 | view->impl->destroy(view); | 65 | view->impl->destroy(view); |
@@ -65,23 +68,13 @@ void view_destroy(struct sway_view *view) { | |||
65 | } | 68 | } |
66 | } | 69 | } |
67 | 70 | ||
68 | /** | ||
69 | * The view may or may not be involved in a transaction. For example, a view may | ||
70 | * unmap then attempt to destroy itself before we've applied the new layout. If | ||
71 | * an unmapping view is still involved in a transaction then it'll still have a | ||
72 | * swayc. | ||
73 | * | ||
74 | * If there's no transaction we can simply free the view. Otherwise the | ||
75 | * destroying flag will make the view get freed when the transaction is | ||
76 | * finished. | ||
77 | */ | ||
78 | void view_begin_destroy(struct sway_view *view) { | 71 | void view_begin_destroy(struct sway_view *view) { |
79 | if (!sway_assert(view->surface == NULL, "Tried to destroy a mapped view")) { | 72 | if (!sway_assert(view->surface == NULL, "Tried to destroy a mapped view")) { |
80 | return; | 73 | return; |
81 | } | 74 | } |
82 | view->destroying = true; | 75 | view->destroying = true; |
83 | 76 | ||
84 | if (!view->swayc) { | 77 | if (!view->container) { |
85 | view_destroy(view); | 78 | view_destroy(view); |
86 | } | 79 | } |
87 | } | 80 | } |
@@ -171,30 +164,27 @@ uint32_t view_configure(struct sway_view *view, double lx, double ly, int width, | |||
171 | } | 164 | } |
172 | 165 | ||
173 | void view_autoconfigure(struct sway_view *view) { | 166 | void view_autoconfigure(struct sway_view *view) { |
174 | if (!sway_assert(view->swayc, | 167 | struct sway_output *output = view->container->workspace->output; |
175 | "Called view_autoconfigure() on a view without a swayc")) { | ||
176 | return; | ||
177 | } | ||
178 | |||
179 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); | ||
180 | 168 | ||
181 | if (view->swayc->is_fullscreen) { | 169 | if (view->container->is_fullscreen) { |
182 | view->x = output->x; | 170 | view->x = output->wlr_output->lx; |
183 | view->y = output->y; | 171 | view->y = output->wlr_output->ly; |
184 | view->width = output->width; | 172 | view->width = output->wlr_output->width; |
185 | view->height = output->height; | 173 | view->height = output->wlr_output->height; |
186 | return; | 174 | return; |
187 | } | 175 | } |
188 | 176 | ||
189 | struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); | 177 | struct sway_workspace *ws = view->container->workspace; |
190 | 178 | ||
191 | int other_views = 0; | 179 | bool other_views = false; |
192 | if (config->hide_edge_borders == E_SMART) { | 180 | if (config->hide_edge_borders == E_SMART) { |
193 | struct sway_container *con = view->swayc; | 181 | struct sway_container *con = view->container; |
194 | while (con != output) { | 182 | while (con) { |
195 | if (con->layout != L_TABBED && con->layout != L_STACKED) { | 183 | enum sway_container_layout layout = container_parent_layout(con); |
196 | other_views += con->children ? con->children->length - 1 : 0; | 184 | if (layout != L_TABBED && layout != L_STACKED) { |
197 | if (other_views > 0) { | 185 | list_t *siblings = container_get_siblings(con); |
186 | if (siblings && siblings->length > 1) { | ||
187 | other_views = true; | ||
198 | break; | 188 | break; |
199 | } | 189 | } |
200 | } | 190 | } |
@@ -202,7 +192,7 @@ void view_autoconfigure(struct sway_view *view) { | |||
202 | } | 192 | } |
203 | } | 193 | } |
204 | 194 | ||
205 | struct sway_container *con = view->swayc; | 195 | struct sway_container *con = view->container; |
206 | 196 | ||
207 | view->border_top = view->border_bottom = true; | 197 | view->border_top = view->border_bottom = true; |
208 | view->border_left = view->border_right = true; | 198 | view->border_left = view->border_right = true; |
@@ -228,7 +218,8 @@ void view_autoconfigure(struct sway_view *view) { | |||
228 | // In a tabbed or stacked container, the swayc's y is the bottom of the | 218 | // In a tabbed or stacked container, the swayc's y is the bottom of the |
229 | // title area. We have to disable any top border because the title bar is | 219 | // title area. We have to disable any top border because the title bar is |
230 | // rendered by the parent. | 220 | // rendered by the parent. |
231 | if (con->parent->layout == L_TABBED || con->parent->layout == L_STACKED) { | 221 | enum sway_container_layout layout = container_parent_layout(con); |
222 | if (layout == L_TABBED || layout == L_STACKED) { | ||
232 | view->border_top = false; | 223 | view->border_top = false; |
233 | } else { | 224 | } else { |
234 | y_offset = container_titlebar_height(); | 225 | y_offset = container_titlebar_height(); |
@@ -281,13 +272,16 @@ void view_set_activated(struct sway_view *view, bool activated) { | |||
281 | } | 272 | } |
282 | 273 | ||
283 | void view_request_activate(struct sway_view *view) { | 274 | void view_request_activate(struct sway_view *view) { |
284 | struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); | 275 | struct sway_workspace *ws = view->container->workspace; |
276 | if (!ws) { // hidden scratchpad container | ||
277 | return; | ||
278 | } | ||
285 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 279 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
286 | 280 | ||
287 | switch (config->focus_on_window_activation) { | 281 | switch (config->focus_on_window_activation) { |
288 | case FOWA_SMART: | 282 | case FOWA_SMART: |
289 | if (workspace_is_visible(ws)) { | 283 | if (workspace_is_visible(ws)) { |
290 | seat_set_focus(seat, view->swayc); | 284 | seat_set_focus(seat, &view->container->node); |
291 | } else { | 285 | } else { |
292 | view_set_urgent(view, true); | 286 | view_set_urgent(view, true); |
293 | } | 287 | } |
@@ -296,7 +290,7 @@ void view_request_activate(struct sway_view *view) { | |||
296 | view_set_urgent(view, true); | 290 | view_set_urgent(view, true); |
297 | break; | 291 | break; |
298 | case FOWA_FOCUS: | 292 | case FOWA_FOCUS: |
299 | seat_set_focus(seat, view->swayc); | 293 | seat_set_focus(seat, &view->container->node); |
300 | break; | 294 | break; |
301 | case FOWA_NONE: | 295 | case FOWA_NONE: |
302 | break; | 296 | break; |
@@ -331,23 +325,12 @@ void view_close_popups(struct sway_view *view) { | |||
331 | } | 325 | } |
332 | 326 | ||
333 | void view_damage_from(struct sway_view *view) { | 327 | void view_damage_from(struct sway_view *view) { |
334 | for (int i = 0; i < root_container.children->length; ++i) { | 328 | for (int i = 0; i < root->outputs->length; ++i) { |
335 | struct sway_container *cont = root_container.children->items[i]; | 329 | struct sway_output *output = root->outputs->items[i]; |
336 | if (cont->type == C_OUTPUT) { | 330 | output_damage_from_view(output, view); |
337 | output_damage_from_view(cont->sway_output, view); | ||
338 | } | ||
339 | } | 331 | } |
340 | } | 332 | } |
341 | 333 | ||
342 | static void view_get_layout_box(struct sway_view *view, struct wlr_box *box) { | ||
343 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); | ||
344 | |||
345 | box->x = output->x + view->swayc->x; | ||
346 | box->y = output->y + view->swayc->y; | ||
347 | box->width = view->width; | ||
348 | box->height = view->height; | ||
349 | } | ||
350 | |||
351 | void view_for_each_surface(struct sway_view *view, | 334 | void view_for_each_surface(struct sway_view *view, |
352 | wlr_surface_iterator_func_t iterator, void *user_data) { | 335 | wlr_surface_iterator_func_t iterator, void *user_data) { |
353 | if (!view->surface) { | 336 | if (!view->surface) { |
@@ -396,11 +379,8 @@ static bool view_has_executed_criteria(struct sway_view *view, | |||
396 | } | 379 | } |
397 | 380 | ||
398 | void view_execute_criteria(struct sway_view *view) { | 381 | void view_execute_criteria(struct sway_view *view) { |
399 | if (!view->swayc) { | ||
400 | return; | ||
401 | } | ||
402 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 382 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
403 | struct sway_container *prior_focus = seat_get_focus(seat); | 383 | struct sway_node *prior_focus = seat_get_focus(seat); |
404 | list_t *criterias = criteria_for_view(view, CT_COMMAND); | 384 | list_t *criterias = criteria_for_view(view, CT_COMMAND); |
405 | for (int i = 0; i < criterias->length; i++) { | 385 | for (int i = 0; i < criterias->length; i++) { |
406 | struct criteria *criteria = criterias->items[i]; | 386 | struct criteria *criteria = criterias->items[i]; |
@@ -411,7 +391,7 @@ void view_execute_criteria(struct sway_view *view) { | |||
411 | } | 391 | } |
412 | wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'", | 392 | wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'", |
413 | criteria->raw, view, criteria->cmdlist); | 393 | criteria->raw, view, criteria->cmdlist); |
414 | seat_set_focus(seat, view->swayc); | 394 | seat_set_focus(seat, &view->container->node); |
415 | list_add(view->executed_criteria, criteria); | 395 | list_add(view->executed_criteria, criteria); |
416 | struct cmd_results *res = execute_command(criteria->cmdlist, NULL); | 396 | struct cmd_results *res = execute_command(criteria->cmdlist, NULL); |
417 | if (res->status != CMD_SUCCESS) { | 397 | if (res->status != CMD_SUCCESS) { |
@@ -423,19 +403,19 @@ void view_execute_criteria(struct sway_view *view) { | |||
423 | seat_set_focus(seat, prior_focus); | 403 | seat_set_focus(seat, prior_focus); |
424 | } | 404 | } |
425 | 405 | ||
426 | static struct sway_container *select_workspace(struct sway_view *view) { | 406 | static struct sway_workspace *select_workspace(struct sway_view *view) { |
427 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 407 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
428 | 408 | ||
429 | // Check if there's any `assign` criteria for the view | 409 | // Check if there's any `assign` criteria for the view |
430 | list_t *criterias = criteria_for_view(view, | 410 | list_t *criterias = criteria_for_view(view, |
431 | CT_ASSIGN_WORKSPACE | CT_ASSIGN_WORKSPACE_NUMBER | CT_ASSIGN_OUTPUT); | 411 | CT_ASSIGN_WORKSPACE | CT_ASSIGN_WORKSPACE_NUMBER | CT_ASSIGN_OUTPUT); |
432 | struct sway_container *ws = NULL; | 412 | struct sway_workspace *ws = NULL; |
433 | for (int i = 0; i < criterias->length; ++i) { | 413 | for (int i = 0; i < criterias->length; ++i) { |
434 | struct criteria *criteria = criterias->items[i]; | 414 | struct criteria *criteria = criterias->items[i]; |
435 | if (criteria->type == CT_ASSIGN_OUTPUT) { | 415 | if (criteria->type == CT_ASSIGN_OUTPUT) { |
436 | struct sway_container *output = output_by_name(criteria->target); | 416 | struct sway_output *output = output_by_name(criteria->target); |
437 | if (output) { | 417 | if (output) { |
438 | ws = seat_get_active_child(seat, output); | 418 | ws = output_get_active_workspace(output); |
439 | break; | 419 | break; |
440 | } | 420 | } |
441 | } else { | 421 | } else { |
@@ -484,20 +464,14 @@ static struct sway_container *select_workspace(struct sway_view *view) { | |||
484 | } | 464 | } |
485 | 465 | ||
486 | // Use the focused workspace | 466 | // Use the focused workspace |
487 | ws = seat_get_focus_inactive(seat, &root_container); | 467 | return seat_get_focused_workspace(seat); |
488 | if (ws->type != C_WORKSPACE) { | ||
489 | ws = container_parent(ws, C_WORKSPACE); | ||
490 | } | ||
491 | return ws; | ||
492 | } | 468 | } |
493 | 469 | ||
494 | static bool should_focus(struct sway_view *view) { | 470 | static bool should_focus(struct sway_view *view) { |
495 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 471 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
496 | struct sway_container *prev_focus = | 472 | struct sway_container *prev_con = seat_get_focused_container(seat); |
497 | seat_get_focus_inactive(seat, &root_container); | 473 | struct sway_workspace *prev_ws = seat_get_focused_workspace(seat); |
498 | struct sway_container *prev_ws = prev_focus->type == C_WORKSPACE ? | 474 | struct sway_workspace *map_ws = view->container->workspace; |
499 | prev_focus : container_parent(prev_focus, C_WORKSPACE); | ||
500 | struct sway_container *map_ws = container_parent(view->swayc, C_WORKSPACE); | ||
501 | 475 | ||
502 | // Views can only take focus if they are mapped into the active workspace | 476 | // Views can only take focus if they are mapped into the active workspace |
503 | if (prev_ws != map_ws) { | 477 | if (prev_ws != map_ws) { |
@@ -506,10 +480,9 @@ static bool should_focus(struct sway_view *view) { | |||
506 | 480 | ||
507 | // If the view is the only one in the focused workspace, it'll get focus | 481 | // If the view is the only one in the focused workspace, it'll get focus |
508 | // regardless of any no_focus criteria. | 482 | // regardless of any no_focus criteria. |
509 | struct sway_container *parent = view->swayc->parent; | 483 | if (!view->container->parent && !prev_con) { |
510 | if (parent->type == C_WORKSPACE && prev_focus == parent) { | 484 | size_t num_children = view->container->workspace->tiling->length + |
511 | size_t num_children = parent->children->length + | 485 | view->container->workspace->floating->length; |
512 | parent->sway_workspace->floating->length; | ||
513 | if (num_children == 1) { | 486 | if (num_children == 1) { |
514 | return true; | 487 | return true; |
515 | } | 488 | } |
@@ -529,16 +502,24 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { | |||
529 | view->surface = wlr_surface; | 502 | view->surface = wlr_surface; |
530 | 503 | ||
531 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 504 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
532 | struct sway_container *ws = select_workspace(view); | 505 | struct sway_workspace *ws = select_workspace(view); |
533 | struct sway_container *target_sibling = seat_get_focus_inactive(seat, ws); | 506 | struct sway_node *node = seat_get_focus_inactive(seat, &ws->node); |
507 | struct sway_container *target_sibling = node->type == N_CONTAINER ? | ||
508 | node->sway_container : NULL; | ||
534 | 509 | ||
535 | // If we're about to launch the view into the floating container, then | 510 | // If we're about to launch the view into the floating container, then |
536 | // launch it as a tiled view in the root of the workspace instead. | 511 | // launch it as a tiled view in the root of the workspace instead. |
537 | if (container_is_floating(target_sibling)) { | 512 | if (target_sibling && container_is_floating(target_sibling)) { |
538 | target_sibling = target_sibling->parent; | 513 | target_sibling = NULL; |
539 | } | 514 | } |
540 | 515 | ||
541 | view->swayc = container_view_create(target_sibling, view); | 516 | view->container = container_create(view); |
517 | if (target_sibling) { | ||
518 | container_add_sibling(target_sibling, view->container, 1); | ||
519 | } else { | ||
520 | workspace_add_tiling(ws, view->container); | ||
521 | } | ||
522 | ipc_event_window(view->container, "new"); | ||
542 | 523 | ||
543 | view_init_subsurfaces(view, wlr_surface); | 524 | view_init_subsurfaces(view, wlr_surface); |
544 | wl_signal_add(&wlr_surface->events.new_subsurface, | 525 | wl_signal_add(&wlr_surface->events.new_subsurface, |
@@ -548,7 +529,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { | |||
548 | if (view->impl->wants_floating && view->impl->wants_floating(view)) { | 529 | if (view->impl->wants_floating && view->impl->wants_floating(view)) { |
549 | view->border = config->floating_border; | 530 | view->border = config->floating_border; |
550 | view->border_thickness = config->floating_border_thickness; | 531 | view->border_thickness = config->floating_border_thickness; |
551 | container_set_floating(view->swayc, true); | 532 | container_set_floating(view->container, true); |
552 | } else { | 533 | } else { |
553 | view->border = config->border; | 534 | view->border = config->border; |
554 | view->border_thickness = config->border_thickness; | 535 | view->border_thickness = config->border_thickness; |
@@ -556,11 +537,11 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { | |||
556 | } | 537 | } |
557 | 538 | ||
558 | if (should_focus(view)) { | 539 | if (should_focus(view)) { |
559 | input_manager_set_focus(input_manager, view->swayc); | 540 | input_manager_set_focus(input_manager, &view->container->node); |
560 | } | 541 | } |
561 | 542 | ||
562 | view_update_title(view, false); | 543 | view_update_title(view, false); |
563 | container_notify_subtree_changed(view->swayc->parent); | 544 | container_update_representation(view->container); |
564 | view_execute_criteria(view); | 545 | view_execute_criteria(view); |
565 | } | 546 | } |
566 | 547 | ||
@@ -574,17 +555,17 @@ void view_unmap(struct sway_view *view) { | |||
574 | view->urgent_timer = NULL; | 555 | view->urgent_timer = NULL; |
575 | } | 556 | } |
576 | 557 | ||
577 | bool was_fullscreen = view->swayc->is_fullscreen; | 558 | struct sway_container *parent = view->container->parent; |
578 | struct sway_container *parent = view->swayc->parent; | 559 | struct sway_workspace *ws = view->container->workspace; |
579 | container_begin_destroy(view->swayc); | 560 | container_begin_destroy(view->container); |
580 | struct sway_container *surviving_ancestor = container_reap_empty(parent); | 561 | if (parent) { |
562 | container_reap_empty(parent); | ||
563 | } else { | ||
564 | workspace_consider_destroy(ws); | ||
565 | } | ||
581 | 566 | ||
582 | // If the workspace wasn't reaped | 567 | if (!ws->node.destroying) { |
583 | if (surviving_ancestor && surviving_ancestor->type >= C_WORKSPACE) { | 568 | arrange_workspace(ws); |
584 | struct sway_container *ws = surviving_ancestor->type == C_WORKSPACE ? | ||
585 | surviving_ancestor : | ||
586 | container_parent(surviving_ancestor, C_WORKSPACE); | ||
587 | arrange_windows(was_fullscreen ? ws : surviving_ancestor); | ||
588 | workspace_detect_urgent(ws); | 569 | workspace_detect_urgent(ws); |
589 | } | 570 | } |
590 | 571 | ||
@@ -593,15 +574,15 @@ void view_unmap(struct sway_view *view) { | |||
593 | } | 574 | } |
594 | 575 | ||
595 | void view_update_size(struct sway_view *view, int width, int height) { | 576 | void view_update_size(struct sway_view *view, int width, int height) { |
596 | if (!sway_assert(container_is_floating(view->swayc), | 577 | if (!sway_assert(container_is_floating(view->container), |
597 | "Expected a floating container")) { | 578 | "Expected a floating container")) { |
598 | return; | 579 | return; |
599 | } | 580 | } |
600 | view->width = width; | 581 | view->width = width; |
601 | view->height = height; | 582 | view->height = height; |
602 | view->swayc->current.view_width = width; | 583 | view->container->current.view_width = width; |
603 | view->swayc->current.view_height = height; | 584 | view->container->current.view_height = height; |
604 | container_set_geometry_from_floating_view(view->swayc); | 585 | container_set_geometry_from_floating_view(view->container); |
605 | } | 586 | } |
606 | 587 | ||
607 | static void view_subsurface_create(struct sway_view *view, | 588 | static void view_subsurface_create(struct sway_view *view, |
@@ -670,27 +651,18 @@ void view_child_init(struct sway_view_child *child, | |||
670 | wl_signal_add(&view->events.unmap, &child->view_unmap); | 651 | wl_signal_add(&view->events.unmap, &child->view_unmap); |
671 | child->view_unmap.notify = view_child_handle_view_unmap; | 652 | child->view_unmap.notify = view_child_handle_view_unmap; |
672 | 653 | ||
673 | struct sway_container *output = child->view->swayc->parent; | 654 | struct sway_output *output = child->view->container->workspace->output; |
674 | if (output != NULL) { | 655 | wlr_surface_send_enter(child->surface, output->wlr_output); |
675 | if (output->type != C_OUTPUT) { | ||
676 | output = container_parent(output, C_OUTPUT); | ||
677 | } | ||
678 | wlr_surface_send_enter(child->surface, output->sway_output->wlr_output); | ||
679 | } | ||
680 | 656 | ||
681 | view_init_subsurfaces(child->view, surface); | 657 | view_init_subsurfaces(child->view, surface); |
682 | 658 | ||
683 | // TODO: only damage the whole child | 659 | // TODO: only damage the whole child |
684 | if (child->view->swayc) { | 660 | container_damage_whole(child->view->container); |
685 | container_damage_whole(child->view->swayc); | ||
686 | } | ||
687 | } | 661 | } |
688 | 662 | ||
689 | void view_child_destroy(struct sway_view_child *child) { | 663 | void view_child_destroy(struct sway_view_child *child) { |
690 | // TODO: only damage the whole child | 664 | // TODO: only damage the whole child |
691 | if (child->view->swayc) { | 665 | container_damage_whole(child->view->container); |
692 | container_damage_whole(child->view->swayc); | ||
693 | } | ||
694 | 666 | ||
695 | wl_list_remove(&child->surface_commit.link); | 667 | wl_list_remove(&child->surface_commit.link); |
696 | wl_list_remove(&child->surface_destroy.link); | 668 | wl_list_remove(&child->surface_destroy.link); |
@@ -808,22 +780,20 @@ static char *escape_title(char *buffer) { | |||
808 | } | 780 | } |
809 | 781 | ||
810 | void view_update_title(struct sway_view *view, bool force) { | 782 | void view_update_title(struct sway_view *view, bool force) { |
811 | if (!view->swayc) { | ||
812 | return; | ||
813 | } | ||
814 | const char *title = view_get_title(view); | 783 | const char *title = view_get_title(view); |
815 | 784 | ||
816 | if (!force) { | 785 | if (!force) { |
817 | if (title && view->swayc->name && strcmp(title, view->swayc->name) == 0) { | 786 | if (title && view->container->title && |
787 | strcmp(title, view->container->title) == 0) { | ||
818 | return; | 788 | return; |
819 | } | 789 | } |
820 | if (!title && !view->swayc->name) { | 790 | if (!title && !view->container->title) { |
821 | return; | 791 | return; |
822 | } | 792 | } |
823 | } | 793 | } |
824 | 794 | ||
825 | free(view->swayc->name); | 795 | free(view->container->title); |
826 | free(view->swayc->formatted_title); | 796 | free(view->container->formatted_title); |
827 | if (title) { | 797 | if (title) { |
828 | size_t len = parse_title_format(view, NULL); | 798 | size_t len = parse_title_format(view, NULL); |
829 | char *buffer = calloc(len + 1, sizeof(char)); | 799 | char *buffer = calloc(len + 1, sizeof(char)); |
@@ -836,25 +806,25 @@ void view_update_title(struct sway_view *view, bool force) { | |||
836 | buffer = escape_title(buffer); | 806 | buffer = escape_title(buffer); |
837 | } | 807 | } |
838 | 808 | ||
839 | view->swayc->name = strdup(title); | 809 | view->container->title = strdup(title); |
840 | view->swayc->formatted_title = buffer; | 810 | view->container->formatted_title = buffer; |
841 | } else { | 811 | } else { |
842 | view->swayc->name = NULL; | 812 | view->container->title = NULL; |
843 | view->swayc->formatted_title = NULL; | 813 | view->container->formatted_title = NULL; |
844 | } | 814 | } |
845 | container_calculate_title_height(view->swayc); | 815 | container_calculate_title_height(view->container); |
846 | config_update_font_height(false); | 816 | config_update_font_height(false); |
847 | 817 | ||
848 | // Update title after the global font height is updated | 818 | // Update title after the global font height is updated |
849 | container_update_title_textures(view->swayc); | 819 | container_update_title_textures(view->container); |
850 | 820 | ||
851 | ipc_event_window(view->swayc, "title"); | 821 | ipc_event_window(view->container, "title"); |
852 | } | 822 | } |
853 | 823 | ||
854 | static bool find_by_mark_iterator(struct sway_container *con, | 824 | static bool find_by_mark_iterator(struct sway_container *con, |
855 | void *data) { | 825 | void *data) { |
856 | char *mark = data; | 826 | char *mark = data; |
857 | return con->type == C_VIEW && view_has_mark(con->sway_view, mark); | 827 | return con->view && view_has_mark(con->view, mark); |
858 | } | 828 | } |
859 | 829 | ||
860 | struct sway_view *view_find_mark(char *mark) { | 830 | struct sway_view *view_find_mark(char *mark) { |
@@ -863,7 +833,7 @@ struct sway_view *view_find_mark(char *mark) { | |||
863 | if (!container) { | 833 | if (!container) { |
864 | return NULL; | 834 | return NULL; |
865 | } | 835 | } |
866 | return container->sway_view; | 836 | return container->view; |
867 | } | 837 | } |
868 | 838 | ||
869 | bool view_find_and_unmark(char *mark) { | 839 | bool view_find_and_unmark(char *mark) { |
@@ -872,7 +842,7 @@ bool view_find_and_unmark(char *mark) { | |||
872 | if (!container) { | 842 | if (!container) { |
873 | return false; | 843 | return false; |
874 | } | 844 | } |
875 | struct sway_view *view = container->sway_view; | 845 | struct sway_view *view = container->view; |
876 | 846 | ||
877 | for (int i = 0; i < view->marks->length; ++i) { | 847 | for (int i = 0; i < view->marks->length; ++i) { |
878 | char *view_mark = view->marks->items[i]; | 848 | char *view_mark = view->marks->items[i]; |
@@ -888,10 +858,9 @@ bool view_find_and_unmark(char *mark) { | |||
888 | } | 858 | } |
889 | 859 | ||
890 | void view_clear_marks(struct sway_view *view) { | 860 | void view_clear_marks(struct sway_view *view) { |
891 | while (view->marks->length) { | 861 | list_foreach(view->marks, free); |
892 | list_del(view->marks, 0); | 862 | view->marks->length = 0; |
893 | ipc_event_window(view->swayc, "mark"); | 863 | ipc_event_window(view->container, "mark"); |
894 | } | ||
895 | } | 864 | } |
896 | 865 | ||
897 | bool view_has_mark(struct sway_view *view, char *mark) { | 866 | bool view_has_mark(struct sway_view *view, char *mark) { |
@@ -906,12 +875,13 @@ bool view_has_mark(struct sway_view *view, char *mark) { | |||
906 | 875 | ||
907 | void view_add_mark(struct sway_view *view, char *mark) { | 876 | void view_add_mark(struct sway_view *view, char *mark) { |
908 | list_add(view->marks, strdup(mark)); | 877 | list_add(view->marks, strdup(mark)); |
909 | ipc_event_window(view->swayc, "mark"); | 878 | ipc_event_window(view->container, "mark"); |
910 | } | 879 | } |
911 | 880 | ||
912 | static void update_marks_texture(struct sway_view *view, | 881 | static void update_marks_texture(struct sway_view *view, |
913 | struct wlr_texture **texture, struct border_colors *class) { | 882 | struct wlr_texture **texture, struct border_colors *class) { |
914 | struct sway_output *output = container_get_effective_output(view->swayc); | 883 | struct sway_output *output = |
884 | container_get_effective_output(view->container); | ||
915 | if (!output) { | 885 | if (!output) { |
916 | return; | 886 | return; |
917 | } | 887 | } |
@@ -949,7 +919,7 @@ static void update_marks_texture(struct sway_view *view, | |||
949 | 919 | ||
950 | double scale = output->wlr_output->scale; | 920 | double scale = output->wlr_output->scale; |
951 | int width = 0; | 921 | int width = 0; |
952 | int height = view->swayc->title_height * scale; | 922 | int height = view->container->title_height * scale; |
953 | 923 | ||
954 | cairo_t *c = cairo_create(NULL); | 924 | cairo_t *c = cairo_create(NULL); |
955 | get_text_size(c, config->font, &width, NULL, scale, false, "%s", buffer); | 925 | get_text_size(c, config->font, &width, NULL, scale, false, "%s", buffer); |
@@ -994,44 +964,40 @@ void view_update_marks_textures(struct sway_view *view) { | |||
994 | &config->border_colors.unfocused); | 964 | &config->border_colors.unfocused); |
995 | update_marks_texture(view, &view->marks_urgent, | 965 | update_marks_texture(view, &view->marks_urgent, |
996 | &config->border_colors.urgent); | 966 | &config->border_colors.urgent); |
997 | container_damage_whole(view->swayc); | 967 | container_damage_whole(view->container); |
998 | } | 968 | } |
999 | 969 | ||
1000 | bool view_is_visible(struct sway_view *view) { | 970 | bool view_is_visible(struct sway_view *view) { |
1001 | if (!view->swayc || view->swayc->destroying) { | 971 | if (view->container->node.destroying) { |
1002 | return false; | 972 | return false; |
1003 | } | 973 | } |
1004 | struct sway_container *workspace = | 974 | struct sway_workspace *workspace = view->container->workspace; |
1005 | container_parent(view->swayc, C_WORKSPACE); | ||
1006 | if (!workspace) { | 975 | if (!workspace) { |
1007 | return false; | 976 | return false; |
1008 | } | 977 | } |
1009 | // Determine if view is nested inside a floating container which is sticky. | 978 | // Determine if view is nested inside a floating container which is sticky |
1010 | // A simple floating view will have this ancestry: | 979 | struct sway_container *floater = view->container; |
1011 | // C_VIEW -> floating -> workspace | 980 | while (floater->parent) { |
1012 | // A more complex ancestry could be: | ||
1013 | // C_VIEW -> C_CONTAINER (tabbed) -> floating -> workspace | ||
1014 | struct sway_container *floater = view->swayc; | ||
1015 | while (floater->parent->type != C_WORKSPACE | ||
1016 | && floater->parent->parent->type != C_WORKSPACE) { | ||
1017 | floater = floater->parent; | 981 | floater = floater->parent; |
1018 | } | 982 | } |
1019 | bool is_sticky = container_is_floating(floater) && floater->is_sticky; | 983 | bool is_sticky = container_is_floating(floater) && floater->is_sticky; |
1020 | // Check view isn't in a tabbed or stacked container on an inactive tab | 984 | // Check view isn't in a tabbed or stacked container on an inactive tab |
1021 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 985 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
1022 | struct sway_container *container = view->swayc; | 986 | struct sway_container *container = view->container; |
1023 | while (container->type != C_WORKSPACE) { | 987 | while (container) { |
1024 | if (container->parent->layout == L_TABBED || | 988 | enum sway_container_layout layout = container_parent_layout(container); |
1025 | container->parent->layout == L_STACKED) { | 989 | if (layout == L_TABBED || layout == L_STACKED) { |
1026 | if (seat_get_active_child(seat, container->parent) != container) { | 990 | struct sway_node *parent = container->parent ? |
991 | &container->parent->node : &container->workspace->node; | ||
992 | if (seat_get_active_child(seat, parent) != &container->node) { | ||
1027 | return false; | 993 | return false; |
1028 | } | 994 | } |
1029 | } | 995 | } |
1030 | container = container->parent; | 996 | container = container->parent; |
1031 | } | 997 | } |
1032 | // Check view isn't hidden by another fullscreen view | 998 | // Check view isn't hidden by another fullscreen view |
1033 | if (workspace->sway_workspace->fullscreen && | 999 | if (workspace->fullscreen && |
1034 | !container_is_fullscreen_or_child(view->swayc)) { | 1000 | !container_is_fullscreen_or_child(view->container)) { |
1035 | return false; | 1001 | return false; |
1036 | } | 1002 | } |
1037 | // Check the workspace is visible | 1003 | // Check the workspace is visible |
@@ -1047,7 +1013,7 @@ void view_set_urgent(struct sway_view *view, bool enable) { | |||
1047 | } | 1013 | } |
1048 | if (enable) { | 1014 | if (enable) { |
1049 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 1015 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
1050 | if (seat_get_focus(seat) == view->swayc) { | 1016 | if (seat_get_focused_container(seat) == view->container) { |
1051 | return; | 1017 | return; |
1052 | } | 1018 | } |
1053 | clock_gettime(CLOCK_MONOTONIC, &view->urgent); | 1019 | clock_gettime(CLOCK_MONOTONIC, &view->urgent); |
@@ -1058,12 +1024,11 @@ void view_set_urgent(struct sway_view *view, bool enable) { | |||
1058 | view->urgent_timer = NULL; | 1024 | view->urgent_timer = NULL; |
1059 | } | 1025 | } |
1060 | } | 1026 | } |
1061 | container_damage_whole(view->swayc); | 1027 | container_damage_whole(view->container); |
1062 | 1028 | ||
1063 | ipc_event_window(view->swayc, "urgent"); | 1029 | ipc_event_window(view->container, "urgent"); |
1064 | 1030 | ||
1065 | struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); | 1031 | workspace_detect_urgent(view->container->workspace); |
1066 | workspace_detect_urgent(ws); | ||
1067 | } | 1032 | } |
1068 | 1033 | ||
1069 | bool view_is_urgent(struct sway_view *view) { | 1034 | bool view_is_urgent(struct sway_view *view) { |
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 1957d94f..38ee478e 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c | |||
@@ -12,128 +12,105 @@ | |||
12 | #include "sway/output.h" | 12 | #include "sway/output.h" |
13 | #include "sway/tree/arrange.h" | 13 | #include "sway/tree/arrange.h" |
14 | #include "sway/tree/container.h" | 14 | #include "sway/tree/container.h" |
15 | #include "sway/tree/node.h" | ||
15 | #include "sway/tree/view.h" | 16 | #include "sway/tree/view.h" |
16 | #include "sway/tree/workspace.h" | 17 | #include "sway/tree/workspace.h" |
17 | #include "list.h" | 18 | #include "list.h" |
18 | #include "log.h" | 19 | #include "log.h" |
19 | #include "util.h" | 20 | #include "util.h" |
20 | 21 | ||
21 | struct sway_container *workspace_get_initial_output(const char *name) { | 22 | struct sway_output *workspace_get_initial_output(const char *name) { |
22 | struct sway_container *parent; | ||
23 | // Search for workspace<->output pair | 23 | // Search for workspace<->output pair |
24 | int e = config->workspace_outputs->length; | ||
25 | for (int i = 0; i < config->workspace_outputs->length; ++i) { | 24 | for (int i = 0; i < config->workspace_outputs->length; ++i) { |
26 | struct workspace_output *wso = config->workspace_outputs->items[i]; | 25 | struct workspace_output *wso = config->workspace_outputs->items[i]; |
27 | if (strcasecmp(wso->workspace, name) == 0) { | 26 | if (strcasecmp(wso->workspace, name) == 0) { |
28 | // Find output to use if it exists | 27 | // Find output to use if it exists |
29 | e = root_container.children->length; | 28 | struct sway_output *output = output_by_name(wso->output); |
30 | for (i = 0; i < e; ++i) { | 29 | if (output) { |
31 | parent = root_container.children->items[i]; | 30 | return output; |
32 | if (strcmp(parent->name, wso->output) == 0) { | ||
33 | return parent; | ||
34 | } | ||
35 | } | 31 | } |
36 | break; | 32 | break; |
37 | } | 33 | } |
38 | } | 34 | } |
39 | // Otherwise put it on the focused output | 35 | // Otherwise put it on the focused output |
40 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 36 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
41 | struct sway_container *focus = | 37 | struct sway_workspace *focus = seat_get_focused_workspace(seat); |
42 | seat_get_focus_inactive(seat, &root_container); | 38 | return focus->output; |
43 | parent = focus; | ||
44 | parent = container_parent(parent, C_OUTPUT); | ||
45 | return parent; | ||
46 | } | 39 | } |
47 | 40 | ||
48 | struct sway_container *workspace_create(struct sway_container *output, | 41 | struct sway_workspace *workspace_create(struct sway_output *output, |
49 | const char *name) { | 42 | const char *name) { |
50 | if (output == NULL) { | 43 | if (output == NULL) { |
51 | output = workspace_get_initial_output(name); | 44 | output = workspace_get_initial_output(name); |
52 | } | 45 | } |
53 | 46 | ||
54 | wlr_log(WLR_DEBUG, "Added workspace %s for output %s", name, output->name); | 47 | wlr_log(WLR_DEBUG, "Adding workspace %s for output %s", name, |
55 | struct sway_container *workspace = container_create(C_WORKSPACE); | 48 | output->wlr_output->name); |
56 | |||
57 | workspace->x = output->x; | ||
58 | workspace->y = output->y; | ||
59 | workspace->width = output->width; | ||
60 | workspace->height = output->height; | ||
61 | workspace->name = !name ? NULL : strdup(name); | ||
62 | workspace->prev_split_layout = L_NONE; | ||
63 | workspace->layout = container_get_default_layout(output); | ||
64 | 49 | ||
65 | struct sway_workspace *swayws = calloc(1, sizeof(struct sway_workspace)); | 50 | struct sway_workspace *ws = calloc(1, sizeof(struct sway_workspace)); |
66 | if (!swayws) { | 51 | if (!ws) { |
52 | wlr_log(WLR_ERROR, "Unable to allocate sway_workspace"); | ||
67 | return NULL; | 53 | return NULL; |
68 | } | 54 | } |
69 | swayws->swayc = workspace; | 55 | node_init(&ws->node, N_WORKSPACE, ws); |
70 | swayws->floating = create_list(); | 56 | ws->x = output->wlr_output->lx; |
71 | swayws->output_priority = create_list(); | 57 | ws->y = output->wlr_output->ly; |
72 | workspace->sway_workspace = swayws; | 58 | ws->width = output->wlr_output->width; |
73 | workspace_output_add_priority(workspace, output); | 59 | ws->height = output->wlr_output->height; |
74 | 60 | ws->name = name ? strdup(name) : NULL; | |
75 | container_add_child(output, workspace); | 61 | ws->prev_split_layout = L_NONE; |
62 | ws->layout = output_get_default_layout(output); | ||
63 | ws->floating = create_list(); | ||
64 | ws->tiling = create_list(); | ||
65 | ws->output_priority = create_list(); | ||
66 | workspace_output_add_priority(ws, output); | ||
67 | |||
68 | output_add_workspace(output, ws); | ||
76 | output_sort_workspaces(output); | 69 | output_sort_workspaces(output); |
77 | container_create_notify(workspace); | ||
78 | 70 | ||
79 | return workspace; | 71 | ipc_event_workspace(NULL, ws, "init"); |
72 | wl_signal_emit(&root->events.new_node, &ws->node); | ||
73 | |||
74 | return ws; | ||
80 | } | 75 | } |
81 | 76 | ||
82 | void workspace_destroy(struct sway_container *workspace) { | 77 | void workspace_destroy(struct sway_workspace *workspace) { |
83 | if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { | 78 | if (!sway_assert(workspace->node.destroying, |
84 | return; | ||
85 | } | ||
86 | if (!sway_assert(workspace->destroying, | ||
87 | "Tried to free workspace which wasn't marked as destroying")) { | 79 | "Tried to free workspace which wasn't marked as destroying")) { |
88 | return; | 80 | return; |
89 | } | 81 | } |
90 | if (!sway_assert(workspace->ntxnrefs == 0, "Tried to free workspace " | 82 | if (!sway_assert(workspace->node.ntxnrefs == 0, "Tried to free workspace " |
91 | "which is still referenced by transactions")) { | 83 | "which is still referenced by transactions")) { |
92 | return; | 84 | return; |
93 | } | 85 | } |
94 | // sway_workspace | ||
95 | struct sway_workspace *ws = workspace->sway_workspace; | ||
96 | list_foreach(ws->output_priority, free); | ||
97 | list_free(ws->output_priority); | ||
98 | list_free(ws->floating); | ||
99 | free(ws); | ||
100 | 86 | ||
101 | // swayc | ||
102 | free(workspace->name); | 87 | free(workspace->name); |
103 | free(workspace->formatted_title); | 88 | free(workspace->representation); |
104 | wlr_texture_destroy(workspace->title_focused); | 89 | list_foreach(workspace->output_priority, free); |
105 | wlr_texture_destroy(workspace->title_focused_inactive); | 90 | list_free(workspace->output_priority); |
106 | wlr_texture_destroy(workspace->title_unfocused); | 91 | list_free(workspace->floating); |
107 | wlr_texture_destroy(workspace->title_urgent); | 92 | list_free(workspace->tiling); |
108 | list_free(workspace->children); | 93 | list_free(workspace->current.floating); |
109 | list_free(workspace->current.children); | 94 | list_free(workspace->current.tiling); |
110 | list_free(workspace->outputs); | ||
111 | free(workspace); | 95 | free(workspace); |
112 | } | 96 | } |
113 | 97 | ||
114 | void workspace_begin_destroy(struct sway_container *workspace) { | 98 | void workspace_begin_destroy(struct sway_workspace *workspace) { |
115 | if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { | ||
116 | return; | ||
117 | } | ||
118 | wlr_log(WLR_DEBUG, "Destroying workspace '%s'", workspace->name); | 99 | wlr_log(WLR_DEBUG, "Destroying workspace '%s'", workspace->name); |
119 | wl_signal_emit(&workspace->events.destroy, workspace); | ||
120 | ipc_event_workspace(NULL, workspace, "empty"); // intentional | 100 | ipc_event_workspace(NULL, workspace, "empty"); // intentional |
101 | wl_signal_emit(&workspace->node.events.destroy, &workspace->node); | ||
121 | 102 | ||
122 | workspace->destroying = true; | 103 | if (workspace->output) { |
123 | container_set_dirty(workspace); | 104 | workspace_detach(workspace); |
124 | |||
125 | if (workspace->parent) { | ||
126 | container_remove_child(workspace); | ||
127 | } | 105 | } |
106 | |||
107 | workspace->node.destroying = true; | ||
108 | node_set_dirty(&workspace->node); | ||
128 | } | 109 | } |
129 | 110 | ||
130 | void workspace_consider_destroy(struct sway_container *ws) { | 111 | void workspace_consider_destroy(struct sway_workspace *ws) { |
131 | if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { | 112 | if (ws->tiling->length == 0 && ws->floating->length == 0 |
132 | return; | 113 | && output_get_active_workspace(ws->output) != ws) { |
133 | } | ||
134 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
135 | if (ws->children->length == 0 && ws->sway_workspace->floating->length == 0 | ||
136 | && seat_get_active_child(seat, ws->parent) != ws) { | ||
137 | workspace_begin_destroy(ws); | 114 | workspace_begin_destroy(ws); |
138 | } | 115 | } |
139 | } | 116 | } |
@@ -272,59 +249,49 @@ char *workspace_next_name(const char *output_name) { | |||
272 | } | 249 | } |
273 | // As a fall back, get the current number of active workspaces | 250 | // As a fall back, get the current number of active workspaces |
274 | // and return that + 1 for the next workspace's name | 251 | // and return that + 1 for the next workspace's name |
275 | int ws_num = root_container.children->length; | 252 | int ws_num = root->outputs->length; |
276 | int l = snprintf(NULL, 0, "%d", ws_num); | 253 | int l = snprintf(NULL, 0, "%d", ws_num); |
277 | char *name = malloc(l + 1); | 254 | char *name = malloc(l + 1); |
278 | if (!sway_assert(name, "Cloud not allocate workspace name")) { | 255 | if (!sway_assert(name, "Could not allocate workspace name")) { |
279 | return NULL; | 256 | return NULL; |
280 | } | 257 | } |
281 | sprintf(name, "%d", ws_num++); | 258 | sprintf(name, "%d", ws_num++); |
282 | return name; | 259 | return name; |
283 | } | 260 | } |
284 | 261 | ||
285 | static bool _workspace_by_number(struct sway_container *view, void *data) { | 262 | static bool _workspace_by_number(struct sway_workspace *ws, void *data) { |
286 | if (view->type != C_WORKSPACE) { | ||
287 | return false; | ||
288 | } | ||
289 | char *name = data; | 263 | char *name = data; |
290 | char *view_name = view->name; | 264 | char *ws_name = ws->name; |
291 | while (isdigit(*name)) { | 265 | while (isdigit(*name)) { |
292 | if (*name++ != *view_name++) { | 266 | if (*name++ != *ws_name++) { |
293 | return false; | 267 | return false; |
294 | } | 268 | } |
295 | } | 269 | } |
296 | return !isdigit(*view_name); | 270 | return !isdigit(*ws_name); |
297 | } | 271 | } |
298 | 272 | ||
299 | struct sway_container *workspace_by_number(const char* name) { | 273 | struct sway_workspace *workspace_by_number(const char* name) { |
300 | return root_find_workspace(_workspace_by_number, (void *) name); | 274 | return root_find_workspace(_workspace_by_number, (void *) name); |
301 | } | 275 | } |
302 | 276 | ||
303 | static bool _workspace_by_name(struct sway_container *view, void *data) { | 277 | static bool _workspace_by_name(struct sway_workspace *ws, void *data) { |
304 | return (view->type == C_WORKSPACE) && | 278 | return strcasecmp(ws->name, data) == 0; |
305 | (strcasecmp(view->name, (char *) data) == 0); | ||
306 | } | 279 | } |
307 | 280 | ||
308 | struct sway_container *workspace_by_name(const char *name) { | 281 | struct sway_workspace *workspace_by_name(const char *name) { |
309 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 282 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
310 | struct sway_container *current_workspace = NULL, *current_output = NULL; | 283 | struct sway_workspace *current = seat_get_focused_workspace(seat); |
311 | struct sway_container *focus = seat_get_focus(seat); | ||
312 | if (focus) { | ||
313 | current_workspace = focus->type == C_WORKSPACE ? | ||
314 | focus : container_parent(focus, C_WORKSPACE); | ||
315 | current_output = container_parent(focus, C_OUTPUT); | ||
316 | } | ||
317 | 284 | ||
318 | if (strcmp(name, "prev") == 0) { | 285 | if (strcmp(name, "prev") == 0) { |
319 | return workspace_prev(current_workspace); | 286 | return workspace_prev(current); |
320 | } else if (strcmp(name, "prev_on_output") == 0) { | 287 | } else if (strcmp(name, "prev_on_output") == 0) { |
321 | return workspace_output_prev(current_output); | 288 | return workspace_output_prev(current); |
322 | } else if (strcmp(name, "next") == 0) { | 289 | } else if (strcmp(name, "next") == 0) { |
323 | return workspace_next(current_workspace); | 290 | return workspace_next(current); |
324 | } else if (strcmp(name, "next_on_output") == 0) { | 291 | } else if (strcmp(name, "next_on_output") == 0) { |
325 | return workspace_output_next(current_output); | 292 | return workspace_output_next(current); |
326 | } else if (strcmp(name, "current") == 0) { | 293 | } else if (strcmp(name, "current") == 0) { |
327 | return current_workspace; | 294 | return current; |
328 | } else if (strcasecmp(name, "back_and_forth") == 0) { | 295 | } else if (strcasecmp(name, "back_and_forth") == 0) { |
329 | return prev_workspace_name ? | 296 | return prev_workspace_name ? |
330 | root_find_workspace(_workspace_by_name, (void*)prev_workspace_name) | 297 | root_find_workspace(_workspace_by_name, (void*)prev_workspace_name) |
@@ -339,97 +306,68 @@ struct sway_container *workspace_by_name(const char *name) { | |||
339 | * the end and beginning. If next is false, the previous workspace is returned, | 306 | * the end and beginning. If next is false, the previous workspace is returned, |
340 | * otherwise the next one is returned. | 307 | * otherwise the next one is returned. |
341 | */ | 308 | */ |
342 | static struct sway_container *workspace_output_prev_next_impl( | 309 | static struct sway_workspace *workspace_output_prev_next_impl( |
343 | struct sway_container *output, int dir) { | 310 | struct sway_output *output, int dir) { |
344 | if (!output) { | ||
345 | return NULL; | ||
346 | } | ||
347 | if (!sway_assert(output->type == C_OUTPUT, | ||
348 | "Argument must be an output, is %d", output->type)) { | ||
349 | return NULL; | ||
350 | } | ||
351 | |||
352 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 311 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
353 | struct sway_container *focus = seat_get_focus_inactive(seat, output); | 312 | struct sway_workspace *workspace = seat_get_focused_workspace(seat); |
354 | struct sway_container *workspace = (focus->type == C_WORKSPACE ? | ||
355 | focus : | ||
356 | container_parent(focus, C_WORKSPACE)); | ||
357 | 313 | ||
358 | int index = list_find(output->children, workspace); | 314 | int index = list_find(output->workspaces, workspace); |
359 | size_t new_index = wrap(index + dir, output->children->length); | 315 | size_t new_index = wrap(index + dir, output->workspaces->length); |
360 | return output->children->items[new_index]; | 316 | return output->workspaces->items[new_index]; |
361 | } | 317 | } |
362 | 318 | ||
363 | /** | 319 | /** |
364 | * Get the previous or next workspace. If the first/last workspace on an output | 320 | * Get the previous or next workspace. If the first/last workspace on an output |
365 | * is active, proceed to the previous/next output's previous/next workspace. | 321 | * is active, proceed to the previous/next output's previous/next workspace. |
366 | */ | 322 | */ |
367 | static struct sway_container *workspace_prev_next_impl( | 323 | static struct sway_workspace *workspace_prev_next_impl( |
368 | struct sway_container *workspace, int dir) { | 324 | struct sway_workspace *workspace, int dir) { |
369 | if (!workspace) { | 325 | struct sway_output *output = workspace->output; |
370 | return NULL; | 326 | int index = list_find(output->workspaces, workspace); |
371 | } | ||
372 | if (!sway_assert(workspace->type == C_WORKSPACE, | ||
373 | "Argument must be a workspace, is %d", workspace->type)) { | ||
374 | return NULL; | ||
375 | } | ||
376 | |||
377 | struct sway_container *output = workspace->parent; | ||
378 | int index = list_find(output->children, workspace); | ||
379 | int new_index = index + dir; | 327 | int new_index = index + dir; |
380 | 328 | ||
381 | if (new_index >= 0 && new_index < output->children->length) { | 329 | if (new_index >= 0 && new_index < output->workspaces->length) { |
382 | return output->children->items[index + dir]; | 330 | return output->workspaces->items[new_index]; |
383 | } | 331 | } |
384 | 332 | ||
385 | // Look on a different output | 333 | // Look on a different output |
386 | int output_index = list_find(root_container.children, output); | 334 | int output_index = list_find(root->outputs, output); |
387 | new_index = wrap(output_index + dir, root_container.children->length); | 335 | new_index = wrap(output_index + dir, root->outputs->length); |
388 | output = root_container.children->items[new_index]; | 336 | output = root->outputs->items[new_index]; |
389 | 337 | ||
390 | if (dir == 1) { | 338 | if (dir == 1) { |
391 | return output->children->items[0]; | 339 | return output->workspaces->items[0]; |
392 | } else { | 340 | } else { |
393 | return output->children->items[output->children->length - 1]; | 341 | return output->workspaces->items[output->workspaces->length - 1]; |
394 | } | 342 | } |
395 | } | 343 | } |
396 | 344 | ||
397 | struct sway_container *workspace_output_next(struct sway_container *current) { | 345 | struct sway_workspace *workspace_output_next(struct sway_workspace *current) { |
398 | return workspace_output_prev_next_impl(current, 1); | 346 | return workspace_output_prev_next_impl(current->output, 1); |
399 | } | 347 | } |
400 | 348 | ||
401 | struct sway_container *workspace_next(struct sway_container *current) { | 349 | struct sway_workspace *workspace_next(struct sway_workspace *current) { |
402 | return workspace_prev_next_impl(current, 1); | 350 | return workspace_prev_next_impl(current, 1); |
403 | } | 351 | } |
404 | 352 | ||
405 | struct sway_container *workspace_output_prev(struct sway_container *current) { | 353 | struct sway_workspace *workspace_output_prev(struct sway_workspace *current) { |
406 | return workspace_output_prev_next_impl(current, -1); | 354 | return workspace_output_prev_next_impl(current->output, -1); |
407 | } | 355 | } |
408 | 356 | ||
409 | struct sway_container *workspace_prev(struct sway_container *current) { | 357 | struct sway_workspace *workspace_prev(struct sway_workspace *current) { |
410 | return workspace_prev_next_impl(current, -1); | 358 | return workspace_prev_next_impl(current, -1); |
411 | } | 359 | } |
412 | 360 | ||
413 | bool workspace_switch(struct sway_container *workspace, | 361 | bool workspace_switch(struct sway_workspace *workspace, |
414 | bool no_auto_back_and_forth) { | 362 | bool no_auto_back_and_forth) { |
415 | if (!workspace) { | ||
416 | return false; | ||
417 | } | ||
418 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 363 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
419 | struct sway_container *focus = | 364 | struct sway_node *focus = seat_get_focus_inactive(seat, &root->node); |
420 | seat_get_focus_inactive(seat, &root_container); | 365 | struct sway_workspace *active_ws = seat_get_focused_workspace(seat); |
421 | if (!seat || !focus) { | ||
422 | return false; | ||
423 | } | ||
424 | struct sway_container *active_ws = focus; | ||
425 | if (active_ws->type != C_WORKSPACE) { | ||
426 | active_ws = container_parent(focus, C_WORKSPACE); | ||
427 | } | ||
428 | 366 | ||
429 | if (!no_auto_back_and_forth && config->auto_back_and_forth | 367 | if (!no_auto_back_and_forth && config->auto_back_and_forth |
430 | && active_ws == workspace | 368 | && active_ws == workspace |
431 | && prev_workspace_name) { | 369 | && prev_workspace_name) { |
432 | struct sway_container *new_ws = workspace_by_name(prev_workspace_name); | 370 | struct sway_workspace *new_ws = workspace_by_name(prev_workspace_name); |
433 | workspace = new_ws ? | 371 | workspace = new_ws ? |
434 | new_ws : | 372 | new_ws : |
435 | workspace_create(NULL, prev_workspace_name); | 373 | workspace_create(NULL, prev_workspace_name); |
@@ -447,21 +385,21 @@ bool workspace_switch(struct sway_container *workspace, | |||
447 | } | 385 | } |
448 | 386 | ||
449 | // Move sticky containers to new workspace | 387 | // Move sticky containers to new workspace |
450 | struct sway_container *next_output = workspace->parent; | 388 | struct sway_output *next_output = workspace->output; |
451 | struct sway_container *next_output_prev_ws = | 389 | struct sway_workspace *next_output_prev_ws = |
452 | seat_get_active_child(seat, next_output); | 390 | output_get_active_workspace(next_output); |
453 | list_t *floating = next_output_prev_ws->sway_workspace->floating; | ||
454 | bool has_sticky = false; | 391 | bool has_sticky = false; |
455 | if (workspace != next_output_prev_ws) { | 392 | if (workspace != next_output_prev_ws) { |
456 | for (int i = 0; i < floating->length; ++i) { | 393 | for (int i = 0; i < next_output_prev_ws->floating->length; ++i) { |
457 | struct sway_container *floater = floating->items[i]; | 394 | struct sway_container *floater = |
395 | next_output_prev_ws->floating->items[i]; | ||
458 | if (floater->is_sticky) { | 396 | if (floater->is_sticky) { |
459 | has_sticky = true; | 397 | has_sticky = true; |
460 | container_remove_child(floater); | 398 | container_detach(floater); |
461 | workspace_add_floating(workspace, floater); | 399 | workspace_add_floating(workspace, floater); |
462 | if (floater == focus) { | 400 | if (&floater->node == focus) { |
463 | seat_set_focus(seat, NULL); | 401 | seat_set_focus(seat, NULL); |
464 | seat_set_focus(seat, floater); | 402 | seat_set_focus(seat, &floater->node); |
465 | } | 403 | } |
466 | --i; | 404 | --i; |
467 | } | 405 | } |
@@ -470,9 +408,9 @@ bool workspace_switch(struct sway_container *workspace, | |||
470 | 408 | ||
471 | wlr_log(WLR_DEBUG, "Switching to workspace %p:%s", | 409 | wlr_log(WLR_DEBUG, "Switching to workspace %p:%s", |
472 | workspace, workspace->name); | 410 | workspace, workspace->name); |
473 | struct sway_container *next = seat_get_focus_inactive(seat, workspace); | 411 | struct sway_node *next = seat_get_focus_inactive(seat, &workspace->node); |
474 | if (next == NULL) { | 412 | if (next == NULL) { |
475 | next = workspace; | 413 | next = &workspace->node; |
476 | } | 414 | } |
477 | if (has_sticky) { | 415 | if (has_sticky) { |
478 | // If there's a sticky container, we might be setting focus to the same | 416 | // If there's a sticky container, we might be setting focus to the same |
@@ -483,35 +421,24 @@ bool workspace_switch(struct sway_container *workspace, | |||
483 | workspace_consider_destroy(active_ws); | 421 | workspace_consider_destroy(active_ws); |
484 | } | 422 | } |
485 | seat_set_focus(seat, next); | 423 | seat_set_focus(seat, next); |
486 | struct sway_container *output = container_parent(workspace, C_OUTPUT); | 424 | arrange_workspace(workspace); |
487 | arrange_windows(output); | ||
488 | return true; | 425 | return true; |
489 | } | 426 | } |
490 | 427 | ||
491 | bool workspace_is_visible(struct sway_container *ws) { | 428 | bool workspace_is_visible(struct sway_workspace *ws) { |
492 | if (ws->destroying) { | 429 | if (ws->node.destroying) { |
493 | return false; | 430 | return false; |
494 | } | 431 | } |
495 | struct sway_container *output = container_parent(ws, C_OUTPUT); | 432 | return output_get_active_workspace(ws->output) == ws; |
496 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
497 | struct sway_container *focus = seat_get_focus_inactive(seat, output); | ||
498 | if (focus->type != C_WORKSPACE) { | ||
499 | focus = container_parent(focus, C_WORKSPACE); | ||
500 | } | ||
501 | return focus == ws; | ||
502 | } | 433 | } |
503 | 434 | ||
504 | bool workspace_is_empty(struct sway_container *ws) { | 435 | bool workspace_is_empty(struct sway_workspace *ws) { |
505 | if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { | 436 | if (ws->tiling->length) { |
506 | return false; | ||
507 | } | ||
508 | if (ws->children->length) { | ||
509 | return false; | 437 | return false; |
510 | } | 438 | } |
511 | // Sticky views are not considered to be part of this workspace | 439 | // Sticky views are not considered to be part of this workspace |
512 | list_t *floating = ws->sway_workspace->floating; | 440 | for (int i = 0; i < ws->floating->length; ++i) { |
513 | for (int i = 0; i < floating->length; ++i) { | 441 | struct sway_container *floater = ws->floating->items[i]; |
514 | struct sway_container *floater = floating->items[i]; | ||
515 | if (!floater->is_sticky) { | 442 | if (!floater->is_sticky) { |
516 | return false; | 443 | return false; |
517 | } | 444 | } |
@@ -523,20 +450,19 @@ static int find_output(const void *id1, const void *id2) { | |||
523 | return strcmp(id1, id2) ? 0 : 1; | 450 | return strcmp(id1, id2) ? 0 : 1; |
524 | } | 451 | } |
525 | 452 | ||
526 | void workspace_output_raise_priority(struct sway_container *workspace, | 453 | void workspace_output_raise_priority(struct sway_workspace *ws, |
527 | struct sway_container *old_output, struct sway_container *output) { | 454 | struct sway_output *old_output, struct sway_output *output) { |
528 | struct sway_workspace *ws = workspace->sway_workspace; | ||
529 | |||
530 | int old_index = list_seq_find(ws->output_priority, find_output, | 455 | int old_index = list_seq_find(ws->output_priority, find_output, |
531 | old_output->name); | 456 | old_output->wlr_output->name); |
532 | if (old_index < 0) { | 457 | if (old_index < 0) { |
533 | return; | 458 | return; |
534 | } | 459 | } |
535 | 460 | ||
536 | int new_index = list_seq_find(ws->output_priority, find_output, | 461 | int new_index = list_seq_find(ws->output_priority, find_output, |
537 | output->name); | 462 | output->wlr_output->name); |
538 | if (new_index < 0) { | 463 | if (new_index < 0) { |
539 | list_insert(ws->output_priority, old_index, strdup(output->name)); | 464 | list_insert(ws->output_priority, old_index, |
465 | strdup(output->wlr_output->name)); | ||
540 | } else if (new_index > old_index) { | 466 | } else if (new_index > old_index) { |
541 | char *name = ws->output_priority->items[new_index]; | 467 | char *name = ws->output_priority->items[new_index]; |
542 | list_del(ws->output_priority, new_index); | 468 | list_del(ws->output_priority, new_index); |
@@ -544,29 +470,24 @@ void workspace_output_raise_priority(struct sway_container *workspace, | |||
544 | } | 470 | } |
545 | } | 471 | } |
546 | 472 | ||
547 | void workspace_output_add_priority(struct sway_container *workspace, | 473 | void workspace_output_add_priority(struct sway_workspace *workspace, |
548 | struct sway_container *output) { | 474 | struct sway_output *output) { |
549 | int index = list_seq_find(workspace->sway_workspace->output_priority, | 475 | int index = list_seq_find(workspace->output_priority, |
550 | find_output, output->name); | 476 | find_output, output->wlr_output->name); |
551 | if (index < 0) { | 477 | if (index < 0) { |
552 | list_add(workspace->sway_workspace->output_priority, | 478 | list_add(workspace->output_priority, strdup(output->wlr_output->name)); |
553 | strdup(output->name)); | ||
554 | } | 479 | } |
555 | } | 480 | } |
556 | 481 | ||
557 | static bool _output_by_name(struct sway_container *output, void *data) { | 482 | struct sway_output *workspace_output_get_highest_available( |
558 | return output->type == C_OUTPUT && strcasecmp(output->name, data) == 0; | 483 | struct sway_workspace *ws, struct sway_output *exclude) { |
559 | } | 484 | for (int i = 0; i < ws->output_priority->length; i++) { |
560 | 485 | char *name = ws->output_priority->items[i]; | |
561 | struct sway_container *workspace_output_get_highest_available( | 486 | if (exclude && strcasecmp(name, exclude->wlr_output->name) == 0) { |
562 | struct sway_container *ws, struct sway_container *exclude) { | ||
563 | for (int i = 0; i < ws->sway_workspace->output_priority->length; i++) { | ||
564 | char *name = ws->sway_workspace->output_priority->items[i]; | ||
565 | if (exclude && strcasecmp(name, exclude->name) == 0) { | ||
566 | continue; | 487 | continue; |
567 | } | 488 | } |
568 | 489 | ||
569 | struct sway_container *output = root_find_output(_output_by_name, name); | 490 | struct sway_output *output = output_by_name(name); |
570 | if (output) { | 491 | if (output) { |
571 | return output; | 492 | return output; |
572 | } | 493 | } |
@@ -576,49 +497,42 @@ struct sway_container *workspace_output_get_highest_available( | |||
576 | } | 497 | } |
577 | 498 | ||
578 | static bool find_urgent_iterator(struct sway_container *con, void *data) { | 499 | static bool find_urgent_iterator(struct sway_container *con, void *data) { |
579 | return con->type == C_VIEW && view_is_urgent(con->sway_view); | 500 | return con->view && view_is_urgent(con->view); |
580 | } | 501 | } |
581 | 502 | ||
582 | void workspace_detect_urgent(struct sway_container *workspace) { | 503 | void workspace_detect_urgent(struct sway_workspace *workspace) { |
583 | bool new_urgent = (bool)workspace_find_container(workspace, | 504 | bool new_urgent = (bool)workspace_find_container(workspace, |
584 | find_urgent_iterator, NULL); | 505 | find_urgent_iterator, NULL); |
585 | 506 | ||
586 | if (workspace->sway_workspace->urgent != new_urgent) { | 507 | if (workspace->urgent != new_urgent) { |
587 | workspace->sway_workspace->urgent = new_urgent; | 508 | workspace->urgent = new_urgent; |
588 | ipc_event_workspace(NULL, workspace, "urgent"); | 509 | ipc_event_workspace(NULL, workspace, "urgent"); |
589 | container_damage_whole(workspace); | 510 | output_damage_whole(workspace->output); |
590 | } | 511 | } |
591 | } | 512 | } |
592 | 513 | ||
593 | void workspace_for_each_container(struct sway_container *ws, | 514 | void workspace_for_each_container(struct sway_workspace *ws, |
594 | void (*f)(struct sway_container *con, void *data), void *data) { | 515 | void (*f)(struct sway_container *con, void *data), void *data) { |
595 | if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { | ||
596 | return; | ||
597 | } | ||
598 | // Tiling | 516 | // Tiling |
599 | for (int i = 0; i < ws->children->length; ++i) { | 517 | for (int i = 0; i < ws->tiling->length; ++i) { |
600 | struct sway_container *container = ws->children->items[i]; | 518 | struct sway_container *container = ws->tiling->items[i]; |
601 | f(container, data); | 519 | f(container, data); |
602 | container_for_each_child(container, f, data); | 520 | container_for_each_child(container, f, data); |
603 | } | 521 | } |
604 | // Floating | 522 | // Floating |
605 | for (int i = 0; i < ws->sway_workspace->floating->length; ++i) { | 523 | for (int i = 0; i < ws->floating->length; ++i) { |
606 | struct sway_container *container = | 524 | struct sway_container *container = ws->floating->items[i]; |
607 | ws->sway_workspace->floating->items[i]; | ||
608 | f(container, data); | 525 | f(container, data); |
609 | container_for_each_child(container, f, data); | 526 | container_for_each_child(container, f, data); |
610 | } | 527 | } |
611 | } | 528 | } |
612 | 529 | ||
613 | struct sway_container *workspace_find_container(struct sway_container *ws, | 530 | struct sway_container *workspace_find_container(struct sway_workspace *ws, |
614 | bool (*test)(struct sway_container *con, void *data), void *data) { | 531 | bool (*test)(struct sway_container *con, void *data), void *data) { |
615 | if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { | ||
616 | return NULL; | ||
617 | } | ||
618 | struct sway_container *result = NULL; | 532 | struct sway_container *result = NULL; |
619 | // Tiling | 533 | // Tiling |
620 | for (int i = 0; i < ws->children->length; ++i) { | 534 | for (int i = 0; i < ws->tiling->length; ++i) { |
621 | struct sway_container *child = ws->children->items[i]; | 535 | struct sway_container *child = ws->tiling->items[i]; |
622 | if (test(child, data)) { | 536 | if (test(child, data)) { |
623 | return child; | 537 | return child; |
624 | } | 538 | } |
@@ -627,8 +541,8 @@ struct sway_container *workspace_find_container(struct sway_container *ws, | |||
627 | } | 541 | } |
628 | } | 542 | } |
629 | // Floating | 543 | // Floating |
630 | for (int i = 0; i < ws->sway_workspace->floating->length; ++i) { | 544 | for (int i = 0; i < ws->floating->length; ++i) { |
631 | struct sway_container *child = ws->sway_workspace->floating->items[i]; | 545 | struct sway_container *child = ws->floating->items[i]; |
632 | if (test(child, data)) { | 546 | if (test(child, data)) { |
633 | return child; | 547 | return child; |
634 | } | 548 | } |
@@ -639,37 +553,76 @@ struct sway_container *workspace_find_container(struct sway_container *ws, | |||
639 | return NULL; | 553 | return NULL; |
640 | } | 554 | } |
641 | 555 | ||
642 | struct sway_container *workspace_wrap_children(struct sway_container *ws) { | 556 | struct sway_container *workspace_wrap_children(struct sway_workspace *ws) { |
643 | struct sway_container *middle = container_create(C_CONTAINER); | 557 | struct sway_container *middle = container_create(NULL); |
644 | middle->layout = ws->layout; | 558 | middle->layout = ws->layout; |
645 | while (ws->children->length) { | 559 | while (ws->tiling->length) { |
646 | struct sway_container *child = ws->children->items[0]; | 560 | struct sway_container *child = ws->tiling->items[0]; |
647 | container_remove_child(child); | 561 | container_detach(child); |
648 | container_add_child(middle, child); | 562 | container_add_child(middle, child); |
649 | } | 563 | } |
650 | container_add_child(ws, middle); | 564 | workspace_add_tiling(ws, middle); |
651 | return middle; | 565 | return middle; |
652 | } | 566 | } |
653 | 567 | ||
654 | void workspace_add_floating(struct sway_container *workspace, | 568 | void workspace_detach(struct sway_workspace *workspace) { |
655 | struct sway_container *con) { | 569 | struct sway_output *output = workspace->output; |
656 | if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { | 570 | int index = list_find(output->workspaces, workspace); |
657 | return; | 571 | if (index != -1) { |
572 | list_del(output->workspaces, index); | ||
658 | } | 573 | } |
659 | if (!sway_assert(con->parent == NULL, "Expected an orphan container")) { | 574 | workspace->output = NULL; |
660 | return; | 575 | |
576 | node_set_dirty(&workspace->node); | ||
577 | node_set_dirty(&output->node); | ||
578 | } | ||
579 | |||
580 | static void set_workspace(struct sway_container *container, void *data) { | ||
581 | container->workspace = container->parent->workspace; | ||
582 | } | ||
583 | |||
584 | void workspace_add_tiling(struct sway_workspace *workspace, | ||
585 | struct sway_container *con) { | ||
586 | if (con->workspace) { | ||
587 | container_detach(con); | ||
661 | } | 588 | } |
589 | list_add(workspace->tiling, con); | ||
590 | con->workspace = workspace; | ||
591 | container_for_each_child(con, set_workspace, NULL); | ||
592 | container_handle_fullscreen_reparent(con); | ||
593 | workspace_update_representation(workspace); | ||
594 | node_set_dirty(&workspace->node); | ||
595 | node_set_dirty(&con->node); | ||
596 | } | ||
662 | 597 | ||
663 | list_add(workspace->sway_workspace->floating, con); | 598 | void workspace_add_floating(struct sway_workspace *workspace, |
664 | con->parent = workspace; | 599 | struct sway_container *con) { |
665 | container_set_dirty(workspace); | 600 | if (con->workspace) { |
666 | container_set_dirty(con); | 601 | container_detach(con); |
602 | } | ||
603 | list_add(workspace->floating, con); | ||
604 | con->workspace = workspace; | ||
605 | container_for_each_child(con, set_workspace, NULL); | ||
606 | container_handle_fullscreen_reparent(con); | ||
607 | node_set_dirty(&workspace->node); | ||
608 | node_set_dirty(&con->node); | ||
667 | } | 609 | } |
668 | 610 | ||
669 | void workspace_remove_gaps(struct sway_container *ws) { | 611 | void workspace_insert_tiling(struct sway_workspace *workspace, |
670 | if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { | 612 | struct sway_container *con, int index) { |
671 | return; | 613 | if (con->workspace) { |
614 | container_detach(con); | ||
672 | } | 615 | } |
616 | list_insert(workspace->tiling, index, con); | ||
617 | con->workspace = workspace; | ||
618 | container_for_each_child(con, set_workspace, NULL); | ||
619 | container_handle_fullscreen_reparent(con); | ||
620 | workspace_update_representation(workspace); | ||
621 | node_set_dirty(&workspace->node); | ||
622 | node_set_dirty(&con->node); | ||
623 | } | ||
624 | |||
625 | void workspace_remove_gaps(struct sway_workspace *ws) { | ||
673 | if (ws->current_gaps == 0) { | 626 | if (ws->current_gaps == 0) { |
674 | return; | 627 | return; |
675 | } | 628 | } |
@@ -681,15 +634,12 @@ void workspace_remove_gaps(struct sway_container *ws) { | |||
681 | ws->current_gaps = 0; | 634 | ws->current_gaps = 0; |
682 | } | 635 | } |
683 | 636 | ||
684 | void workspace_add_gaps(struct sway_container *ws) { | 637 | void workspace_add_gaps(struct sway_workspace *ws) { |
685 | if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { | ||
686 | return; | ||
687 | } | ||
688 | if (ws->current_gaps > 0) { | 638 | if (ws->current_gaps > 0) { |
689 | return; | 639 | return; |
690 | } | 640 | } |
691 | bool should_apply = | 641 | bool should_apply = |
692 | config->edge_gaps || (config->smart_gaps && ws->children->length > 1); | 642 | config->edge_gaps || (config->smart_gaps && ws->tiling->length > 1); |
693 | if (!should_apply) { | 643 | if (!should_apply) { |
694 | return; | 644 | return; |
695 | } | 645 | } |
@@ -708,3 +658,36 @@ void workspace_add_gaps(struct sway_container *ws) { | |||
708 | ws->width -= 2 * ws->current_gaps; | 658 | ws->width -= 2 * ws->current_gaps; |
709 | ws->height -= 2 * ws->current_gaps; | 659 | ws->height -= 2 * ws->current_gaps; |
710 | } | 660 | } |
661 | |||
662 | struct sway_container *workspace_split(struct sway_workspace *workspace, | ||
663 | enum sway_container_layout layout) { | ||
664 | if (workspace->tiling->length == 0) { | ||
665 | workspace->prev_split_layout = workspace->layout; | ||
666 | workspace->layout = layout; | ||
667 | return NULL; | ||
668 | } | ||
669 | |||
670 | enum sway_container_layout old_layout = workspace->layout; | ||
671 | struct sway_container *middle = workspace_wrap_children(workspace); | ||
672 | workspace->layout = layout; | ||
673 | middle->layout = old_layout; | ||
674 | |||
675 | return middle; | ||
676 | } | ||
677 | |||
678 | void workspace_update_representation(struct sway_workspace *ws) { | ||
679 | size_t len = container_build_representation(ws->layout, ws->tiling, NULL); | ||
680 | free(ws->representation); | ||
681 | ws->representation = calloc(len + 1, sizeof(char)); | ||
682 | if (!sway_assert(ws->representation, "Unable to allocate title string")) { | ||
683 | return; | ||
684 | } | ||
685 | container_build_representation(ws->layout, ws->tiling, ws->representation); | ||
686 | } | ||
687 | |||
688 | void workspace_get_box(struct sway_workspace *workspace, struct wlr_box *box) { | ||
689 | box->x = workspace->x; | ||
690 | box->y = workspace->y; | ||
691 | box->width = workspace->width; | ||
692 | box->height = workspace->height; | ||
693 | } | ||