Fix inconsistent floating window z order across outputs

This commit is contained in:
Alexander Orzechowski 2022-01-08 11:57:10 -05:00
parent f92329701b
commit 9239bd05ca
6 changed files with 73 additions and 15 deletions

View file

@ -113,6 +113,12 @@ struct sway_seat {
// sway_keyboard_shortcuts_inhibitor::link // sway_keyboard_shortcuts_inhibitor::link
struct wl_list link; // input_manager::seats struct wl_list link; // input_manager::seats
// Used by sway_container.floating_order. This value will increment as
// floating windows request to be shown on top, this makes sure that a
// value can be assigned to a floating window that is guaranteed
// to be highter (ignoring overflow) than other floating windows.
uint32_t floating_counter;
}; };
struct sway_pointer_constraint { struct sway_pointer_constraint {

View file

@ -113,6 +113,12 @@ struct sway_container {
// Hidden scratchpad containers have a NULL parent. // Hidden scratchpad containers have a NULL parent.
bool scratchpad; bool scratchpad;
// Value specifing in which order floating windows should be shown
// higher values means that the floating window should appear
// ontop of others. This variable is undefined if this container is not
// floating.
uint32_t floating_order;
float alpha; float alpha;
struct wlr_texture *title_focused; struct wlr_texture *title_focused;

View file

@ -996,8 +996,17 @@ static void render_floating_container(struct sway_output *soutput,
} }
} }
static int floating_order_compare (const void *a, const void *b) {
struct sway_container *a_container = *(struct sway_container **)a;
struct sway_container *b_container = *(struct sway_container **)b;
return a_container->floating_order - b_container->floating_order;
}
static void render_floating(struct sway_output *soutput, static void render_floating(struct sway_output *soutput,
pixman_region32_t *damage) { pixman_region32_t *damage) {
list_t *floating = create_list();
for (int i = 0; i < root->outputs->length; ++i) { for (int i = 0; i < root->outputs->length; ++i) {
struct sway_output *output = root->outputs->items[i]; struct sway_output *output = root->outputs->items[i];
for (int j = 0; j < output->current.workspaces->length; ++j) { for (int j = 0; j < output->current.workspaces->length; ++j) {
@ -1010,10 +1019,19 @@ static void render_floating(struct sway_output *soutput,
if (floater->current.fullscreen_mode != FULLSCREEN_NONE) { if (floater->current.fullscreen_mode != FULLSCREEN_NONE) {
continue; continue;
} }
render_floating_container(soutput, damage, floater); list_add(floating, floater);
} }
} }
} }
list_qsort(floating, floating_order_compare);
for (int i = 0; i < floating->length; ++i) {
struct sway_container *floater = floating->items[i];
render_floating_container(soutput, damage, floater);
}
list_free(floating);
} }
static void render_seatops(struct sway_output *output, static void render_seatops(struct sway_output *output,

View file

@ -565,6 +565,8 @@ struct sway_seat *seat_create(const char *seat_name) {
} }
seat->wlr_seat->data = seat; seat->wlr_seat->data = seat;
seat->floating_counter = 0;
seat->cursor = sway_cursor_create(seat); seat->cursor = sway_cursor_create(seat);
if (!seat->cursor) { if (!seat->cursor) {
wlr_seat_destroy(seat->wlr_seat); wlr_seat_destroy(seat->wlr_seat);

View file

@ -289,31 +289,49 @@ static struct sway_container *container_at_linear(struct sway_node *parent,
return NULL; return NULL;
} }
static int floating_order_compare (const void *a, const void *b) {
struct sway_container *a_container = *(struct sway_container **)a;
struct sway_container *b_container = *(struct sway_container **)b;
return a_container->floating_order - b_container->floating_order;
}
static struct sway_container *floating_container_at(double lx, double ly, static struct sway_container *floating_container_at(double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy) { struct wlr_surface **surface, double *sx, double *sy) {
// For outputs with floating containers that overhang the output bounds, list_t *floating = create_list();
// those at the end of the output list appear on top of floating
// containers from other outputs, so iterate the list in reverse. for (int i = 0; i < root->outputs->length; ++i) {
for (int i = root->outputs->length - 1; i >= 0; --i) {
struct sway_output *output = root->outputs->items[i]; struct sway_output *output = root->outputs->items[i];
for (int j = 0; j < output->workspaces->length; ++j) { for (int j = 0; j < output->workspaces->length; ++j) {
struct sway_workspace *ws = output->workspaces->items[j]; struct sway_workspace *ws = output->workspaces->items[j];
if (!workspace_is_visible(ws)) { if (!workspace_is_visible(ws)) {
continue; continue;
} }
// Items at the end of the list are on top, so iterate the list in for (int k = 0; k < ws->floating->length; ++k) {
// reverse.
for (int k = ws->floating->length - 1; k >= 0; --k) {
struct sway_container *floater = ws->floating->items[k]; struct sway_container *floater = ws->floating->items[k];
struct sway_container *container = list_add(floating, floater);
tiling_container_at(&floater->node, lx, ly, surface, sx, sy);
if (container) {
return container;
}
} }
} }
} }
return NULL;
list_qsort(floating, floating_order_compare);
struct sway_container *container = NULL;
// Items at the end of the list are on top, so iterate the list in
// reverse.
for (int i = floating->length - 1; i >= 0; --i) {
struct sway_container *floater = floating->items[i];
struct sway_container *current =
tiling_container_at(&floater->node, lx, ly, surface, sx, sy);
if (current) {
container = current;
break;
}
}
list_free(floating);
return container;
} }
static struct sway_container *view_container_content_at(struct sway_node *parent, static struct sway_container *view_container_content_at(struct sway_node *parent,
@ -837,6 +855,7 @@ void container_set_floating(struct sway_container *container, bool enable) {
if (enable) { if (enable) {
struct sway_container *old_parent = container->pending.parent; struct sway_container *old_parent = container->pending.parent;
container_detach(container); container_detach(container);
container->floating_order = ++seat->floating_counter;
workspace_add_floating(workspace, container); workspace_add_floating(workspace, container);
if (container->view) { if (container->view) {
view_set_tiled(container->view, false); view_set_tiled(container->view, false);
@ -1733,10 +1752,15 @@ void container_update_marks_textures(struct sway_container *con) {
} }
void container_raise_floating(struct sway_container *con) { void container_raise_floating(struct sway_container *con) {
struct sway_seat *seat = input_manager_current_seat();
// Bring container to front by putting it at the end of the floating list. // Bring container to front by putting it at the end of the floating list.
struct sway_container *floater = container_toplevel_ancestor(con); struct sway_container *floater = container_toplevel_ancestor(con);
if (container_is_floating(floater) && floater->pending.workspace) { if (container_is_floating(floater) && floater->pending.workspace) {
list_move_to_end(floater->pending.workspace->floating, floater); // Don't raise if already on top
if (floater->floating_order != seat->floating_counter) {
floater->floating_order = ++seat->floating_counter;
}
node_set_dirty(&floater->pending.workspace->node); node_set_dirty(&floater->pending.workspace->node);
} }
} }

View file

@ -813,6 +813,8 @@ void workspace_add_floating(struct sway_workspace *workspace,
if (con->pending.workspace) { if (con->pending.workspace) {
container_detach(con); container_detach(con);
} }
struct sway_seat *seat = input_manager_current_seat();
con->floating_order = ++seat->floating_counter;
list_add(workspace->floating, con); list_add(workspace->floating, con);
con->pending.workspace = workspace; con->pending.workspace = workspace;
container_for_each_child(con, set_workspace, NULL); container_for_each_child(con, set_workspace, NULL);