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.
This commit is contained in:
parent
bdb402404c
commit
cdcc2a5bb5
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue