diff --git a/CHANGELOG.md b/CHANGELOG.md index 215db71f..2a93ffc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - 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) - When an application is launched or a window is created; tile the window on the space that has focus, rather than the display it spawned at [#467](https://github.com/koekeishiya/yabai/issues/467) - Properly re-adjust window frame of managed windows if they break the assigned region in response to an event not invoked directly by the user [#16](https://github.com/koekeishiya/yabai/issues/16) +- Cardinal directions for *WINDOW_SEL* will only consider managed windows due to various issues with detecting the correct window [#562](https://github.com/koekeishiya/yabai/issues/562) ## [3.1.0] - 2020-06-05 ### Added diff --git a/src/message.c b/src/message.c index 502a250b..46e3d573 100644 --- a/src/message.c +++ b/src/message.c @@ -1013,7 +1013,7 @@ static struct selector parse_window_selector(FILE *rsp, char **message, struct w 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); + struct window *closest_window = window_manager_find_closest_managed_window_in_direction(&g_window_manager, acting_window, DIR_NORTH); if (closest_window) { result.window = closest_window; } else { @@ -1024,7 +1024,7 @@ static struct selector parse_window_selector(FILE *rsp, char **message, struct w } } 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); + struct window *closest_window = window_manager_find_closest_managed_window_in_direction(&g_window_manager, acting_window, DIR_EAST); if (closest_window) { result.window = closest_window; } else { @@ -1035,7 +1035,7 @@ static struct selector parse_window_selector(FILE *rsp, char **message, struct w } } 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); + struct window *closest_window = window_manager_find_closest_managed_window_in_direction(&g_window_manager, acting_window, DIR_SOUTH); if (closest_window) { result.window = closest_window; } else { @@ -1046,7 +1046,7 @@ static struct selector parse_window_selector(FILE *rsp, char **message, struct w } } 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); + struct window *closest_window = window_manager_find_closest_managed_window_in_direction(&g_window_manager, acting_window, DIR_WEST); if (closest_window) { result.window = closest_window; } else { diff --git a/src/view.c b/src/view.c index c6df8097..b233f731 100644 --- a/src/view.c +++ b/src/view.c @@ -92,36 +92,35 @@ void insert_feedback_destroy(struct window_node *node) } } -static struct area area_from_cgrect(CGRect rect) +static inline CGPoint area_center(struct area a) { - struct area area = { - rect.origin.x, - rect.origin.y, - rect.size.width, - rect.size.height - }; - return area; + return (CGPoint) { a.x + a.w*0.5f, a.y + a.h*0.5f }; } -static enum window_node_child window_node_get_child(struct window_node *node) +static inline struct area area_from_cgrect(CGRect rect) +{ + return (struct area) { rect.origin.x, rect.origin.y, rect.size.width, rect.size.height }; +} + +static inline enum window_node_child window_node_get_child(struct window_node *node) { if (node->child != CHILD_NONE) return node->child; return g_space_manager.window_placement; } -static enum window_node_split window_node_get_split(struct window_node *node) +static inline enum window_node_split window_node_get_split(struct window_node *node) { if (node->split != SPLIT_NONE) return node->split; return node->area.w / node->area.h >= 1.1618f ? SPLIT_Y : SPLIT_X; } -static float window_node_get_ratio(struct window_node *node) +static inline float window_node_get_ratio(struct window_node *node) { if (in_range_ii(node->ratio, 0.1f, 0.9f)) return node->ratio; return g_space_manager.split_ratio; } -static float window_node_get_gap(struct view *view) +static inline float window_node_get_gap(struct view *view) { return view->enable_gap ? view->window_gap*0.5f : 0.0f; } @@ -158,27 +157,27 @@ static void area_make_pair(struct view *view, struct window_node *node) node->ratio = ratio; } -static bool window_node_is_occupied(struct window_node *node) +static inline bool window_node_is_occupied(struct window_node *node) { return node->window_id != 0; } -static bool window_node_is_intermediate(struct window_node *node) +static inline bool window_node_is_intermediate(struct window_node *node) { return node->parent != NULL; } -static bool window_node_is_leaf(struct window_node *node) +static inline bool window_node_is_leaf(struct window_node *node) { return node->left == NULL && node->right == NULL; } -static bool window_node_is_left_child(struct window_node *node) +static inline bool window_node_is_left_child(struct window_node *node) { return node->parent && node->parent->left == node; } -static bool window_node_is_right_child(struct window_node *node) +static inline bool window_node_is_right_child(struct window_node *node) { return node->parent && node->parent->right == node; } @@ -422,6 +421,52 @@ struct window_node *view_find_min_depth_leaf_node(struct window_node *node) return NULL; } +struct window_node *view_find_window_node_in_direction(struct view *view, struct window_node *source, int direction) +{ + int best_distance = INT_MAX; + struct window_node *best_node = NULL; + CGPoint source_point = area_center(source->area); + + struct window_node *target = window_node_find_first_leaf(view->root); + while (target) { + CGPoint target_point = area_center(target->area); + int distance = euclidean_distance(source_point, target_point); + if (distance >= best_distance) goto next; + + switch (direction) { + case DIR_EAST: { + if (target->area.x >= source->area.x + source->area.w) { + best_node = target; + best_distance = distance; + } + } break; + case DIR_SOUTH: { + if (target->area.y >= source->area.y + source->area.h) { + best_node = target; + best_distance = distance; + } + } break; + case DIR_WEST: { + if (target->area.x + target->area.w <= source->area.x) { + best_node = target; + best_distance = distance; + } + } break; + case DIR_NORTH: { + if (target->area.y + target->area.h <= source->area.y) { + best_node = target; + best_distance = distance; + } + } 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); diff --git a/src/view.h b/src/view.h index 8ac7e8d3..1f43f454 100644 --- a/src/view.h +++ b/src/view.h @@ -129,6 +129,7 @@ struct window_node *window_node_find_last_leaf(struct window_node *root); 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_window_node(struct view *view, uint32_t window_id); void view_remove_window_node(struct view *view, struct window *window); void view_add_window_node(struct view *view, struct window *window); diff --git a/src/window_manager.c b/src/window_manager.c index adb545a0..b44a8d11 100644 --- a/src/window_manager.c +++ b/src/window_manager.c @@ -581,79 +581,18 @@ struct window *window_manager_find_window_below_cursor(struct window_manager *wm return window_manager_find_window_at_point(wm, cursor); } -static struct window *window_manager_find_closest_window_for_direction_in_window_list(struct window_manager *wm, struct window *source, int direction, uint32_t *window_list, int window_count) -{ - struct window *best_window = NULL; - int best_distance = INT_MAX; - - CGRect source_frame = window_frame(source); - CGPoint source_point = { source_frame.origin.x, source_frame.origin.y }; - - for (int i = 0; i < window_count; ++i) { - struct window *window = window_manager_find_window(wm, window_list[i]); - if (!window || !window_is_standard(window) || window == source) continue; - - CGRect frame = window_frame(window); - CGPoint point = { frame.origin.x, frame.origin.y }; - - int distance = euclidean_distance(source_point, point); - if (distance >= best_distance) continue; - - switch (direction) { - case DIR_EAST: { - if (point.x > source_point.x) { - best_window = window; - best_distance = distance; - } - } break; - case DIR_SOUTH: { - if (point.y > source_point.y) { - best_window = window; - best_distance = distance; - } - } break; - case DIR_WEST: { - if (point.x < source_point.x) { - best_window = window; - best_distance = distance; - } - } break; - case DIR_NORTH: { - if (point.y < source_point.y) { - best_window = window; - best_distance = distance; - } - } break; - } - } - - return best_window; -} - struct window *window_manager_find_closest_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; - uint32_t *view_window_list = view_find_window_list(view); - if (!view_window_list) return NULL; - - struct window *result = window_manager_find_closest_window_for_direction_in_window_list(wm, window, direction, view_window_list, buf_len(view_window_list)); - buf_free(view_window_list); - - return result; -} - -struct window *window_manager_find_closest_window_in_direction(struct window_manager *wm, struct window *window, int direction) -{ - int window_count; - uint32_t *window_list = space_window_list(display_space_id(window_display_id(window)), &window_count, false); - if (!window_list) return NULL; + struct window_node *node = view_find_window_node(view, window->id); + if (!node) return NULL; - struct window *result = window_manager_find_closest_window_for_direction_in_window_list(wm, window, direction, window_list, window_count); - free(window_list); + struct window_node *closest = view_find_window_node_in_direction(view, node, direction); + if (!closest) return NULL; - return result; + return window_manager_find_window(wm, closest->window_id); } struct window *window_manager_find_prev_managed_window(struct space_manager *sm, struct window_manager *wm, struct window *window) diff --git a/src/window_manager.h b/src/window_manager.h index 01a25b11..7b8e5f3e 100644 --- a/src/window_manager.h +++ b/src/window_manager.h @@ -105,7 +105,6 @@ 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_closest_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);