diff options
author | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-06-23 16:24:11 +1000 |
---|---|---|
committer | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-06-23 16:24:11 +1000 |
commit | 38398e2d77d57dc06b67ec88a54091c897915602 (patch) | |
tree | c80935807865fd96ab7d037070287d4dfaba1863 /sway/tree/container.c | |
parent | Preserve buffers during transactions (diff) | |
download | sway-38398e2d77d57dc06b67ec88a54091c897915602.tar.gz sway-38398e2d77d57dc06b67ec88a54091c897915602.tar.zst sway-38398e2d77d57dc06b67ec88a54091c897915602.zip |
Implement atomic layout updates for tree operations
This implements atomic layout updates for when views map, reparent or
unmap.
Diffstat (limited to 'sway/tree/container.c')
-rw-r--r-- | sway/tree/container.c | 184 |
1 files changed, 93 insertions, 91 deletions
diff --git a/sway/tree/container.c b/sway/tree/container.c index b071f394..484d26a5 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -16,7 +16,6 @@ | |||
16 | #include "sway/ipc-server.h" | 16 | #include "sway/ipc-server.h" |
17 | #include "sway/output.h" | 17 | #include "sway/output.h" |
18 | #include "sway/server.h" | 18 | #include "sway/server.h" |
19 | #include "sway/tree/arrange.h" | ||
20 | #include "sway/tree/layout.h" | 19 | #include "sway/tree/layout.h" |
21 | #include "sway/tree/view.h" | 20 | #include "sway/tree/view.h" |
22 | #include "sway/tree/workspace.h" | 21 | #include "sway/tree/workspace.h" |
@@ -113,10 +112,11 @@ struct sway_container *container_create(enum sway_container_type type) { | |||
113 | c->layout = L_NONE; | 112 | c->layout = L_NONE; |
114 | c->type = type; | 113 | c->type = type; |
115 | c->alpha = 1.0f; | 114 | c->alpha = 1.0f; |
115 | c->instructions = create_list(); | ||
116 | 116 | ||
117 | if (type != C_VIEW) { | 117 | if (type != C_VIEW) { |
118 | c->children = create_list(); | 118 | c->children = create_list(); |
119 | //c->pending.children = create_list(); | 119 | c->current.children = create_list(); |
120 | } | 120 | } |
121 | 121 | ||
122 | wl_signal_init(&c->events.destroy); | 122 | wl_signal_init(&c->events.destroy); |
@@ -133,43 +133,68 @@ struct sway_container *container_create(enum sway_container_type type) { | |||
133 | return c; | 133 | return c; |
134 | } | 134 | } |
135 | 135 | ||
136 | static void _container_destroy(struct sway_container *cont) { | 136 | static void container_workspace_free(struct sway_workspace *ws) { |
137 | if (cont == NULL) { | 137 | list_foreach(ws->output_priority, free); |
138 | return; | 138 | list_free(ws->output_priority); |
139 | } | 139 | ws->floating->destroying = true; |
140 | 140 | container_free(ws->floating); | |
141 | wl_signal_emit(&cont->events.destroy, cont); | 141 | free(ws); |
142 | } | ||
142 | 143 | ||
143 | struct sway_container *parent = cont->parent; | 144 | void container_free(struct sway_container *cont) { |
144 | if (cont->children != NULL && cont->children->length) { | 145 | if (!sway_assert(cont->destroying, |
145 | // remove children until there are no more, container_destroy calls | 146 | "Tried to free container which wasn't marked as destroying")) { |
146 | // container_remove_child, which removes child from this container | 147 | return; |
147 | while (cont->children != NULL && cont->children->length > 0) { | ||
148 | struct sway_container *child = cont->children->items[0]; | ||
149 | ipc_event_window(child, "close"); | ||
150 | container_remove_child(child); | ||
151 | _container_destroy(child); | ||
152 | } | ||
153 | } | ||
154 | if (cont->marks) { | ||
155 | list_foreach(cont->marks, free); | ||
156 | list_free(cont->marks); | ||
157 | } | ||
158 | if (parent) { | ||
159 | parent = container_remove_child(cont); | ||
160 | } | 148 | } |
161 | if (cont->name) { | 149 | if (!sway_assert(cont->instructions->length == 0, |
162 | free(cont->name); | 150 | "Tried to free container with pending instructions")) { |
151 | return; | ||
163 | } | 152 | } |
164 | 153 | free(cont->name); | |
165 | wlr_texture_destroy(cont->title_focused); | 154 | wlr_texture_destroy(cont->title_focused); |
166 | wlr_texture_destroy(cont->title_focused_inactive); | 155 | wlr_texture_destroy(cont->title_focused_inactive); |
167 | wlr_texture_destroy(cont->title_unfocused); | 156 | wlr_texture_destroy(cont->title_unfocused); |
168 | wlr_texture_destroy(cont->title_urgent); | 157 | wlr_texture_destroy(cont->title_urgent); |
169 | 158 | ||
159 | for (int i = 0; i < server.destroying_containers->length; ++i) { | ||
160 | if (server.destroying_containers->items[i] == cont) { | ||
161 | list_del(server.destroying_containers, i); | ||
162 | break; | ||
163 | } | ||
164 | } | ||
165 | |||
166 | list_free(cont->instructions); | ||
170 | list_free(cont->children); | 167 | list_free(cont->children); |
171 | //list_free(cont->pending.children); | 168 | list_free(cont->current.children); |
172 | cont->children = NULL; | 169 | |
170 | switch (cont->type) { | ||
171 | case C_ROOT: | ||
172 | break; | ||
173 | case C_OUTPUT: | ||
174 | cont->sway_output->swayc = NULL; | ||
175 | break; | ||
176 | case C_WORKSPACE: | ||
177 | container_workspace_free(cont->sway_workspace); | ||
178 | break; | ||
179 | case C_CONTAINER: | ||
180 | break; | ||
181 | case C_VIEW: | ||
182 | { | ||
183 | struct sway_view *view = cont->sway_view; | ||
184 | view->swayc = NULL; | ||
185 | free(view->title_format); | ||
186 | view->title_format = NULL; | ||
187 | |||
188 | if (view->destroying) { | ||
189 | view_free(view); | ||
190 | } | ||
191 | } | ||
192 | break; | ||
193 | case C_TYPES: | ||
194 | sway_assert(false, "Didn't expect to see C_TYPES here"); | ||
195 | break; | ||
196 | } | ||
197 | |||
173 | free(cont); | 198 | free(cont); |
174 | } | 199 | } |
175 | 200 | ||
@@ -186,7 +211,6 @@ static struct sway_container *container_workspace_destroy( | |||
186 | } | 211 | } |
187 | 212 | ||
188 | wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name); | 213 | wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name); |
189 | ipc_event_window(workspace, "close"); | ||
190 | 214 | ||
191 | struct sway_container *parent = workspace->parent; | 215 | struct sway_container *parent = workspace->parent; |
192 | if (!workspace_is_empty(workspace) && output) { | 216 | if (!workspace_is_empty(workspace) && output) { |
@@ -209,25 +233,6 @@ static struct sway_container *container_workspace_destroy( | |||
209 | container_move_to(floating->children->items[i], | 233 | container_move_to(floating->children->items[i], |
210 | new_workspace->sway_workspace->floating); | 234 | new_workspace->sway_workspace->floating); |
211 | } | 235 | } |
212 | arrange_and_commit(new_workspace); | ||
213 | } | ||
214 | |||
215 | struct sway_workspace *sway_workspace = workspace->sway_workspace; | ||
216 | |||
217 | // This emits the destroy event and also destroys the swayc. | ||
218 | _container_destroy(workspace); | ||
219 | |||
220 | // Clean up the floating container | ||
221 | sway_workspace->floating->parent = NULL; | ||
222 | _container_destroy(sway_workspace->floating); | ||
223 | |||
224 | list_foreach(sway_workspace->output_priority, free); | ||
225 | list_free(sway_workspace->output_priority); | ||
226 | |||
227 | free(sway_workspace); | ||
228 | |||
229 | if (output) { | ||
230 | output_damage_whole(output->sway_output); | ||
231 | } | 236 | } |
232 | 237 | ||
233 | return parent; | 238 | return parent; |
@@ -266,14 +271,13 @@ static struct sway_container *container_output_destroy( | |||
266 | container_add_child(new_output, workspace); | 271 | container_add_child(new_output, workspace); |
267 | ipc_event_workspace(workspace, NULL, "move"); | 272 | ipc_event_workspace(workspace, NULL, "move"); |
268 | } else { | 273 | } else { |
269 | container_workspace_destroy(workspace); | 274 | container_destroy(workspace); |
270 | } | 275 | } |
271 | 276 | ||
272 | container_sort_workspaces(new_output); | 277 | container_sort_workspaces(new_output); |
273 | } | 278 | } |
274 | } | 279 | } |
275 | } | 280 | } |
276 | arrange_and_commit(&root_container); | ||
277 | 281 | ||
278 | wl_list_remove(&output->sway_output->mode.link); | 282 | wl_list_remove(&output->sway_output->mode.link); |
279 | wl_list_remove(&output->sway_output->transform.link); | 283 | wl_list_remove(&output->sway_output->transform.link); |
@@ -285,12 +289,8 @@ static struct sway_container *container_output_destroy( | |||
285 | output->sway_output->swayc = NULL; | 289 | output->sway_output->swayc = NULL; |
286 | 290 | ||
287 | wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); | 291 | wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); |
288 | _container_destroy(output); | ||
289 | return &root_container; | ||
290 | } | ||
291 | 292 | ||
292 | static void container_root_finish(struct sway_container *con) { | 293 | return &root_container; |
293 | wlr_log(L_ERROR, "TODO: destroy the root container"); | ||
294 | } | 294 | } |
295 | 295 | ||
296 | bool container_reap_empty(struct sway_container *con) { | 296 | bool container_reap_empty(struct sway_container *con) { |
@@ -306,13 +306,13 @@ bool container_reap_empty(struct sway_container *con) { | |||
306 | case C_WORKSPACE: | 306 | case C_WORKSPACE: |
307 | if (!workspace_is_visible(con) && workspace_is_empty(con)) { | 307 | if (!workspace_is_visible(con) && workspace_is_empty(con)) { |
308 | wlr_log(L_DEBUG, "Destroying workspace via reaper"); | 308 | wlr_log(L_DEBUG, "Destroying workspace via reaper"); |
309 | container_workspace_destroy(con); | 309 | container_destroy(con); |
310 | return true; | 310 | return true; |
311 | } | 311 | } |
312 | break; | 312 | break; |
313 | case C_CONTAINER: | 313 | case C_CONTAINER: |
314 | if (con->children->length == 0) { | 314 | if (con->children->length == 0) { |
315 | _container_destroy(con); | 315 | container_destroy(con); |
316 | return true; | 316 | return true; |
317 | } | 317 | } |
318 | case C_VIEW: | 318 | case C_VIEW: |
@@ -349,46 +349,48 @@ struct sway_container *container_flatten(struct sway_container *container) { | |||
349 | return container; | 349 | return container; |
350 | } | 350 | } |
351 | 351 | ||
352 | /** | ||
353 | * container_destroy() is the first step in destroying a container. We'll emit | ||
354 | * events, detach it from the tree and mark it as destroying. The container will | ||
355 | * remain in memory until it's no longer used by a transaction, then it will be | ||
356 | * freed via container_free(). | ||
357 | */ | ||
352 | struct sway_container *container_destroy(struct sway_container *con) { | 358 | struct sway_container *container_destroy(struct sway_container *con) { |
353 | if (con == NULL) { | 359 | if (con == NULL) { |
354 | return NULL; | 360 | return NULL; |
355 | } | 361 | } |
362 | if (con->destroying) { | ||
363 | return NULL; | ||
364 | } | ||
356 | 365 | ||
357 | struct sway_container *parent = con->parent; | 366 | // The below functions move their children to somewhere else. |
367 | if (con->type == C_OUTPUT) { | ||
368 | container_output_destroy(con); | ||
369 | } else if (con->type == C_WORKSPACE) { | ||
370 | // Workspaces will refuse to be destroyed if they're the last workspace | ||
371 | // on their output. | ||
372 | if (!container_workspace_destroy(con)) { | ||
373 | return NULL; | ||
374 | } | ||
375 | } | ||
358 | 376 | ||
359 | switch (con->type) { | 377 | // At this point the container being destroyed shouldn't have any children |
360 | case C_ROOT: | 378 | // unless sway is terminating. |
361 | container_root_finish(con); | 379 | if (!server.terminating) { |
362 | break; | 380 | if (!sway_assert(!con->children || con->children->length == 0, |
363 | case C_OUTPUT: | 381 | "Didn't expect to see children here")) { |
364 | // dont try to reap the root after this | 382 | return NULL; |
365 | container_output_destroy(con); | 383 | } |
366 | break; | ||
367 | case C_WORKSPACE: | ||
368 | // dont try to reap the output after this | ||
369 | container_workspace_destroy(con); | ||
370 | break; | ||
371 | case C_CONTAINER: | ||
372 | if (con->children->length) { | ||
373 | for (int i = 0; i < con->children->length; ++i) { | ||
374 | struct sway_container *child = con->children->items[0]; | ||
375 | ipc_event_window(child, "close"); | ||
376 | container_remove_child(child); | ||
377 | container_add_child(parent, child); | ||
378 | } | ||
379 | } | ||
380 | ipc_event_window(con, "close"); | ||
381 | _container_destroy(con); | ||
382 | break; | ||
383 | case C_VIEW: | ||
384 | _container_destroy(con); | ||
385 | break; | ||
386 | case C_TYPES: | ||
387 | wlr_log(L_ERROR, "container_destroy called on an invalid " | ||
388 | "container"); | ||
389 | break; | ||
390 | } | 384 | } |
391 | 385 | ||
386 | wl_signal_emit(&con->events.destroy, con); | ||
387 | ipc_event_window(con, "close"); | ||
388 | |||
389 | struct sway_container *parent = container_remove_child(con); | ||
390 | |||
391 | con->destroying = true; | ||
392 | list_add(server.destroying_containers, con); | ||
393 | |||
392 | return container_reap_empty_recursive(parent); | 394 | return container_reap_empty_recursive(parent); |
393 | } | 395 | } |
394 | 396 | ||