aboutsummaryrefslogtreecommitdiffstats
path: root/sway/tree/container.c
diff options
context:
space:
mode:
authorLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-06-23 16:24:11 +1000
committerLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-06-23 16:24:11 +1000
commit38398e2d77d57dc06b67ec88a54091c897915602 (patch)
treec80935807865fd96ab7d037070287d4dfaba1863 /sway/tree/container.c
parentPreserve buffers during transactions (diff)
downloadsway-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.c184
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
136static void _container_destroy(struct sway_container *cont) { 136static 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; 144void 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
292static 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
296bool container_reap_empty(struct sway_container *con) { 296bool 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 */
352struct sway_container *container_destroy(struct sway_container *con) { 358struct 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