From 24614bfeb3736f33e48ba7a14aba08fb843de639 Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Tue, 8 Oct 2024 18:53:53 +0200 Subject: [PATCH 1/2] feat: when clicking in gaps, redirect the input to the closest window --- include/sway/tree/container.h | 4 ++ sway/input/cursor.c | 6 +++ sway/tree/container.c | 81 +++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 42fb71bf0..436c40d1c 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -174,6 +174,10 @@ struct sway_container *tiling_container_at( struct sway_node *parent, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy); +struct sway_container *closest_tiling_container_at( + struct sway_node *parent, double lx, double ly, + struct wlr_surface **surface, double *sx, double *sy, double *distanceSquared); + void container_for_each_child(struct sway_container *container, void (*f)(struct sway_container *container, void *data), void *data); diff --git a/sway/input/cursor.c b/sway/input/cursor.c index fa9d5b331..aea7e3bad 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -241,6 +241,12 @@ struct sway_node *node_at_coords( return NULL; } + double distanceSquared; + struct sway_container *closest_container = closest_tiling_container_at(&ws->node, lx, ly, surface, sx, sy, &distanceSquared); + if(closest_container) { + return &closest_container->node; + } + return &ws->node; } diff --git a/sway/tree/container.c b/sway/tree/container.c index 2de58a267..18d88ae9f 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -438,6 +439,86 @@ struct sway_container *container_at(struct sway_workspace *workspace, return NULL; } + +static struct sway_container *closest_view_container_at(struct sway_node *parent, + double lx, double ly, + struct wlr_surface **surface, double *sx, double *sy, double *distanceSquared) { + if (!sway_assert(node_is_view(parent), "Expected a view")) { + return NULL; + } + + struct sway_container* container = parent->sway_container; + struct wlr_box box = { + .x = container->pending.content_x, + .y = container->pending.content_y, + .width = container->pending.content_width, + .height = container->pending.content_height, + }; + + double closest_x, closest_y; + wlr_box_closest_point(&box, lx, ly, &closest_x, &closest_y); + + double dx = fabs(closest_x - lx); + double dy = fabs(closest_y - ly); + *distanceSquared = dx * dx + dy * dy; + + if (surface_at_view(container, closest_x, closest_y, surface, sx, sy)) { + return container; + } + + return NULL; +} + +static struct sway_container *closest_container_at_linear(struct sway_node *parent, + double lx, double ly, + struct wlr_surface **surface, double *sx, double *sy, double *distanceSquared) { + list_t *children = node_get_children(parent); + + *distanceSquared = DBL_MAX; + struct sway_container *closestContainer = NULL; + + for (int i = 0; i < children->length; ++i) { + struct sway_container *child = children->items[i]; + + double containerDistance, containerSx, containerSy; + struct wlr_surface *containerSurface = NULL; + struct sway_container *container = closest_tiling_container_at(&child->node, lx, ly, &containerSurface, &containerSx, &containerSy, &containerDistance); + if (container && containerDistance < *distanceSquared) { + *distanceSquared = containerDistance; + *sx = containerSx; + *sy = containerSy; + *surface = containerSurface; + closestContainer = container; + } + } + + return closestContainer; +} + +struct sway_container *closest_tiling_container_at(struct sway_node *parent, + double lx, double ly, + struct wlr_surface **surface, double *sx, double *sy, double *distanceSquared) { + if (node_is_view(parent)) { + return closest_view_container_at(parent, lx, ly, surface, sx, sy, distanceSquared); + } + if (!node_get_children(parent)) { + return NULL; + } + + switch (node_get_layout(parent)) { + case L_HORIZ: + case L_VERT: + return closest_container_at_linear(parent, lx, ly, surface, sx, sy, distanceSquared); + case L_TABBED: + case L_STACKED: + case L_NONE: + return NULL; + } + + return NULL; +} + + void container_for_each_child(struct sway_container *container, void (*f)(struct sway_container *container, void *data), void *data) { From 6c86f1a35be7c9414365ad3119bdfbbe6d885808 Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Sat, 7 Dec 2024 22:06:21 +0100 Subject: [PATCH 2/2] feat: make gap clicking configurable as 'gap_click_redirect enable' --- include/sway/commands.h | 1 + include/sway/config.h | 1 + sway/commands.c | 1 + sway/commands/gap_click_redirect.c | 16 ++++++++++++++++ sway/config.c | 1 + sway/input/cursor.c | 10 ++++++---- sway/meson.build | 1 + 7 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 sway/commands/gap_click_redirect.c diff --git a/include/sway/commands.h b/include/sway/commands.h index 8f21b989e..2fee4ae00 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -191,6 +191,7 @@ sway_cmd cmd_rename; sway_cmd cmd_resize; sway_cmd cmd_scratchpad; sway_cmd cmd_scratchpad_minimize; +sway_cmd cmd_gap_click_redirect; sway_cmd cmd_seamless_mouse; sway_cmd cmd_set; sway_cmd cmd_shortcuts_inhibitor; diff --git a/include/sway/config.h b/include/sway/config.h index 84e4ab8e7..cf1f409a5 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -500,6 +500,7 @@ struct sway_config { bool titlebar_separator; bool scratchpad_minimize; + bool gap_click_redirect; list_t *layer_criteria; diff --git a/sway/commands.c b/sway/commands.c index 2e048203a..3b8043e0a 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -85,6 +85,7 @@ static const struct cmd_handler handlers[] = { { "force_display_urgency_hint", cmd_force_display_urgency_hint }, { "force_focus_wrapping", cmd_force_focus_wrapping }, { "fullscreen", cmd_fullscreen }, + { "gap_click_redirect", cmd_gap_click_redirect }, { "gaps", cmd_gaps }, { "hide_edge_borders", cmd_hide_edge_borders }, { "input", cmd_input }, diff --git a/sway/commands/gap_click_redirect.c b/sway/commands/gap_click_redirect.c new file mode 100644 index 000000000..86d4ecfd7 --- /dev/null +++ b/sway/commands/gap_click_redirect.c @@ -0,0 +1,16 @@ +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "util.h" + +struct cmd_results *cmd_gap_click_redirect(int argc, char **argv) { + struct cmd_results *error = checkarg(argc, "gap_click_redirect", EXPECTED_AT_LEAST, 1); + + if (error) { + return error; + } + + config->gap_click_redirect = parse_boolean(argv[0], config->gap_click_redirect); + + return cmd_results_new(CMD_SUCCESS, NULL); +} diff --git a/sway/config.c b/sway/config.c index 616965c1e..a5738887b 100644 --- a/sway/config.c +++ b/sway/config.c @@ -368,6 +368,7 @@ static void config_defaults(struct sway_config *config) { config->titlebar_separator = true; config->scratchpad_minimize = false; + config->gap_click_redirect = false; if (!(config->layer_criteria = create_list())) goto cleanup; diff --git a/sway/input/cursor.c b/sway/input/cursor.c index aea7e3bad..248dcca0f 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -241,10 +241,12 @@ struct sway_node *node_at_coords( return NULL; } - double distanceSquared; - struct sway_container *closest_container = closest_tiling_container_at(&ws->node, lx, ly, surface, sx, sy, &distanceSquared); - if(closest_container) { - return &closest_container->node; + if(config->gap_click_redirect) { + double distanceSquared; + struct sway_container *closest_container = closest_tiling_container_at(&ws->node, lx, ly, surface, sx, sy, &distanceSquared); + if(closest_container) { + return &closest_container->node; + } } return &ws->node; diff --git a/sway/meson.build b/sway/meson.build index 40c7382e1..6645c37c1 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -108,6 +108,7 @@ sway_sources = files( 'commands/saturation.c', 'commands/scratchpad.c', 'commands/scratchpad_minimize.c', + 'commands/gap_click_redirect.c', 'commands/seat.c', 'commands/seat/attach.c', 'commands/seat/cursor.c',