Fix issues with sticky containers and workspaces

* Attach sticky containers to new workspaces when switching
* Fire the close event *before* we start destroying the workspace to
prevent a crash

Because the sticky container now follows the visible workspace, this
simplifies the rendering and container_at logic.
This commit is contained in:
Ryan Dwyer 2018-05-25 15:39:14 +10:00
parent 13a4b0512e
commit dc83b158e1
3 changed files with 54 additions and 33 deletions

View File

@ -832,12 +832,13 @@ static void render_floating(struct sway_output *soutput,
for (int j = 0; j < output->children->length; ++j) { for (int j = 0; j < output->children->length; ++j) {
struct sway_container *workspace = output->children->items[j]; struct sway_container *workspace = output->children->items[j];
struct sway_workspace *ws = workspace->sway_workspace; struct sway_workspace *ws = workspace->sway_workspace;
bool ws_is_visible = workspace_is_visible(workspace); if (!workspace_is_visible(workspace)) {
continue;
}
for (int k = 0; k < ws->floating->children->length; ++k) { for (int k = 0; k < ws->floating->children->length; ++k) {
struct sway_container *floater = struct sway_container *floater =
ws->floating->children->items[k]; ws->floating->children->items[k];
if ((ws_is_visible || floater->is_sticky) if (floater_intersects_output(floater, soutput->swayc)) {
&& floater_intersects_output(floater, soutput->swayc)) {
render_floating_container(soutput, damage, floater); render_floating_container(soutput, damage, floater);
} }
} }

View File

@ -64,16 +64,6 @@ void container_create_notify(struct sway_container *container) {
} }
} }
static void container_close_notify(struct sway_container *container) {
if (container == NULL) {
return;
}
// TODO send ipc event type based on the container type
if (container->type == C_VIEW || container->type == C_WORKSPACE) {
ipc_event_window(container, "close");
}
}
static void container_update_textures_recursive(struct sway_container *con) { static void container_update_textures_recursive(struct sway_container *con) {
container_update_title_textures(con); container_update_title_textures(con);
@ -143,7 +133,6 @@ static void _container_destroy(struct sway_container *cont) {
} }
wl_signal_emit(&cont->events.destroy, cont); wl_signal_emit(&cont->events.destroy, cont);
container_close_notify(cont);
struct sway_container *parent = cont->parent; struct sway_container *parent = cont->parent;
if (cont->children != NULL && cont->children->length) { if (cont->children != NULL && cont->children->length) {
@ -151,6 +140,7 @@ static void _container_destroy(struct sway_container *cont) {
// container_remove_child, which removes child from this container // container_remove_child, which removes child from this container
while (cont->children != NULL && cont->children->length > 0) { while (cont->children != NULL && cont->children->length > 0) {
struct sway_container *child = cont->children->items[0]; struct sway_container *child = cont->children->items[0];
ipc_event_window(child, "close");
container_remove_child(child); container_remove_child(child);
_container_destroy(child); _container_destroy(child);
} }
@ -188,12 +178,11 @@ static struct sway_container *container_workspace_destroy(
return NULL; return NULL;
} }
wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name);
ipc_event_window(workspace, "close");
struct sway_container *parent = workspace->parent; struct sway_container *parent = workspace->parent;
if (workspace_is_empty(workspace)) { if (!workspace_is_empty(workspace) && output) {
// destroy the WS if there are no children
wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name);
ipc_event_workspace(workspace, NULL, "empty");
} else if (output) {
// Move children to a different workspace on this output // Move children to a different workspace on this output
struct sway_container *new_workspace = NULL; struct sway_container *new_workspace = NULL;
for (int i = 0; i < output->children->length; i++) { for (int i = 0; i < output->children->length; i++) {
@ -357,10 +346,12 @@ struct sway_container *container_destroy(struct sway_container *con) {
if (con->children->length) { if (con->children->length) {
for (int i = 0; i < con->children->length; ++i) { for (int i = 0; i < con->children->length; ++i) {
struct sway_container *child = con->children->items[0]; struct sway_container *child = con->children->items[0];
ipc_event_window(child, "close");
container_remove_child(child); container_remove_child(child);
container_add_child(parent, child); container_add_child(parent, child);
} }
} }
ipc_event_window(con, "close");
_container_destroy(con); _container_destroy(con);
break; break;
case C_VIEW: case C_VIEW:
@ -635,20 +626,20 @@ struct sway_container *floating_container_at(double lx, double ly,
for (int j = 0; j < output->children->length; ++j) { for (int j = 0; j < output->children->length; ++j) {
struct sway_container *workspace = output->children->items[j]; struct sway_container *workspace = output->children->items[j];
struct sway_workspace *ws = workspace->sway_workspace; struct sway_workspace *ws = workspace->sway_workspace;
bool ws_is_visible = workspace_is_visible(workspace); if (!workspace_is_visible(workspace)) {
continue;
}
for (int k = 0; k < ws->floating->children->length; ++k) { for (int k = 0; k < ws->floating->children->length; ++k) {
struct sway_container *floater = struct sway_container *floater =
ws->floating->children->items[k]; ws->floating->children->items[k];
if (ws_is_visible || floater->is_sticky) { struct wlr_box box = {
struct wlr_box box = { .x = floater->x,
.x = floater->x, .y = floater->y,
.y = floater->y, .width = floater->width,
.width = floater->width, .height = floater->height,
.height = floater->height, };
}; if (wlr_box_contains_point(&box, lx, ly)) {
if (wlr_box_contains_point(&box, lx, ly)) { return container_at(floater, lx, ly, surface, sx, sy);
return container_at(floater, lx, ly, surface, sx, sy);
}
} }
} }
} }

View File

@ -387,7 +387,21 @@ bool workspace_switch(struct sway_container *workspace) {
strcpy(prev_workspace_name, active_ws->name); strcpy(prev_workspace_name, active_ws->name);
} }
// TODO: Deal with sticky containers // Move sticky containers to new workspace
struct sway_container *next_output = workspace->parent;
struct sway_container *next_output_prev_ws =
seat_get_active_child(seat, next_output);
struct sway_container *floating =
next_output_prev_ws->sway_workspace->floating;
bool has_sticky = false;
for (int i = 0; i < floating->children->length; ++i) {
struct sway_container *floater = floating->children->items[i];
if (floater->is_sticky) {
has_sticky = true;
container_remove_child(floater);
container_add_child(workspace->sway_workspace->floating, floater);
}
}
wlr_log(L_DEBUG, "Switching to workspace %p:%s", wlr_log(L_DEBUG, "Switching to workspace %p:%s",
workspace, workspace->name); workspace, workspace->name);
@ -395,6 +409,16 @@ bool workspace_switch(struct sway_container *workspace) {
if (next == NULL) { if (next == NULL) {
next = workspace; next = workspace;
} }
if (has_sticky) {
// If there's a sticky container, we might be setting focus to the same
// container that's already focused, so seat_set_focus is effectively a
// no op. We therefore need to send the IPC event and clean up the old
// workspace here.
ipc_event_workspace(active_ws, workspace, "focus");
if (!workspace_is_visible(active_ws) && workspace_is_empty(active_ws)) {
container_destroy(active_ws);
}
}
seat_set_focus(seat, next); seat_set_focus(seat, next);
struct sway_container *output = container_parent(workspace, C_OUTPUT); struct sway_container *output = container_parent(workspace, C_OUTPUT);
arrange_output(output); arrange_output(output);
@ -418,8 +442,13 @@ bool workspace_is_empty(struct sway_container *ws) {
if (ws->children->length) { if (ws->children->length) {
return false; return false;
} }
if (ws->sway_workspace->floating->children->length) { // Sticky views are not considered to be part of this workspace
return false; struct sway_container *floating = ws->sway_workspace->floating;
for (int i = 0; i < floating->children->length; ++i) {
struct sway_container *floater = floating->children->items[i];
if (!floater->is_sticky) {
return false;
}
} }
return true; return true;
} }