aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Dwyer <ryandwyer1@gmail.com>2019-03-20 22:16:53 +1000
committerDrew DeVault <sir@cmpwn.com>2019-03-20 08:55:28 -0600
commitcdcc2a5bb52a34865eee2ec3d09a38b047c08ffd (patch)
tree326f7c5be7a51d56ce5617d6bc536c94db3cf129
parentbdb402404cd6d54242b0b1dc2360cfc5679e52f2 (diff)
Support focus <direction> 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.
-rw-r--r--sway/commands/focus.c49
1 files 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 <float.h>
#include <strings.h>
#include <wlr/types/wlr_output_layout.h>
#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);