From 59c94887018bdfa578c4371c4275061ca6e71b3e Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 3 Jun 2018 16:35:06 +1000 Subject: WIP: Atomic layout updates ground work --- sway/tree/container.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'sway/tree/container.c') diff --git a/sway/tree/container.c b/sway/tree/container.c index cd2c083c..e6956f5c 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -116,6 +116,7 @@ struct sway_container *container_create(enum sway_container_type type) { if (type != C_VIEW) { c->children = create_list(); + //c->pending.children = create_list(); } wl_signal_init(&c->events.destroy); @@ -162,6 +163,7 @@ static void _container_destroy(struct sway_container *cont) { wlr_texture_destroy(cont->title_urgent); list_free(cont->children); + //list_free(cont->pending.children); cont->children = NULL; free(cont); } @@ -971,3 +973,12 @@ bool container_is_floating(struct sway_container *container) { } return container->parent == workspace->sway_workspace->floating; } + +struct wlr_box *container_get_box(struct sway_container *container) { + struct wlr_box *box = calloc(1, sizeof(struct wlr_box)); + box->x = container->x; + box->y = container->y; + box->width = container->width; + box->height = container->height; + return box; +} -- cgit v1.2.3 From bb66e6d578fdc68fb33d0fde921390d74f20bb31 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Wed, 6 Jun 2018 22:57:34 +1000 Subject: Refactor everything that needs to arrange windows * The arrange_foo functions are now replaced with arrange_and_commit, or with manually created transactions and arrange_windows x2. * The arrange functions are now only called from the highest level functions rather than from both high level and low level functions. * Due to the previous point, view_set_fullscreen_raw and view_set_fullscreen are both merged into one function again. * Floating and fullscreen are now working with transactions. --- sway/tree/container.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sway/tree/container.c') diff --git a/sway/tree/container.c b/sway/tree/container.c index e6956f5c..d312eb60 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -204,6 +204,7 @@ static struct sway_container *container_workspace_destroy( container_move_to(floating->children->items[i], new_workspace->sway_workspace->floating); } + arrange_and_commit(new_workspace); } struct sway_workspace *sway_workspace = workspace->sway_workspace; @@ -264,10 +265,10 @@ static struct sway_container *container_output_destroy( } container_sort_workspaces(new_output); - arrange_output(new_output); } } } + arrange_and_commit(&root_container); wl_list_remove(&output->sway_output->mode.link); wl_list_remove(&output->sway_output->transform.link); @@ -924,13 +925,12 @@ void container_set_floating(struct sway_container *container, bool enable) { struct sway_container *workspace = container_parent(container, C_WORKSPACE); struct sway_seat *seat = input_manager_current_seat(input_manager); - container_damage_whole(container); if (enable) { container_remove_child(container); container_add_child(workspace->sway_workspace->floating, container); if (container->type == C_VIEW) { - view_autoconfigure(container->sway_view); + view_init_floating(container->sway_view); } seat_set_focus(seat, seat_get_focus_inactive(seat, container)); container_reap_empty_recursive(workspace); @@ -943,8 +943,8 @@ void container_set_floating(struct sway_container *container, bool enable) { container->is_sticky = false; container_reap_empty_recursive(workspace->sway_workspace->floating); } - arrange_workspace(workspace); - container_damage_whole(container); + + ipc_event_window(container, "floating"); } void container_set_geometry_from_floating_view(struct sway_container *con) { -- cgit v1.2.3 From 1c89f32533534f6e78c81c95578f40df45bb9016 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Mon, 18 Jun 2018 20:42:12 +1000 Subject: Preserve buffers during transactions * Also fix parts of the rendering where it was rendering the pending state instead of current. --- sway/tree/container.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sway/tree/container.c') diff --git a/sway/tree/container.c b/sway/tree/container.c index f8620b72..b071f394 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -766,9 +766,6 @@ static void update_title_texture(struct sway_container *con, "Unexpected type %s", container_type_to_str(con->type))) { return; } - if (!con->width) { - return; - } struct sway_container *output = container_parent(con, C_OUTPUT); if (!output) { return; -- cgit v1.2.3 From 38398e2d77d57dc06b67ec88a54091c897915602 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sat, 23 Jun 2018 16:24:11 +1000 Subject: Implement atomic layout updates for tree operations This implements atomic layout updates for when views map, reparent or unmap. --- sway/tree/container.c | 184 +++++++++++++++++++++++++------------------------- 1 file changed, 93 insertions(+), 91 deletions(-) (limited to 'sway/tree/container.c') 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 @@ #include "sway/ipc-server.h" #include "sway/output.h" #include "sway/server.h" -#include "sway/tree/arrange.h" #include "sway/tree/layout.h" #include "sway/tree/view.h" #include "sway/tree/workspace.h" @@ -113,10 +112,11 @@ struct sway_container *container_create(enum sway_container_type type) { c->layout = L_NONE; c->type = type; c->alpha = 1.0f; + c->instructions = create_list(); if (type != C_VIEW) { c->children = create_list(); - //c->pending.children = create_list(); + c->current.children = create_list(); } wl_signal_init(&c->events.destroy); @@ -133,43 +133,68 @@ struct sway_container *container_create(enum sway_container_type type) { return c; } -static void _container_destroy(struct sway_container *cont) { - if (cont == NULL) { - return; - } - - wl_signal_emit(&cont->events.destroy, cont); +static void container_workspace_free(struct sway_workspace *ws) { + list_foreach(ws->output_priority, free); + list_free(ws->output_priority); + ws->floating->destroying = true; + container_free(ws->floating); + free(ws); +} - struct sway_container *parent = cont->parent; - if (cont->children != NULL && cont->children->length) { - // remove children until there are no more, container_destroy calls - // container_remove_child, which removes child from this container - while (cont->children != NULL && cont->children->length > 0) { - struct sway_container *child = cont->children->items[0]; - ipc_event_window(child, "close"); - container_remove_child(child); - _container_destroy(child); - } - } - if (cont->marks) { - list_foreach(cont->marks, free); - list_free(cont->marks); - } - if (parent) { - parent = container_remove_child(cont); +void container_free(struct sway_container *cont) { + if (!sway_assert(cont->destroying, + "Tried to free container which wasn't marked as destroying")) { + return; } - if (cont->name) { - free(cont->name); + if (!sway_assert(cont->instructions->length == 0, + "Tried to free container with pending instructions")) { + return; } - + free(cont->name); wlr_texture_destroy(cont->title_focused); wlr_texture_destroy(cont->title_focused_inactive); wlr_texture_destroy(cont->title_unfocused); wlr_texture_destroy(cont->title_urgent); + for (int i = 0; i < server.destroying_containers->length; ++i) { + if (server.destroying_containers->items[i] == cont) { + list_del(server.destroying_containers, i); + break; + } + } + + list_free(cont->instructions); list_free(cont->children); - //list_free(cont->pending.children); - cont->children = NULL; + list_free(cont->current.children); + + switch (cont->type) { + case C_ROOT: + break; + case C_OUTPUT: + cont->sway_output->swayc = NULL; + break; + case C_WORKSPACE: + container_workspace_free(cont->sway_workspace); + break; + case C_CONTAINER: + break; + case C_VIEW: + { + struct sway_view *view = cont->sway_view; + view->swayc = NULL; + free(view->title_format); + view->title_format = NULL; + + if (view->destroying) { + view_free(view); + } + } + break; + case C_TYPES: + sway_assert(false, "Didn't expect to see C_TYPES here"); + break; + } + free(cont); } @@ -186,7 +211,6 @@ static struct sway_container *container_workspace_destroy( } wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name); - ipc_event_window(workspace, "close"); struct sway_container *parent = workspace->parent; if (!workspace_is_empty(workspace) && output) { @@ -209,25 +233,6 @@ static struct sway_container *container_workspace_destroy( container_move_to(floating->children->items[i], new_workspace->sway_workspace->floating); } - arrange_and_commit(new_workspace); - } - - struct sway_workspace *sway_workspace = workspace->sway_workspace; - - // This emits the destroy event and also destroys the swayc. - _container_destroy(workspace); - - // Clean up the floating container - sway_workspace->floating->parent = NULL; - _container_destroy(sway_workspace->floating); - - list_foreach(sway_workspace->output_priority, free); - list_free(sway_workspace->output_priority); - - free(sway_workspace); - - if (output) { - output_damage_whole(output->sway_output); } return parent; @@ -266,14 +271,13 @@ static struct sway_container *container_output_destroy( container_add_child(new_output, workspace); ipc_event_workspace(workspace, NULL, "move"); } else { - container_workspace_destroy(workspace); + container_destroy(workspace); } container_sort_workspaces(new_output); } } } - arrange_and_commit(&root_container); wl_list_remove(&output->sway_output->mode.link); wl_list_remove(&output->sway_output->transform.link); @@ -285,12 +289,8 @@ static struct sway_container *container_output_destroy( output->sway_output->swayc = NULL; wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); - _container_destroy(output); - return &root_container; -} -static void container_root_finish(struct sway_container *con) { - wlr_log(L_ERROR, "TODO: destroy the root container"); + return &root_container; } bool container_reap_empty(struct sway_container *con) { @@ -306,13 +306,13 @@ bool container_reap_empty(struct sway_container *con) { case C_WORKSPACE: if (!workspace_is_visible(con) && workspace_is_empty(con)) { wlr_log(L_DEBUG, "Destroying workspace via reaper"); - container_workspace_destroy(con); + container_destroy(con); return true; } break; case C_CONTAINER: if (con->children->length == 0) { - _container_destroy(con); + container_destroy(con); return true; } case C_VIEW: @@ -349,46 +349,48 @@ struct sway_container *container_flatten(struct sway_container *container) { return container; } +/** + * container_destroy() is the first step in destroying a container. We'll emit + * events, detach it from the tree and mark it as destroying. The container will + * remain in memory until it's no longer used by a transaction, then it will be + * freed via container_free(). + */ struct sway_container *container_destroy(struct sway_container *con) { if (con == NULL) { return NULL; } + if (con->destroying) { + return NULL; + } - struct sway_container *parent = con->parent; + // The below functions move their children to somewhere else. + if (con->type == C_OUTPUT) { + container_output_destroy(con); + } else if (con->type == C_WORKSPACE) { + // Workspaces will refuse to be destroyed if they're the last workspace + // on their output. + if (!container_workspace_destroy(con)) { + return NULL; + } + } - switch (con->type) { - case C_ROOT: - container_root_finish(con); - break; - case C_OUTPUT: - // dont try to reap the root after this - container_output_destroy(con); - break; - case C_WORKSPACE: - // dont try to reap the output after this - container_workspace_destroy(con); - break; - case C_CONTAINER: - if (con->children->length) { - for (int i = 0; i < con->children->length; ++i) { - struct sway_container *child = con->children->items[0]; - ipc_event_window(child, "close"); - container_remove_child(child); - container_add_child(parent, child); - } - } - ipc_event_window(con, "close"); - _container_destroy(con); - break; - case C_VIEW: - _container_destroy(con); - break; - case C_TYPES: - wlr_log(L_ERROR, "container_destroy called on an invalid " - "container"); - break; + // At this point the container being destroyed shouldn't have any children + // unless sway is terminating. + if (!server.terminating) { + if (!sway_assert(!con->children || con->children->length == 0, + "Didn't expect to see children here")) { + return NULL; + } } + wl_signal_emit(&con->events.destroy, con); + ipc_event_window(con, "close"); + + struct sway_container *parent = container_remove_child(con); + + con->destroying = true; + list_add(server.destroying_containers, con); + return container_reap_empty_recursive(parent); } -- cgit v1.2.3 From b864ac0149212adf753824366e20badfa971b29f Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 24 Jun 2018 15:50:53 +1000 Subject: Fix crash when unmapping a view with reapable parents container_destroy was calling container_reap_empty, which calls container_destroy and so on. Eventually the original container_destroy would return a NULL pointer to the caller which caused a crash. This also fixes an arrange on the wrong container when moving views in and out of stacks. --- sway/tree/container.c | 82 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 34 deletions(-) (limited to 'sway/tree/container.c') diff --git a/sway/tree/container.c b/sway/tree/container.c index 484d26a5..075c508c 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -293,6 +293,47 @@ static struct sway_container *container_output_destroy( return &root_container; } +/** + * Implement the actual destroy logic, without reaping. + */ +struct sway_container *container_destroy_noreaping(struct sway_container *con) { + if (con == NULL) { + return NULL; + } + if (con->destroying) { + return NULL; + } + + // The below functions move their children to somewhere else. + if (con->type == C_OUTPUT) { + container_output_destroy(con); + } else if (con->type == C_WORKSPACE) { + // Workspaces will refuse to be destroyed if they're the last workspace + // on their output. + if (!container_workspace_destroy(con)) { + wlr_log(L_ERROR, "workspace doesn't want to destroy"); + return NULL; + } + } + + // At this point the container being destroyed shouldn't have any children + // unless sway is terminating. + if (!server.terminating) { + if (!sway_assert(!con->children || con->children->length == 0, + "Didn't expect to see children here")) { + return NULL; + } + } + + wl_signal_emit(&con->events.destroy, con); + ipc_event_window(con, "close"); + + con->destroying = true; + list_add(server.destroying_containers, con); + + return container_remove_child(con); +} + bool container_reap_empty(struct sway_container *con) { if (con->layout == L_FLOATING) { // Don't reap the magical floating container that each workspace has @@ -306,13 +347,13 @@ bool container_reap_empty(struct sway_container *con) { case C_WORKSPACE: if (!workspace_is_visible(con) && workspace_is_empty(con)) { wlr_log(L_DEBUG, "Destroying workspace via reaper"); - container_destroy(con); + container_destroy_noreaping(con); return true; } break; case C_CONTAINER: if (con->children->length == 0) { - container_destroy(con); + container_destroy_noreaping(con); return true; } case C_VIEW: @@ -354,43 +395,16 @@ struct sway_container *container_flatten(struct sway_container *container) { * events, detach it from the tree and mark it as destroying. The container will * remain in memory until it's no longer used by a transaction, then it will be * freed via container_free(). + * + * This function just wraps container_destroy_noreaping(), then does reaping. */ struct sway_container *container_destroy(struct sway_container *con) { - if (con == NULL) { - return NULL; - } - if (con->destroying) { - return NULL; - } - - // The below functions move their children to somewhere else. - if (con->type == C_OUTPUT) { - container_output_destroy(con); - } else if (con->type == C_WORKSPACE) { - // Workspaces will refuse to be destroyed if they're the last workspace - // on their output. - if (!container_workspace_destroy(con)) { - return NULL; - } - } + struct sway_container *parent = container_destroy_noreaping(con); - // At this point the container being destroyed shouldn't have any children - // unless sway is terminating. - if (!server.terminating) { - if (!sway_assert(!con->children || con->children->length == 0, - "Didn't expect to see children here")) { - return NULL; - } + if (!parent) { + return NULL; } - wl_signal_emit(&con->events.destroy, con); - ipc_event_window(con, "close"); - - struct sway_container *parent = container_remove_child(con); - - con->destroying = true; - list_add(server.destroying_containers, con); - return container_reap_empty_recursive(parent); } -- cgit v1.2.3 From a3976e2659ec3a90ba606ca5a93cfa8e78c410e1 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 24 Jun 2018 23:07:52 +1000 Subject: Fix another crash when moving out of stacks or tabs --- sway/tree/container.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'sway/tree/container.c') diff --git a/sway/tree/container.c b/sway/tree/container.c index 075c508c..e30c7839 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -331,6 +331,10 @@ struct sway_container *container_destroy_noreaping(struct sway_container *con) { con->destroying = true; list_add(server.destroying_containers, con); + if (!con->parent) { + return NULL; + } + return container_remove_child(con); } @@ -384,7 +388,7 @@ struct sway_container *container_flatten(struct sway_container *container) { struct sway_container *child = container->children->items[0]; struct sway_container *parent = container->parent; container_replace_child(container, child); - container_destroy(container); + container_destroy_noreaping(container); container = parent; } return container; -- cgit v1.2.3 From 834805f5e260bcc77d714323d4a7f4bfd1dbfb17 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 26 Jun 2018 19:40:42 +1000 Subject: Fix crash when disconnecting output We were freeing the sway_output immediately upon disconnect which left a dangling pointer in the output's container. It then tried to use the pointer when the container is freed. We don't need to store the sway_output in an output's container which is destroying, so the fix is to set the pointer to NULL and remove the use in container_free. Also added an arrange when the output is disconnected for good measure. --- sway/tree/container.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sway/tree/container.c') diff --git a/sway/tree/container.c b/sway/tree/container.c index e30c7839..2f041a36 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -171,7 +171,6 @@ void container_free(struct sway_container *cont) { case C_ROOT: break; case C_OUTPUT: - cont->sway_output->swayc = NULL; break; case C_WORKSPACE: container_workspace_free(cont->sway_workspace); @@ -287,6 +286,7 @@ static struct sway_container *container_output_destroy( wl_list_remove(&output->sway_output->damage_frame.link); output->sway_output->swayc = NULL; + output->sway_output = NULL; wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); -- cgit v1.2.3 From 93696b78ecbc31ec34be97ec26836efb74d359f0 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 26 Jun 2018 20:14:58 +1000 Subject: Fix crash when closing output window from outer session Emitting the close event needs to happen before container_output_destroy, because container_output_destroy sets the sway_output to NULL and sway_output is used in IPC. --- sway/tree/container.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sway/tree/container.c') diff --git a/sway/tree/container.c b/sway/tree/container.c index 2f041a36..0c860405 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -304,6 +304,9 @@ struct sway_container *container_destroy_noreaping(struct sway_container *con) { return NULL; } + wl_signal_emit(&con->events.destroy, con); + ipc_event_window(con, "close"); + // The below functions move their children to somewhere else. if (con->type == C_OUTPUT) { container_output_destroy(con); @@ -325,9 +328,6 @@ struct sway_container *container_destroy_noreaping(struct sway_container *con) { } } - wl_signal_emit(&con->events.destroy, con); - ipc_event_window(con, "close"); - con->destroying = true; list_add(server.destroying_containers, con); -- cgit v1.2.3 From a7b3f29292cad029f010aa8b5fafb56b08ba4ed7 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 26 Jun 2018 20:18:57 +1000 Subject: Remove incorrect assertion and supporting code Children can exist when destroying a container, such as when destroying the last output. Sway is not terminating in that case. --- sway/tree/container.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'sway/tree/container.c') diff --git a/sway/tree/container.c b/sway/tree/container.c index 0c860405..2b9eb636 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -319,15 +319,6 @@ struct sway_container *container_destroy_noreaping(struct sway_container *con) { } } - // At this point the container being destroyed shouldn't have any children - // unless sway is terminating. - if (!server.terminating) { - if (!sway_assert(!con->children || con->children->length == 0, - "Didn't expect to see children here")) { - return NULL; - } - } - con->destroying = true; list_add(server.destroying_containers, con); -- cgit v1.2.3 From 61c118768564eec07ac16494d90f567e75ea60cf Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Wed, 27 Jun 2018 17:23:44 +1000 Subject: Fix nitpicks --- sway/tree/container.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sway/tree/container.c') diff --git a/sway/tree/container.c b/sway/tree/container.c index 2b9eb636..8446c457 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -296,7 +296,8 @@ static struct sway_container *container_output_destroy( /** * Implement the actual destroy logic, without reaping. */ -struct sway_container *container_destroy_noreaping(struct sway_container *con) { +static struct sway_container *container_destroy_noreaping( + struct sway_container *con) { if (con == NULL) { return NULL; } -- cgit v1.2.3 From 8773ed39701748ba5500b4698d028795aa6e812e Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Wed, 27 Jun 2018 17:47:41 +1000 Subject: Fix memleak in container_get_box Rather than allocate a structure and expect callers to free it, take a pointer to an existing struct as an argument. This function is no longer called anywhere though. --- sway/tree/container.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sway/tree/container.c') diff --git a/sway/tree/container.c b/sway/tree/container.c index 8446c457..ab3d9dbd 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -988,11 +988,9 @@ bool container_is_floating(struct sway_container *container) { return container->parent == workspace->sway_workspace->floating; } -struct wlr_box *container_get_box(struct sway_container *container) { - struct wlr_box *box = calloc(1, sizeof(struct wlr_box)); +void container_get_box(struct sway_container *container, struct wlr_box *box) { box->x = container->x; box->y = container->y; box->width = container->width; box->height = container->height; - return box; } -- cgit v1.2.3