mirror of
https://github.com/swaywm/sway.git
synced 2025-11-06 13:29:50 -05:00
Implement atomic layout updates for tree operations
This implements atomic layout updates for when views map, reparent or unmap.
This commit is contained in:
parent
1c89f32533
commit
38398e2d77
18 changed files with 545 additions and 389 deletions
|
|
@ -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) {
|
||||
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);
|
||||
}
|
||||
|
||||
void container_free(struct sway_container *cont) {
|
||||
if (!sway_assert(cont->destroying,
|
||||
"Tried to free container which wasn't marked as destroying")) {
|
||||
return;
|
||||
}
|
||||
|
||||
wl_signal_emit(&cont->events.destroy, cont);
|
||||
|
||||
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 (!sway_assert(cont->instructions->length == 0,
|
||||
"Tried to free container with pending instructions")) {
|
||||
return;
|
||||
}
|
||||
if (cont->marks) {
|
||||
list_foreach(cont->marks, free);
|
||||
list_free(cont->marks);
|
||||
}
|
||||
if (parent) {
|
||||
parent = container_remove_child(cont);
|
||||
}
|
||||
if (cont->name) {
|
||||
free(cont->name);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
struct sway_container *parent = con->parent;
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue