From cdcc2a5bb52a34865eee2ec3d09a38b047c08ffd Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Wed, 20 Mar 2019 22:16:53 +1000 Subject: Support focus for floating containers This kind of worked before in that focus would change, but it wasn't intentionally supported and had side effects such as not raising the container, and being unable to cycle through all floaters depending on the direction used. This commit makes it properly supported. The new focus is chosen based on the distance to the center point of each floating container in the workspace, and the container is raised. In a multi output setup, if both visible workspaces have floating containers, focus will NOT cross into the other output. It is assumed the user will use a workspace binding in this case. If two floating containers occupy the exact same center point and you try to focus in a direction, the behaviour is undefined. --- sway/commands/focus.c | 49 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/sway/commands/focus.c b/sway/commands/focus.c index 6344a765..33d01405 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c @@ -1,3 +1,4 @@ +#include #include #include #include "log.h" @@ -90,8 +91,9 @@ static struct sway_node *get_node_in_output_direction( return &ws->node; } -static struct sway_node *node_get_in_direction(struct sway_container *container, - struct sway_seat *seat, enum wlr_direction dir) { +static struct sway_node *node_get_in_direction_tiling( + struct sway_container *container, struct sway_seat *seat, + enum wlr_direction dir) { struct sway_container *wrap_candidate = NULL; struct sway_container *current = container; while (current) { @@ -172,6 +174,37 @@ static struct sway_node *node_get_in_direction(struct sway_container *container, return NULL; } +static struct sway_node *node_get_in_direction_floating( + struct sway_container *con, struct sway_seat *seat, + enum wlr_direction dir) { + double ref_lx = con->x + con->width / 2; + double ref_ly = con->y + con->height / 2; + double closest_distance = DBL_MAX; + struct sway_container *closest_con = NULL; + + for (int i = 0; i < con->workspace->floating->length; i++) { + struct sway_container *floater = con->workspace->floating->items[i]; + if (floater == con) { + continue; + } + float distance = dir == WLR_DIRECTION_LEFT || dir == WLR_DIRECTION_RIGHT + ? (floater->x + floater->width / 2) - ref_lx + : (floater->y + floater->height / 2) - ref_ly; + if (dir == WLR_DIRECTION_LEFT || dir == WLR_DIRECTION_UP) { + distance = -distance; + } + if (distance < 0) { + continue; + } + if (distance < closest_distance) { + closest_distance = distance; + closest_con = floater; + } + } + + return closest_con ? &closest_con->node : NULL; +} + static struct cmd_results *focus_mode(struct sway_workspace *ws, struct sway_seat *seat, bool floating) { struct sway_container *new_focus = NULL; @@ -330,11 +363,19 @@ struct cmd_results *cmd_focus(int argc, char **argv) { return cmd_results_new(CMD_SUCCESS, NULL); } - struct sway_node *next_focus = - node_get_in_direction(container, seat, direction); + struct sway_node *next_focus = NULL; + if (container_is_floating(container)) { + next_focus = node_get_in_direction_floating(container, seat, direction); + } else { + next_focus = node_get_in_direction_tiling(container, seat, direction); + } if (next_focus) { seat_set_focus(seat, next_focus); seat_consider_warp_to_focus(seat); + + if (next_focus->type == N_CONTAINER) { + container_raise_floating(next_focus->sway_container); + } } return cmd_results_new(CMD_SUCCESS, NULL); -- cgit v1.2.3