diff --git a/src/action.c b/src/action.c index 204f9775..32245f10 100644 --- a/src/action.c +++ b/src/action.c @@ -673,73 +673,108 @@ run_if_action(struct view *view, struct server *server, struct action *action) return !strcmp(branch, "then"); } +static int +rightmost_visible_point(struct server *server, struct view *view) +{ + struct output *output = view->output; + struct wlr_box usable = output_usable_area_in_layout_coords(output); + struct wlr_box o_usable; + struct output *o; + int rightmost_point = usable.x + usable.width; + int cy = view->current.y + view->current.height/2; + wl_list_for_each(o, &server->outputs, link) { + if (!output_is_usable(o)) { + continue; + } + o_usable = output_usable_area_in_layout_coords(o); + if (o_usable.x >= rightmost_point + && o_usable.y <= cy + && o_usable.y + o_usable.height >= cy) { + rightmost_point = o_usable.x + o_usable.width; + } + } + return rightmost_point; +} + +static int +lowest_visible_point(struct server *server, struct view *view) +{ + struct output *output = view->output; + struct wlr_box usable = output_usable_area_in_layout_coords(output); + struct wlr_box o_usable; + struct output *o; + int lowest_point = usable.y + usable.height; + int cx = view->current.x + view->current.width/2; + wl_list_for_each(o, &server->outputs, link) { + if (!output_is_usable(o)) { + continue; + } + o_usable = output_usable_area_in_layout_coords(o); + if (o_usable.y >= lowest_point + && o_usable.x <= cx + && o_usable.x + o_usable.width >= cx) { + lowest_point = o_usable.y + o_usable.height; + } + } + return lowest_point; +} + static struct view* directional_target_window(struct view *view, struct server *server, enum view_edge direction, bool wrap) { - int dx, dy, distance, distance_wrap; + assert(view); struct view *v; - struct output *v_output; - struct wlr_box v_usable; struct view *closest_view = NULL; struct view *closest_view_wrap = NULL; - int min_distance = INT_MAX; - int min_distance_wrap = INT_MAX; struct output *output = view->output; struct wlr_box usable = output_usable_area_in_layout_coords(output); - int cx = view->current.x + view->current.width / 2; - int cy = view->current.y + view->current.height / 2; - assert(view); + float dx, dy, distance, distance_wrap; + int min_distance = INT_MAX; + int min_distance_wrap = INT_MAX; for_each_view(v, &server->views, LAB_VIEW_CRITERIA_CURRENT_WORKSPACE) { if (v->minimized) { continue; } - v_output = v->output; - v_usable = output_usable_area_in_layout_coords(v_output); - dx = v->current.x + v->current.width/2 - cx; - dy = v->current.y + v->current.height/2 - cy; - distance = dx * dx + dy * dy; + distance = INT_MAX; distance_wrap = INT_MAX; + dx = v->current.x + v->current.width/2. + - view->current.x - view->current.width/2.; + dy = v->current.y + v->current.height/2. + - view->current.y - view->current.height/2.; switch (direction) { case VIEW_EDGE_LEFT: - if (dx == 0) { - continue; - } - if (dx > 0) { - distance = INT_MAX; - dx = v_usable.x + v_usable.width - dx; - distance_wrap = dx * dx + dy * dy; + if (dx < 0 && dy*dy/(dx*dx) < 2) { + distance = (dx*dx + dy*dy) * (1 + dy*dy/(dx*dx)); + } else if (dx > 0 && dy*dy/(dx*dx) < 2) { + dx = rightmost_visible_point(server, v) - dx; + distance_wrap = (dx*dx + dy*dy) * (1 + dy*dy/(dx*dx)); } break; case VIEW_EDGE_RIGHT: - if (dx == 0) { - continue; - } - if (dx < 0) { - distance = INT_MAX; + if (dx > 0 && dy*dy/(dx*dx) < 2) { + distance = (dx*dx + dy*dy) * (1 + dy*dy/(dx*dx)); + } else if (dx < 0 && dy*dy/(dx*dx) < 2) { dx = usable.x + usable.width + dx; - distance_wrap = dx * dx + dy * dy; + distance_wrap = (dx*dx + dy*dy) * (1 + dy*dy/(dx*dx)); } + break; case VIEW_EDGE_UP: - if (dy == 0) { - continue; - } - if (dy > 0) { - distance = INT_MAX; - dy = v_usable.y + v_usable.height - dy; - distance_wrap = dx * dx + dy * dy; + if (dy < 0 && dx*dx/(dy*dy) < 2) { + distance = (dx * dx + dy * dy) * (1 + dx*dx/(dy*dy)); + } else if (dy > 0 && dx*dx/(dy*dy) < 2) { + dy = lowest_visible_point(server, v) - dy; + distance_wrap = (dx*dx + dy*dy) * (1 + dx*dx/(dy*dy)); } break; case VIEW_EDGE_DOWN: - if (dy == 0) { - continue; - } - if (dy < 0) { - distance = INT_MAX; + if (dy > 0 && dx*dx/(dy*dy) < 2) { + distance = (dx*dx + dy*dy) * (1 + dx*dx/(dy*dy)); + } else if (dy < 0 && dx*dx/(dy*dy) < 2) { dy = usable.y + usable.height + dy; - distance_wrap = dx * dx + dy * dy; + distance_wrap = (dx*dx + dy*dy) * (1 + dx*dx/(dy*dy)); } break; default: @@ -756,7 +791,7 @@ directional_target_window(struct view *view, struct server *server, if (closest_view) { return closest_view; } - if (closest_view_wrap && wrap) { + if (wrap && closest_view_wrap) { return closest_view_wrap; } return NULL;