Skip to content

Commit

Permalink
#1435 change how window placement is decided when warping windows wit…
Browse files Browse the repository at this point in the history
…hin the same space
  • Loading branch information
koekeishiya committed Dec 17, 2022
1 parent 5c4d476 commit 640e98f
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 30 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Updated scripting-addition to support macOS Ventura 13.0.0 [#1297](https://github.com/koekeishiya/yabai/issues/1297)
- Properly escape application name when returned in window queries [#1489](https://github.com/koekeishiya/yabai/issues/1489)
- Remove window tags used for debugging purposes from result of window query because it could cause a crash under certain conditions when a window closes [#1475](https://github.com/koekeishiya/yabai/issues/1475)
- Change window placement of warp command to be more natural when warping windows within the same space [#1435](https://github.com/koekeishiya/yabai/issues/1435)

## [5.0.1] - 2022-09-26
### Changed
Expand Down
65 changes: 35 additions & 30 deletions src/view.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,41 +136,46 @@ static inline float window_node_get_gap(struct view *view)
}

#define area_ax_truncate(a) \
a.x = (int)(a.x + 0.5f); \
a.y = (int)(a.y + 0.5f); \
a.w = (int)(a.w + 0.5f); \
a.h = (int)(a.h + 0.5f);
a->x = (int)(a->x + 0.5f); \
a->y = (int)(a->y + 0.5f); \
a->w = (int)(a->w + 0.5f); \
a->h = (int)(a->h + 0.5f);

static void area_make_pair(struct view *view, struct window_node *node)
static void area_make_pair(enum window_node_split split, float gap, float ratio, struct area *parent_area, struct area *left_area, struct area *right_area)
{
enum window_node_split split = window_node_get_split(node);
float ratio = window_node_get_ratio(node);
float gap = window_node_get_gap(view);

if (split == SPLIT_Y) {
node->left->area = node->area;
node->left->area.w *= ratio;
node->left->area.w -= gap;

node->right->area = node->area;
node->right->area.x += (node->area.w * ratio);
node->right->area.w *= (1 - ratio);
node->right->area.x += gap;
node->right->area.w -= gap;
*left_area = *parent_area;
left_area->w *= ratio;
left_area->w -= gap;

*right_area = *parent_area;
right_area->x += (parent_area->w * ratio);
right_area->w *= (1 - ratio);
right_area->x += gap;
right_area->w -= gap;
} else {
node->left->area = node->area;
node->left->area.h *= ratio;
node->left->area.h -= gap;
*left_area = *parent_area;
left_area->h *= ratio;
left_area->h -= gap;

node->right->area = node->area;
node->right->area.y += (node->area.h * ratio);
node->right->area.h *= (1 - ratio);
node->right->area.y += gap;
node->right->area.h -= gap;
*right_area = *parent_area;
right_area->y += (parent_area->h * ratio);
right_area->h *= (1 - ratio);
right_area->y += gap;
right_area->h -= gap;
}

area_ax_truncate(node->left->area);
area_ax_truncate(node->right->area);
area_ax_truncate(left_area);
area_ax_truncate(right_area);
}

static void area_make_pair_for_node(struct view *view, struct window_node *node)
{
enum window_node_split split = window_node_get_split(node);
float ratio = window_node_get_ratio(node);
float gap = window_node_get_gap(view);

area_make_pair(split, gap, ratio, &node->area, &node->left->area, &node->right->area);

node->split = split;
node->ratio = ratio;
Expand Down Expand Up @@ -283,13 +288,13 @@ static void window_node_split(struct view *view, struct window_node *node, struc
node->right = right;
node->zoom = NULL;

area_make_pair(view, node);
area_make_pair_for_node(view, node);
}

void window_node_update(struct view *view, struct window_node *node)
{
if (window_node_is_intermediate(node)) {
area_make_pair(view, node->parent);
area_make_pair_for_node(view, node->parent);
}

if (window_node_is_leaf(node)) {
Expand Down
33 changes: 33 additions & 0 deletions src/window_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -1680,6 +1680,31 @@ enum window_op_error window_manager_warp_window(struct space_manager *sm, struct
}
} else {
if (a_view->sid == b_view->sid) {

//
// :NaturalWarp
//
// NOTE(koekeishiya): Precalculate both target areas and select the one that has the closest distance to the source area.
// This allows the warp to feel more natural in terms of where the window is placed on screen, however, this is only utilized
// for warp operations where both operands belong to the same space. There may be a better system to handle this if/when multiple
// monitors should be supported.
//

struct area cf, cs;
area_make_pair(window_node_get_split(b_node), window_node_get_gap(b_view), window_node_get_ratio(b_node), &b_node->area, &cf, &cs);

CGPoint ca = { (int)(0.5f + a_node->area.x + a_node->area.w / 2.0f), (int)(0.5f + a_node->area.y + a_node->area.h / 2.0f) };
float dcf = powf((ca.x - (int)(0.5f + cf.x + cf.w / 2.0f)), 2.0f) + powf((ca.y - (int)(0.5f + cf.y + cf.h / 2.0f)), 2.0f);
float dcs = powf((ca.x - (int)(0.5f + cs.x + cs.w / 2.0f)), 2.0f) + powf((ca.y - (int)(0.5f + cs.y + cs.h / 2.0f)), 2.0f);

if (dcf < dcs) {
b_node->child = CHILD_FIRST;
} else if (dcf > dcs) {
b_node->child = CHILD_SECOND;
} else {
b_node->child = window_node_is_left_child(a_node) ? CHILD_FIRST : CHILD_SECOND;
}

struct window_node *a_node_rm = view_remove_window_node(a_view, a);
struct window_node *a_node_add = view_add_window_node_with_insertion_point(b_view, a, b->id);

Expand All @@ -1703,6 +1728,14 @@ enum window_op_error window_manager_warp_window(struct space_manager *sm, struct
}
}

//
// :NaturalWarp
//
// TODO(koekeishiya): Warp operations with operands that belong to different monitors does not yet implement a heuristic to select
// the target area that feels the most natural in terms of where the window is placed on screen. Is it possible to do better when
// warping between spaces that belong to the same monitor as well??
//

space_manager_untile_window(sm, a_view, a);
window_manager_remove_managed_window(wm, a->id);
window_manager_add_managed_window(wm, a, b_view);
Expand Down

0 comments on commit 640e98f

Please # to comment.