Skip to content

Commit

Permalink
Add FARTHEST_DIR_SEL for windows
Browse files Browse the repository at this point in the history
  • Loading branch information
kiryph committed Feb 23, 2022
1 parent 916d913 commit 6b9c0ba
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 20 deletions.
4 changes: 3 additions & 1 deletion doc/yabai.1
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,11 @@ SIGNAL_SEL := <index> | LABEL

DIR_SEL := north | east | south | west

FARTHEST_DIR_SEL := farthest_north | farthest_east | farthest_south | farthest_west

STACK_SEL := stack.prev | stack.next | stack.first | stack.last | stack.recent

WINDOW_SEL := prev | next | first | last | recent | mouse | largest | smallest | STACK_SEL | DIR_SEL | <window id>
WINDOW_SEL := prev | next | first | last | recent | mouse | largest | smallest | STACK_SEL | DIR_SEL | FARTHEST_DIR_SEL | <window id>

DISPLAY_SEL := prev | next | first | last | recent | mouse | DIR_SEL | <arrangement index (1\-based)>

Expand Down
4 changes: 3 additions & 1 deletion doc/yabai.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,11 @@ SIGNAL_SEL := <index> | LABEL
DIR_SEL := north | east | south | west
FARTHEST_DIR_SEL := farthest_north | farthest_east | farthest_south | farthest_west
STACK_SEL := stack.prev | stack.next | stack.first | stack.last | stack.recent
WINDOW_SEL := prev | next | first | last | recent | mouse | largest | smallest | STACK_SEL | DIR_SEL | <window id>
WINDOW_SEL := prev | next | first | last | recent | mouse | largest | smallest | STACK_SEL | DIR_SEL | FARTHEST_DIR_SEL | <window id>
DISPLAY_SEL := prev | next | first | last | recent | mouse | DIR_SEL | <arrangement index (1-based)>
Expand Down
84 changes: 66 additions & 18 deletions src/message.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,24 +204,28 @@ extern bool g_verbose;
/* ----------------------------------------------------------------------------- */

/* --------------------------------COMMON ARGUMENTS----------------------------- */
#define ARGUMENT_COMMON_VAL_ON "on"
#define ARGUMENT_COMMON_VAL_OFF "off"
#define ARGUMENT_COMMON_SEL_PREV "prev"
#define ARGUMENT_COMMON_SEL_NEXT "next"
#define ARGUMENT_COMMON_SEL_FIRST "first"
#define ARGUMENT_COMMON_SEL_LAST "last"
#define ARGUMENT_COMMON_SEL_RECENT "recent"
#define ARGUMENT_COMMON_SEL_NORTH "north"
#define ARGUMENT_COMMON_SEL_EAST "east"
#define ARGUMENT_COMMON_SEL_SOUTH "south"
#define ARGUMENT_COMMON_SEL_WEST "west"
#define ARGUMENT_COMMON_SEL_MOUSE "mouse"
#define ARGUMENT_COMMON_SEL_STACK "stack"
#define ARGUMENT_COMMON_SEL_STACK_PREV "stack.prev"
#define ARGUMENT_COMMON_SEL_STACK_NEXT "stack.next"
#define ARGUMENT_COMMON_SEL_STACK_FIRST "stack.first"
#define ARGUMENT_COMMON_SEL_STACK_LAST "stack.last"
#define ARGUMENT_COMMON_SEL_STACK_RECENT "stack.recent"
#define ARGUMENT_COMMON_VAL_ON "on"
#define ARGUMENT_COMMON_VAL_OFF "off"
#define ARGUMENT_COMMON_SEL_PREV "prev"
#define ARGUMENT_COMMON_SEL_NEXT "next"
#define ARGUMENT_COMMON_SEL_FIRST "first"
#define ARGUMENT_COMMON_SEL_LAST "last"
#define ARGUMENT_COMMON_SEL_RECENT "recent"
#define ARGUMENT_COMMON_SEL_NORTH "north"
#define ARGUMENT_COMMON_SEL_EAST "east"
#define ARGUMENT_COMMON_SEL_SOUTH "south"
#define ARGUMENT_COMMON_SEL_WEST "west"
#define ARGUMENT_COMMON_SEL_FARTHEST_NORTH "farthest_north"
#define ARGUMENT_COMMON_SEL_FARTHEST_EAST "farthest_east"
#define ARGUMENT_COMMON_SEL_FARTHEST_SOUTH "farthest_south"
#define ARGUMENT_COMMON_SEL_FARTHEST_WEST "farthest_west"
#define ARGUMENT_COMMON_SEL_MOUSE "mouse"
#define ARGUMENT_COMMON_SEL_STACK "stack"
#define ARGUMENT_COMMON_SEL_STACK_PREV "stack.prev"
#define ARGUMENT_COMMON_SEL_STACK_NEXT "stack.next"
#define ARGUMENT_COMMON_SEL_STACK_FIRST "stack.first"
#define ARGUMENT_COMMON_SEL_STACK_LAST "stack.last"
#define ARGUMENT_COMMON_SEL_STACK_RECENT "stack.recent"
/* ----------------------------------------------------------------------------- */

struct token
Expand Down Expand Up @@ -798,6 +802,50 @@ static struct selector parse_window_selector(FILE *rsp, char **message, struct w
} else {
daemon_fail(rsp, "could not locate the selected window.\n");
}
} else if (token_equals(result.token, ARGUMENT_COMMON_SEL_FARTHEST_NORTH)) {
if (acting_window) {
struct window *closest_window = window_manager_find_farthest_managed_window_in_direction(&g_window_manager, acting_window, DIR_NORTH);
if (closest_window) {
result.window = closest_window;
} else {
daemon_fail(rsp, "could not locate a farthest northward managed window.\n");
}
} else {
daemon_fail(rsp, "could not locate the selected window.\n");
}
} else if (token_equals(result.token, ARGUMENT_COMMON_SEL_FARTHEST_EAST)) {
if (acting_window) {
struct window *closest_window = window_manager_find_farthest_managed_window_in_direction(&g_window_manager, acting_window, DIR_EAST);
if (closest_window) {
result.window = closest_window;
} else {
daemon_fail(rsp, "could not locate a farthest eastward managed window.\n");
}
} else {
daemon_fail(rsp, "could not locate the selected window.\n");
}
} else if (token_equals(result.token, ARGUMENT_COMMON_SEL_FARTHEST_SOUTH)) {
if (acting_window) {
struct window *closest_window = window_manager_find_farthest_managed_window_in_direction(&g_window_manager, acting_window, DIR_SOUTH);
if (closest_window) {
result.window = closest_window;
} else {
daemon_fail(rsp, "could not locate a farthest southward managed window.\n");
}
} else {
daemon_fail(rsp, "could not locate the selected window.\n");
}
} else if (token_equals(result.token, ARGUMENT_COMMON_SEL_FARTHEST_WEST)) {
if (acting_window) {
struct window *closest_window = window_manager_find_farthest_managed_window_in_direction(&g_window_manager, acting_window, DIR_WEST);
if (closest_window) {
result.window = closest_window;
} else {
daemon_fail(rsp, "could not locate a farthest westward managed window.\n");
}
} else {
daemon_fail(rsp, "could not locate the selected window.\n");
}
} else if (token_equals(result.token, ARGUMENT_COMMON_SEL_MOUSE)) {
struct window *mouse_window = window_manager_find_window_below_cursor(&g_window_manager);
if (mouse_window) {
Expand Down
85 changes: 85 additions & 0 deletions src/view.c
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,91 @@ struct window_node *view_find_window_node_in_direction(struct view *view, struct
return best_node;
}

struct window_node *view_find_farthest_window_node_in_direction(struct view *view, struct window_node *source, int direction)
{
// Maximize parallel part of direction and minimize orthogonal part of direction
// measured from center of source window (source_point) to center of
// - west border of target for DIR_WEST
// - east border of target for DIR_EAST
// - north border of target for DIR_NORTH
// - north border of target for DIR_SOUTH
// Note coordinate origin: (x=0 (vertical),y=0 (horizontal)) is at top, left corner of screen.

int best_distance_parallel = 0, best_distance_orthogonal = INT_MAX;
CGPoint source_point = area_center(source->area);

struct window_node *best_node = NULL;
struct window_node *target = window_node_find_first_leaf(view->root);

while (target) {
CGPoint target_point = area_center(target->area);

int distance_parallel=0, distance_orthogonal=0;
switch (direction) {
case DIR_EAST: {
distance_parallel = (source_point.x-(target->area.x+target->area.w))*(source_point.x-(target->area.x+target->area.w));
distance_orthogonal = (source_point.y-target_point.y)*(source_point.y-target_point.y);
} break;
case DIR_WEST: {
distance_parallel = (source_point.x-target->area.x)*(source_point.x-target->area.x);
distance_orthogonal = (source_point.y-target_point.y)*(source_point.y-target_point.y);
} break;
case DIR_NORTH: {
distance_parallel = (source_point.y-target->area.y)*(source_point.y-target->area.y);
distance_orthogonal = (source_point.x-target_point.x)*(source_point.x-target_point.x);
} break;
case DIR_SOUTH: {
distance_parallel = (source_point.y-(target->area.y+target->area.h))*(source_point.y-(target->area.y+target->area.h));
distance_orthogonal = (source_point.x-target_point.x)*(source_point.x-target_point.x);
} break;
}

// Skip if parallel dir is not farther and orthogonal dir is not closer
if (distance_parallel <= best_distance_parallel &&
distance_orthogonal >= best_distance_orthogonal) goto next;

switch (direction) {
case DIR_EAST: {
// Accept only if target is actually in the east: compare left of target with right of source
if (target->area.x >= source->area.x + source->area.w) {
best_node = target;
best_distance_parallel = distance_parallel;
best_distance_orthogonal = distance_orthogonal;
}
} break;
case DIR_SOUTH: {
// Accept only if target is actually in the south: compare top of target with bottom of source
if (target->area.y >= source->area.y + source->area.h) {
best_node = target;
best_distance_parallel = distance_parallel;
best_distance_orthogonal = distance_orthogonal;
}
} break;
case DIR_WEST: {
// Accept only if target is actually in the west: compare right of target with left of source
if (target->area.x + target->area.w <= source->area.x) {
best_node = target;
best_distance_parallel = distance_parallel;
best_distance_orthogonal = distance_orthogonal;
}
} break;
case DIR_NORTH: {
// Accept only if target is actually in the north: compare bottom of target with top of source
if (target->area.y + target->area.h <= source->area.y) {
best_node = target;
best_distance_parallel = distance_parallel;
best_distance_orthogonal = distance_orthogonal;
}
} break;
}

next:
target = window_node_find_next_leaf(target);
}

return best_node;
}

struct window_node *view_find_window_node(struct view *view, uint32_t window_id)
{
struct window_node *node = window_node_find_first_leaf(view->root);
Expand Down
1 change: 1 addition & 0 deletions src/view.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ struct window_node *window_node_find_prev_leaf(struct window_node *node);
struct window_node *window_node_find_next_leaf(struct window_node *node);

struct window_node *view_find_window_node_in_direction(struct view *view, struct window_node *source, int direction);
struct window_node *view_find_farthest_window_node_in_direction(struct view *view, struct window_node *source, int direction);
struct window_node *view_find_window_node(struct view *view, uint32_t window_id);
void view_stack_window_node(struct view *view, struct window_node *node, struct window *window);
void view_add_window_node(struct view *view, struct window *window);
Expand Down
14 changes: 14 additions & 0 deletions src/window_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,20 @@ struct window *window_manager_find_closest_managed_window_in_direction(struct wi
return window_manager_find_window(wm, closest->window_order[0]);
}

struct window *window_manager_find_farthest_managed_window_in_direction(struct window_manager *wm, struct window *window, int direction)
{
struct view *view = window_manager_find_managed_window(wm, window);
if (!view) return NULL;

struct window_node *node = view_find_window_node(view, window->id);
if (!node) return NULL;

struct window_node *farthest = view_find_farthest_window_node_in_direction(view, node, direction);
if (!farthest) return NULL;

return window_manager_find_window(wm, farthest->window_order[0]);
}

struct window *window_manager_find_prev_managed_window(struct space_manager *sm, struct window_manager *wm, struct window *window)
{
struct view *view = space_manager_find_view(sm, space_manager_active_space());
Expand Down
1 change: 1 addition & 0 deletions src/window_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ struct window *window_manager_find_window_at_point_filtering_window(struct windo
struct window *window_manager_find_window_at_point(struct window_manager *wm, CGPoint point);
struct window *window_manager_find_window_below_cursor(struct window_manager *wm);
struct window *window_manager_find_closest_managed_window_in_direction(struct window_manager *wm, struct window *window, int direction);
struct window *window_manager_find_farthest_managed_window_in_direction(struct window_manager *wm, struct window *window, int direction);
struct window *window_manager_find_prev_managed_window(struct space_manager *sm, struct window_manager *wm, struct window *window);
struct window *window_manager_find_next_managed_window(struct space_manager *sm, struct window_manager *wm, struct window *window);
struct window *window_manager_find_first_managed_window(struct space_manager *sm, struct window_manager *wm);
Expand Down

0 comments on commit 6b9c0ba

Please sign in to comment.