diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 77c2278d7..fdc34d128 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -113,6 +113,12 @@ struct sway_seat { // sway_keyboard_shortcuts_inhibitor::link 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 { diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 057611508..1f4c5414c 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -113,6 +113,12 @@ struct sway_container { // Hidden scratchpad containers have a NULL parent. 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; struct wlr_texture *title_focused; diff --git a/sway/desktop/render.c b/sway/desktop/render.c index c088c936d..43069ea71 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -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, pixman_region32_t *damage) { + list_t *floating = create_list(); + for (int i = 0; i < root->outputs->length; ++i) { struct sway_output *output = root->outputs->items[i]; 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) { 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, diff --git a/sway/input/seat.c b/sway/input/seat.c index ce933b661..817971dc7 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -565,6 +565,8 @@ struct sway_seat *seat_create(const char *seat_name) { } seat->wlr_seat->data = seat; + seat->floating_counter = 0; + seat->cursor = sway_cursor_create(seat); if (!seat->cursor) { wlr_seat_destroy(seat->wlr_seat); diff --git a/sway/tree/container.c b/sway/tree/container.c index 79e04ec01..9240be5c5 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -289,31 +289,49 @@ static struct sway_container *container_at_linear(struct sway_node *parent, 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, struct wlr_surface **surface, double *sx, double *sy) { - // For outputs with floating containers that overhang the output bounds, - // 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 = root->outputs->length - 1; i >= 0; --i) { + list_t *floating = create_list(); + + for (int i = 0; i < root->outputs->length; ++i) { struct sway_output *output = root->outputs->items[i]; for (int j = 0; j < output->workspaces->length; ++j) { struct sway_workspace *ws = output->workspaces->items[j]; if (!workspace_is_visible(ws)) { continue; } - // Items at the end of the list are on top, so iterate the list in - // reverse. - for (int k = ws->floating->length - 1; k >= 0; --k) { + for (int k = 0; k < ws->floating->length; ++k) { struct sway_container *floater = ws->floating->items[k]; - struct sway_container *container = - tiling_container_at(&floater->node, lx, ly, surface, sx, sy); - if (container) { - return container; - } + list_add(floating, floater); } } } - 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, @@ -837,6 +855,7 @@ void container_set_floating(struct sway_container *container, bool enable) { if (enable) { struct sway_container *old_parent = container->pending.parent; container_detach(container); + container->floating_order = ++seat->floating_counter; workspace_add_floating(workspace, container); if (container->view) { 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) { + struct sway_seat *seat = input_manager_current_seat(); // Bring container to front by putting it at the end of the floating list. struct sway_container *floater = container_toplevel_ancestor(con); 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); } } diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index c84320bda..11f234532 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -813,6 +813,8 @@ void workspace_add_floating(struct sway_workspace *workspace, if (con->pending.workspace) { container_detach(con); } + struct sway_seat *seat = input_manager_current_seat(); + con->floating_order = ++seat->floating_counter; list_add(workspace->floating, con); con->pending.workspace = workspace; container_for_each_child(con, set_workspace, NULL);