diff --git a/include/sway/commands.h b/include/sway/commands.h index 64f707f4..f7fafb96 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -125,6 +125,7 @@ sway_cmd cmd_floating_modifier; sway_cmd cmd_floating_scroll; sway_cmd cmd_focus; sway_cmd cmd_focus_follows_mouse; +sway_cmd cmd_raise_floating; sway_cmd cmd_focus_on_window_activation; sway_cmd cmd_focus_wrapping; sway_cmd cmd_font; diff --git a/include/sway/config.h b/include/sway/config.h index 98a18b76..02ace979 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -359,6 +359,7 @@ struct sway_config { // Flags bool focus_follows_mouse; + bool raise_floating; bool mouse_warping; enum focus_wrapping_mode focus_wrapping; bool active; diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index 7ec45120..4d47ab42 100644 --- a/include/sway/input/cursor.h +++ b/include/sway/input/cursor.h @@ -10,6 +10,7 @@ struct sway_cursor { struct wlr_cursor *cursor; struct { double x, y; + struct sway_node *node; } previous; struct wlr_xcursor_manager *xcursor_manager; diff --git a/sway/commands.c b/sway/commands.c index 72db8ab9..5dd27f7e 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -107,6 +107,7 @@ static struct cmd_handler handlers[] = { { "new_window", cmd_default_border }, { "no_focus", cmd_no_focus }, { "output", cmd_output }, + { "raise_floating", cmd_raise_floating }, { "seat", cmd_seat }, { "set", cmd_set }, { "show_marks", cmd_show_marks }, diff --git a/sway/commands/raise_floating.c b/sway/commands/raise_floating.c new file mode 100644 index 00000000..930299a1 --- /dev/null +++ b/sway/commands/raise_floating.c @@ -0,0 +1,14 @@ +#include +#include +#include "sway/commands.h" +#include "util.h" + +struct cmd_results *cmd_raise_floating(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "raise_floating", EXPECTED_EQUAL_TO, 1))) { + return error; + } + config->raise_floating = + parse_boolean(argv[0], config->raise_floating); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/config.c b/sway/config.c index 048b57de..b56c4f71 100644 --- a/sway/config.c +++ b/sway/config.c @@ -221,6 +221,7 @@ static void config_defaults(struct sway_config *config) { // Flags config->focus_follows_mouse = true; + config->raise_floating = true; config->mouse_warping = true; config->focus_wrapping = WRAP_YES; config->validating = false; diff --git a/sway/input/cursor.c b/sway/input/cursor.c index afad6f6f..3c62acb9 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -567,15 +567,15 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, struct wlr_surface *surface = NULL; double sx, sy; - // Find the node beneath the pointer's previous position - struct sway_node *prev_node = node_at_coords(seat, - cursor->previous.x, cursor->previous.y, &surface, &sx, &sy); + struct sway_node *prev_node = cursor->previous.node; + struct sway_node *node = node_at_coords(seat, + cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); + // Update the stored previous position cursor->previous.x = cursor->cursor->x; cursor->previous.y = cursor->cursor->y; + cursor->previous.node = node; - struct sway_node *node = node_at_coords(seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); if (node && config->focus_follows_mouse && allow_refocusing) { struct sway_node *focus = seat_get_focus(seat); if (focus && node->type == N_WORKSPACE) { diff --git a/sway/input/seat.c b/sway/input/seat.c index 69bee47e..15c56a43 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -606,6 +606,18 @@ static int handle_urgent_timeout(void *data) { return 0; } +static void container_raise_floating(struct sway_container *con) { + // Bring container to front by putting it at the end of the floating list. + struct sway_container *floater = con; + while (floater->parent) { + floater = floater->parent; + } + if (container_is_floating(floater)) { + list_move_to_end(floater->workspace->floating, floater); + node_set_dirty(&floater->workspace->node); + } +} + void seat_set_focus_warp(struct sway_seat *seat, struct sway_node *node, bool warp, bool notify) { if (seat->focused_layer) { @@ -733,16 +745,8 @@ void seat_set_focus_warp(struct sway_seat *seat, struct sway_node *node, } // If we've focused a floating container, bring it to the front. - // We do this by putting it at the end of the floating list. - if (container) { - struct sway_container *floater = container; - while (floater->parent) { - floater = floater->parent; - } - if (container_is_floating(floater)) { - list_move_to_end(floater->workspace->floating, floater); - node_set_dirty(&floater->workspace->node); - } + if (container && config->raise_floating) { + container_raise_floating(container); } if (last_focus) { @@ -1017,6 +1021,11 @@ void seat_begin_down(struct sway_seat *seat, struct sway_container *con, seat->op_ref_con_lx = sx; seat->op_ref_con_ly = sy; seat->op_moved = false; + + // In case the container was not raised by gaining focus, raise on click + if (con && !config->raise_floating) { + container_raise_floating(con); + } } void seat_begin_move_floating(struct sway_seat *seat, diff --git a/sway/meson.build b/sway/meson.build index 00ebcb40..8ab28869 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -48,6 +48,7 @@ sway_sources = files( 'commands/floating_modifier.c', 'commands/focus.c', 'commands/focus_follows_mouse.c', + 'commands/raise_floating.c', 'commands/focus_on_window_activation.c', 'commands/focus_wrapping.c', 'commands/font.c', diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 3202d517..3fda6cef 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -441,6 +441,11 @@ The default colors are: devices. A list of input device names may be obtained via *swaymsg -t get\_inputs*. +*raise\_floating* yes|no + Controls the behaviour of floating windows. A _yes_ (the default) will + raise windows on gaining focus. A _no_ will only raise floating windows + by clicking anywhere in the window. + *seat* For details on seat subcommands, see *sway-input*(5). diff --git a/sway/tree/container.c b/sway/tree/container.c index a069b177..9db7aed1 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -151,10 +151,10 @@ struct sway_container *container_find_child(struct sway_container *container, return NULL; } -static void surface_at_view(struct sway_container *con, double lx, double ly, +static struct sway_container *surface_at_view(struct sway_container *con, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { if (!sway_assert(con->view, "Expected a view")) { - return; + return NULL; } struct sway_view *view = con->view; double view_sx = lx - view->x + view->geometry.x; @@ -184,7 +184,9 @@ static void surface_at_view(struct sway_container *con, double lx, double ly, *sx = _sx; *sy = _sy; *surface = _surface; + return con; } + return NULL; } /** @@ -355,37 +357,31 @@ struct sway_container *container_at(struct sway_workspace *workspace, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { struct sway_container *c; + // Focused view's popups struct sway_seat *seat = input_manager_current_seat(input_manager); struct sway_container *focus = seat_get_focused_container(seat); bool is_floating = focus && container_is_floating_or_child(focus); // Focused view's popups if (focus && focus->view) { - surface_at_view(focus, lx, ly, surface, sx, sy); - if (*surface && surface_is_popup(*surface)) { - return focus; + c = surface_at_view(focus, lx, ly, surface, sx, sy); + if (c && surface_is_popup(*surface)) { + return c; } *surface = NULL; } - // If focused is floating, focused view's non-popups - if (focus && focus->view && is_floating) { - surface_at_view(focus, lx, ly, surface, sx, sy); - if (*surface) { - return focus; + // Cast a ray to handle floating windows + for (int i = workspace->floating->length - 1; i >= 0; --i) { + struct sway_container *cn = workspace->floating->items[i]; + if (cn->view && (c = surface_at_view(cn, lx, ly, surface, sx, sy))) { + return c; } - *surface = NULL; - } - // Floating (non-focused) - if ((c = floating_container_at(lx, ly, surface, sx, sy))) { - return c; } // If focused is tiling, focused view's non-popups if (focus && focus->view && !is_floating) { - surface_at_view(focus, lx, ly, surface, sx, sy); - if (*surface) { - return focus; + if ((c = surface_at_view(focus, lx, ly, surface, sx, sy))) { + return c; } - *surface = NULL; } // Tiling (non-focused) if ((c = tiling_container_at(&workspace->node, lx, ly, surface, sx, sy))) {