Skip to content

Commit

Permalink
#142 smart swap/warp for window drag actions
Browse files Browse the repository at this point in the history
  • Loading branch information
koekeishiya committed Oct 11, 2019
1 parent 1ee6b79 commit 41dcd5b
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Sticky windows are no longer automatically topmost. New option to toggle window always on top through command or rule. New attribute topmost returned in window queries. [#255](https://github.com/koekeishiya/yabai/issues/255)
- Prevent the last user-space from being destroyed or moved to another display, because macOS does not actually support this [#182](https://github.com/koekeishiya/yabai/issues/182)
- Properly read window titles on macOS Catalina [#278](https://github.com/koekeishiya/yabai/issues/278)
- Smart swap/warp for window drag actions - the decision to swap or warp is based on where in the window the cursor is [#142](https://github.com/koekeishiya/yabai/issues/142)

## [2.0.1] - 2019-09-04
### Changed
Expand Down
111 changes: 100 additions & 11 deletions src/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -956,27 +956,116 @@ static EVENT_CALLBACK(EVENT_HANDLER_MOUSE_UP)
struct window_node *a_node = view_find_window_node(src_view, g_mouse_state.window->id);
struct window_node *b_node = window ? view_find_window_node(dst_view, window->id) : NULL;

if (src_view->sid == dst_view->sid) {
if (a_node && b_node) {
/*
* @cleanup
*
* NOTE(koekeishiya): The follow section of code contains duplicated code, but is left
* inline as-is for readability purposes. Consider possibly replacing with a macro,
* because C does not allow for locally-scoped functions.
* */

if (a_node && b_node) {
CGRect frame = window_ax_frame(window);
CGPoint point_in_window = {
.x = point.x - frame.origin.x,
.y = point.y - frame.origin.y
};

CGRect window_center;
window_center.origin.x = 0.25f * frame.size.width;
window_center.origin.y = 0.25f * frame.size.height;
window_center.size.width = 0.50f * frame.size.width;
window_center.size.height = 0.50f * frame.size.height;

CGPoint top_triangle[3];
top_triangle[0].x = 0.0f;
top_triangle[0].y = 0.0f;
top_triangle[1].x = 0.5f * frame.size.width;
top_triangle[1].y = 0.5f * frame.size.height;
top_triangle[2].x = frame.size.width;
top_triangle[2].y = 0.0f;

CGPoint right_triangle[3];
right_triangle[0].x = frame.size.width;
right_triangle[0].y = 0.0f;
right_triangle[1].x = 0.5f * frame.size.width;
right_triangle[1].y = 0.5f * frame.size.height;
right_triangle[2].x = frame.size.width;
right_triangle[2].y = frame.size.height;

CGPoint bottom_triangle[3];
bottom_triangle[0].x = frame.size.width;
bottom_triangle[0].y = frame.size.height;
bottom_triangle[1].x = 0.5f * frame.size.width;
bottom_triangle[1].y = 0.5f * frame.size.height;
bottom_triangle[2].x = 0.0f;
bottom_triangle[2].y = frame.size.height;

CGPoint left_triangle[3];
left_triangle[0].x = 0.0f;
left_triangle[0].y = frame.size.height;
left_triangle[1].x = 0.5f * frame.size.width;
left_triangle[1].y = 0.5f * frame.size.height;
left_triangle[2].x = 0.0f;
left_triangle[2].y = 0.0f;

if (CGRectContainsPoint(window_center, point_in_window)) {
a_node->window_id = window->id;
a_node->zoom = NULL;
b_node->window_id = g_mouse_state.window->id;
b_node->zoom = NULL;
window_node_flush(a_node);
window_node_flush(b_node);
} else if (a_node) {
a_node->zoom = NULL;
window_node_flush(a_node);
}
} else {
space_manager_untile_window(&g_space_manager, src_view, g_mouse_state.window);
window_manager_remove_managed_window(&g_window_manager, g_mouse_state.window->id);
window_manager_purify_window(&g_window_manager, g_mouse_state.window);
} else if (triangle_contains_point(top_triangle, point_in_window)) {
space_manager_untile_window(&g_space_manager, src_view, g_mouse_state.window);
window_manager_remove_managed_window(&g_window_manager, g_mouse_state.window->id);
window_manager_purify_window(&g_window_manager, g_mouse_state.window);

b_node->split = SPLIT_X;
b_node->child = CHILD_FIRST;

if (a_node && b_node) {
struct view *view = space_manager_tile_window_on_space_with_insertion_point(&g_space_manager, g_mouse_state.window, dst_view->sid, window->id);
window_manager_add_managed_window(&g_window_manager, g_mouse_state.window, view);
} else if (triangle_contains_point(right_triangle, point_in_window)) {
space_manager_untile_window(&g_space_manager, src_view, g_mouse_state.window);
window_manager_remove_managed_window(&g_window_manager, g_mouse_state.window->id);
window_manager_purify_window(&g_window_manager, g_mouse_state.window);

b_node->split = SPLIT_Y;
b_node->child = CHILD_SECOND;

struct view *view = space_manager_tile_window_on_space_with_insertion_point(&g_space_manager, g_mouse_state.window, dst_view->sid, window->id);
window_manager_add_managed_window(&g_window_manager, g_mouse_state.window, view);
} else if (triangle_contains_point(bottom_triangle, point_in_window)) {
space_manager_untile_window(&g_space_manager, src_view, g_mouse_state.window);
window_manager_remove_managed_window(&g_window_manager, g_mouse_state.window->id);
window_manager_purify_window(&g_window_manager, g_mouse_state.window);

b_node->split = SPLIT_X;
b_node->child = CHILD_SECOND;

struct view *view = space_manager_tile_window_on_space_with_insertion_point(&g_space_manager, g_mouse_state.window, dst_view->sid, window->id);
window_manager_add_managed_window(&g_window_manager, g_mouse_state.window, view);
} else if (triangle_contains_point(left_triangle, point_in_window)) {
space_manager_untile_window(&g_space_manager, src_view, g_mouse_state.window);
window_manager_remove_managed_window(&g_window_manager, g_mouse_state.window->id);
window_manager_purify_window(&g_window_manager, g_mouse_state.window);

b_node->split = SPLIT_Y;
b_node->child = CHILD_FIRST;

struct view *view = space_manager_tile_window_on_space_with_insertion_point(&g_space_manager, g_mouse_state.window, dst_view->sid, window->id);
window_manager_add_managed_window(&g_window_manager, g_mouse_state.window, view);
}
} else if (a_node) {
if (src_view->sid == dst_view->sid) {
a_node->zoom = NULL;
window_node_flush(a_node);
} else {
space_manager_untile_window(&g_space_manager, src_view, g_mouse_state.window);
window_manager_remove_managed_window(&g_window_manager, g_mouse_state.window->id);
window_manager_purify_window(&g_window_manager, g_mouse_state.window);

struct view *view = space_manager_tile_window_on_space(&g_space_manager, g_mouse_state.window, dst_view->sid);
window_manager_add_managed_window(&g_window_manager, g_mouse_state.window, view);
}
Expand Down
9 changes: 9 additions & 0 deletions src/misc/helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,15 @@ static uint32_t rect_distance(CGRect r1, CGRect r2, int direction)
return UINT32_MAX;
}

static bool triangle_contains_point(CGPoint t[3], CGPoint p)
{
float l1 = (p.x - t[0].x) * (t[2].y - t[0].y) - (t[2].x - t[0].x) * (p.y - t[0].y);
float l2 = (p.x - t[1].x) * (t[0].y - t[1].y) - (t[0].x - t[1].x) * (p.y - t[1].y);
float l3 = (p.x - t[2].x) * (t[1].y - t[2].y) - (t[1].x - t[2].x) * (p.y - t[2].y);

return (l1 > 0.0f && l2 > 0.0f && l3 > 0.0f) || (l1 < 0.0f && l2 < 0.0f && l3 < 0.0f);
}

static int regex_match(bool valid, regex_t *regex, const char *match)
{
if (!valid || !match) return REGEX_MATCH_UD;
Expand Down

0 comments on commit 41dcd5b

Please sign in to comment.