Skip to content

Commit

Permalink
#225 extend display_sel to include dir_sel to target displays using c…
Browse files Browse the repository at this point in the history
…ardinal directions
  • Loading branch information
koekeishiya committed Jun 5, 2020
1 parent 20bef34 commit c565304
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 17 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
## [Unreleased]
### Changed
- If *focus follows mouse* is enabled, moving the cursor to a different display will now focus that display even if it is empty [#459](https://github.com/koekeishiya/yabai/issues/459)
- Extend definition of *DISPLAY_SEL* to include *DIR_SEL* so that displays can be targetted using cardinal directions [#225](https://github.com/koekeishiya/yabai/issues/225)

## [3.1.0] - 2020-06-05
### Added
Expand Down
6 changes: 3 additions & 3 deletions doc/yabai.1
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
.\" Title: yabai
.\" Author: [see the "AUTHOR(S)" section]
.\" Generator: Asciidoctor 2.0.10
.\" Date: 2020-06-02
.\" Date: 2020-06-06
.\" Manual: Yabai Manual
.\" Source: Yabai
.\" Language: English
.\"
.TH "YABAI" "1" "2020-06-02" "Yabai" "Yabai Manual"
.TH "YABAI" "1" "2020-06-06" "Yabai" "Yabai Manual"
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.ss \n[.ss] 0
Expand Down Expand Up @@ -104,7 +104,7 @@ DIR_SEL := north | east | south | west

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

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

SPACE_SEL := prev | next | first | last | recent | <mission\-control index (1\-based)> | LABEL
.fi
Expand Down
2 changes: 1 addition & 1 deletion doc/yabai.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ DIR_SEL := north | east | south | west
WINDOW_SEL := prev | next | first | last | recent | mouse | largest | smallest | DIR_SEL | <window id>
DISPLAY_SEL := prev | next | first | last | recent | <arrangement index (1-based)>
DISPLAY_SEL := prev | next | first | last | recent | DIR_SEL | <arrangement index (1-based)>
SPACE_SEL := prev | next | first | last | recent | <mission-control index (1-based)> | LABEL
Expand Down
52 changes: 52 additions & 0 deletions src/display_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,58 @@ uint32_t display_manager_last_display_id(void)
return display_manager_arrangement_display_id(arrangement);
}

uint32_t display_manager_find_closest_display_in_direction(uint32_t source_did, int direction)
{
uint32_t display_count;
uint32_t *display_list = display_manager_active_display_list(&display_count);
if (!display_list) return 0;

uint32_t best_did = 0;
int best_distance = INT_MAX;
CGRect source_bounds = display_bounds(source_did);
CGPoint source_point = (CGPoint) { source_bounds.origin.x + source_bounds.size.width/2, source_bounds.origin.y + source_bounds.size.height/2 };

for (int i = 0; i < display_count; ++i) {
uint32_t did = display_list[i];
if (did == source_did) continue;

CGRect bounds = display_bounds(did);
CGPoint point = (CGPoint) { bounds.origin.x + bounds.size.width/2, bounds.origin.y + bounds.size.height/2 };
int distance = euclidean_distance(source_point, point);
if (distance >= best_distance) continue;

switch (direction) {
case DIR_EAST: {
if (bounds.origin.x >= source_bounds.origin.x + source_bounds.size.width) {
best_did = did;
best_distance = distance;
}
} break;
case DIR_SOUTH: {
if (bounds.origin.y >= source_bounds.origin.y + source_bounds.size.height) {
best_did = did;
best_distance = distance;
}
} break;
case DIR_WEST: {
if (bounds.origin.x + bounds.size.width <= source_bounds.origin.x) {
best_did = did;
best_distance = distance;
}
} break;
case DIR_NORTH: {
if (bounds.origin.y + bounds.size.height <= source_bounds.origin.y) {
best_did = did;
best_distance = distance;
}
} break;
}
}

free(display_list);
return best_did;
}

bool display_manager_menu_bar_hidden(void)
{
int status = 0;
Expand Down
1 change: 1 addition & 0 deletions src/display_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ uint32_t display_manager_prev_display_id(uint32_t did);
uint32_t display_manager_next_display_id(uint32_t did);
uint32_t display_manager_first_display_id(void);
uint32_t display_manager_last_display_id(void);
uint32_t display_manager_find_closest_display_in_direction(uint32_t acting_did, int direction);
bool display_manager_menu_bar_hidden(void);
CGRect display_manager_menu_bar_rect(uint32_t did);
bool display_manager_dock_hidden(void);
Expand Down
70 changes: 57 additions & 13 deletions src/message.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,6 @@ extern bool g_verbose;
#define COMMAND_WINDOW_DISPLAY "--display"
#define COMMAND_WINDOW_SPACE "--space"

#define ARGUMENT_WINDOW_DIR_NORTH "north"
#define ARGUMENT_WINDOW_DIR_EAST "east"
#define ARGUMENT_WINDOW_DIR_SOUTH "south"
#define ARGUMENT_WINDOW_DIR_WEST "west"
#define ARGUMENT_WINDOW_SEL_MOUSE "mouse"
#define ARGUMENT_WINDOW_SEL_LARGEST "largest"
#define ARGUMENT_WINDOW_SEL_SMALLEST "smallest"
Expand Down Expand Up @@ -192,6 +188,10 @@ extern bool g_verbose;
#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"
/* ----------------------------------------------------------------------------- */

static bool token_equals(struct token token, char *match)
Expand Down Expand Up @@ -821,7 +821,51 @@ static struct selector parse_display_selector(FILE *rsp, char **message, uint32_
.did_parse = true
};

if (token_equals(result.token, ARGUMENT_COMMON_SEL_PREV)) {
if (token_equals(result.token, ARGUMENT_COMMON_SEL_NORTH)) {
if (acting_did) {
uint32_t did = display_manager_find_closest_display_in_direction(acting_did, DIR_NORTH);
if (did) {
result.did = did;
} else {
daemon_fail(rsp, "could not locate a northward display.\n");
}
} else {
daemon_fail(rsp, "could not locate the selected display.\n");
}
} else if (token_equals(result.token, ARGUMENT_COMMON_SEL_EAST)) {
if (acting_did) {
uint32_t did = display_manager_find_closest_display_in_direction(acting_did, DIR_EAST);
if (did) {
result.did = did;
} else {
daemon_fail(rsp, "could not locate a eastward display.\n");
}
} else {
daemon_fail(rsp, "could not locate the selected display.\n");
}
} else if (token_equals(result.token, ARGUMENT_COMMON_SEL_SOUTH)) {
if (acting_did) {
uint32_t did = display_manager_find_closest_display_in_direction(acting_did, DIR_SOUTH);
if (did) {
result.did = did;
} else {
daemon_fail(rsp, "could not locate a southward display.\n");
}
} else {
daemon_fail(rsp, "could not locate the selected display.\n");
}
} else if (token_equals(result.token, ARGUMENT_COMMON_SEL_WEST)) {
if (acting_did) {
uint32_t did = display_manager_find_closest_display_in_direction(acting_did, DIR_WEST);
if (did) {
result.did = did;
} else {
daemon_fail(rsp, "could not locate a westward display.\n");
}
} else {
daemon_fail(rsp, "could not locate the selected display.\n");
}
} else if (token_equals(result.token, ARGUMENT_COMMON_SEL_PREV)) {
if (acting_did) {
uint32_t did = display_manager_prev_display_id(acting_did);
if (did) {
Expand Down Expand Up @@ -967,7 +1011,7 @@ static struct selector parse_window_selector(FILE *rsp, char **message, struct w
.did_parse = true
};

if (token_equals(result.token, ARGUMENT_WINDOW_DIR_NORTH)) {
if (token_equals(result.token, ARGUMENT_COMMON_SEL_NORTH)) {
if (acting_window) {
struct window *closest_window = window_manager_find_closest_window_in_direction(&g_window_manager, acting_window, DIR_NORTH);
if (closest_window) {
Expand All @@ -978,7 +1022,7 @@ 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_WINDOW_DIR_EAST)) {
} else if (token_equals(result.token, ARGUMENT_COMMON_SEL_EAST)) {
if (acting_window) {
struct window *closest_window = window_manager_find_closest_window_in_direction(&g_window_manager, acting_window, DIR_EAST);
if (closest_window) {
Expand All @@ -989,7 +1033,7 @@ 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_WINDOW_DIR_SOUTH)) {
} else if (token_equals(result.token, ARGUMENT_COMMON_SEL_SOUTH)) {
if (acting_window) {
struct window *closest_window = window_manager_find_closest_window_in_direction(&g_window_manager, acting_window, DIR_SOUTH);
if (closest_window) {
Expand All @@ -1000,7 +1044,7 @@ 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_WINDOW_DIR_WEST)) {
} else if (token_equals(result.token, ARGUMENT_COMMON_SEL_WEST)) {
if (acting_window) {
struct window *closest_window = window_manager_find_closest_window_in_direction(&g_window_manager, acting_window, DIR_WEST);
if (closest_window) {
Expand Down Expand Up @@ -1107,13 +1151,13 @@ static struct selector parse_dir_selector(FILE *rsp, char **message)
.did_parse = true
};

if (token_equals(result.token, ARGUMENT_WINDOW_DIR_NORTH)) {
if (token_equals(result.token, ARGUMENT_COMMON_SEL_NORTH)) {
result.dir = DIR_NORTH;
} else if (token_equals(result.token, ARGUMENT_WINDOW_DIR_EAST)) {
} else if (token_equals(result.token, ARGUMENT_COMMON_SEL_EAST)) {
result.dir = DIR_EAST;
} else if (token_equals(result.token, ARGUMENT_WINDOW_DIR_SOUTH)) {
} else if (token_equals(result.token, ARGUMENT_COMMON_SEL_SOUTH)) {
result.dir = DIR_SOUTH;
} else if (token_equals(result.token, ARGUMENT_WINDOW_DIR_WEST)) {
} else if (token_equals(result.token, ARGUMENT_COMMON_SEL_WEST)) {
result.dir = DIR_WEST;
} else {
result.did_parse = false;
Expand Down

0 comments on commit c565304

Please sign in to comment.