Don't confine the DIR descriptor

This commit is contained in:
Bastien Dejean 2016-04-22 12:32:10 +02:00
parent 3b0fc10531
commit f50f1f9b21
8 changed files with 99 additions and 156 deletions

View file

@ -23,6 +23,7 @@
*/
#include <math.h>
#include "types.h"
#include "geometry.h"
double distance(xcb_point_t a, xcb_point_t b)
@ -41,6 +42,35 @@ unsigned int area(xcb_rectangle_t r)
return r.width * r.height;
}
xcb_point_t center(xcb_rectangle_t r)
{
return (xcb_point_t) {r.x + r.width/2, r.y + r.height/2};
}
double rdistance(xcb_rectangle_t r1, xcb_rectangle_t r2)
{
return distance(center(r1), center(r2));
}
bool on_dir_side(xcb_rectangle_t r1, xcb_rectangle_t r2, direction_t dir)
{
switch (dir) {
case DIR_NORTH:
return (r2.y + r2.height) <= r1.y;
break;
case DIR_WEST:
return (r2.x + r2.width) <= r1.x;
break;
case DIR_SOUTH:
return r2.y >= (r1.y + r1.height);
break;
case DIR_EAST:
return r2.x >= (r1.x + r1.width);
break;
}
}
bool rect_eq(xcb_rectangle_t a, xcb_rectangle_t b)
{
return (a.x == b.x && a.y == b.y &&

View file

@ -31,6 +31,9 @@
double distance(xcb_point_t a, xcb_point_t b);
bool is_inside(xcb_point_t p, xcb_rectangle_t r);
unsigned int area(xcb_rectangle_t r);
xcb_point_t center(xcb_rectangle_t r);
double rdistance(xcb_rectangle_t r1, xcb_rectangle_t r2);
bool on_dir_side(xcb_rectangle_t r1, xcb_rectangle_t r2, direction_t dir);
bool rect_eq(xcb_rectangle_t a, xcb_rectangle_t b);
int rect_cmp(xcb_rectangle_t r1, xcb_rectangle_t r2);

View file

@ -261,11 +261,11 @@ bool history_find_monitor(history_dir_t hdi, coordinates_t *ref, coordinates_t *
return false;
}
int history_rank(desktop_t *d, node_t *n)
int history_rank(node_t *n)
{
int i = 0;
history_t *h = history_tail;
while (h != NULL && (!h->latest || h->loc.node != n || h->loc.desktop != d)) {
while (h != NULL && (!h->latest || h->loc.node != n)) {
h = h->prev;
i++;
}

View file

@ -41,6 +41,6 @@ monitor_t *history_last_monitor(monitor_t *m);
bool history_find_node(history_dir_t hdi, coordinates_t *ref, coordinates_t *dst, node_select_t sel);
bool history_find_desktop(history_dir_t hdi, coordinates_t *ref, coordinates_t *dst, desktop_select_t sel);
bool history_find_monitor(history_dir_t hdi, coordinates_t *ref, coordinates_t *dst, monitor_select_t sel);
int history_rank(desktop_t *d, node_t *n);
int history_rank(node_t *n);
#endif

View file

@ -23,6 +23,7 @@
*/
#include <limits.h>
#include <float.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@ -396,28 +397,21 @@ monitor_t *monitor_from_client(client_t *c)
monitor_t *nearest_monitor(monitor_t *m, direction_t dir, monitor_select_t sel)
{
int dmin = INT_MAX;
double dmin = DBL_MAX;
monitor_t *nearest = NULL;
xcb_rectangle_t rect = m->rectangle;
for (monitor_t *f = mon_head; f != NULL; f = f->next) {
if (f == m) {
continue;
}
coordinates_t loc = {f, NULL, NULL};
if (!monitor_matches(&loc, &loc, sel)) {
xcb_rectangle_t r = f->rectangle;
if (f == m ||
!monitor_matches(&loc, &loc, sel) ||
!on_dir_side(rect, r, dir)) {
continue;
}
xcb_rectangle_t r = f->rectangle;
if ((dir == DIR_WEST && r.x < rect.x) ||
(dir == DIR_EAST && r.x >= (rect.x + rect.width)) ||
(dir == DIR_NORTH && r.y < rect.y) ||
(dir == DIR_SOUTH && r.y >= (rect.y + rect.height))) {
int d = abs((r.x + r.width / 2) - (rect.x + rect.width / 2)) +
abs((r.y + r.height / 2) - (rect.y + rect.height / 2));
if (d < dmin) {
dmin = d;
nearest = f;
}
double d = rdistance(rect, r);
if (d < dmin) {
dmin = d;
nearest = f;
}
}
return nearest;

View file

@ -401,7 +401,7 @@ int node_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
cycle_dir_t cyc;
history_dir_t hdi;
if (parse_direction(desc, &dir)) {
dst->node = nearest_neighbor(ref->monitor, ref->desktop, ref->node, dir, sel);
find_nearest_neighbor(ref, dst, dir, sel);
} else if (parse_cycle_direction(desc, &cyc)) {
find_closest_node(ref, dst, cyc, sel);
} else if (parse_history_direction(desc, &hdi)) {

180
tree.c
View file

@ -861,23 +861,6 @@ node_t *find_fence(node_t *n, direction_t dir)
return NULL;
}
node_t *nearest_neighbor(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, node_select_t sel)
{
if (n == NULL || (n->client != NULL && IS_FULLSCREEN(n->client)) ||
(d->layout == LAYOUT_MONOCLE && (n->client != NULL && IS_TILED(n->client)))) {
return NULL;
}
node_t *nearest = NULL;
if (history_aware_focus) {
nearest = nearest_from_history(m, d, n, dir, sel);
}
if (nearest == NULL) {
nearest = nearest_from_distance(m, d, n, dir, sel);
}
return nearest;
}
/* returns *true* if *a* is a child of *b* */
bool is_child(node_t *a, node_t *b)
{
@ -931,111 +914,70 @@ node_t *find_by_id_in(node_t *r, uint32_t id)
}
}
node_t *nearest_from_history(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, node_select_t sel)
void find_nearest_neighbor(coordinates_t *ref, coordinates_t *dst, direction_t dir, node_select_t sel)
{
if (n == NULL || (n->client != NULL && !IS_TILED(n->client))) {
return NULL;
if (ref->node == NULL) {
return;
}
node_t *target = find_fence(n, dir);
if (target == NULL) {
return NULL;
}
if (dir == DIR_NORTH || dir == DIR_WEST) {
target = target->first_child;
} else if (dir == DIR_SOUTH || dir == DIR_EAST) {
target = target->second_child;
if (history_aware_focus) {
nearest_from_history(ref, dst, dir, sel);
}
node_t *nearest = NULL;
int min_rank = INT_MAX;
coordinates_t ref = {m, d, n};
for (node_t *a = first_extrema(target); a != NULL; a = next_leaf(a, target)) {
if (a->vacant || a->client == NULL || !is_adjacent(n, a, dir) || a == n) {
continue;
}
coordinates_t loc = {m, d, a};
if (!node_matches(&loc, &ref, sel)) {
continue;
}
int rank = history_rank(d, a);
if (rank >= 0 && rank < min_rank) {
nearest = a;
min_rank = rank;
}
if (dst->node == NULL) {
nearest_from_distance(ref, dst, dir, sel);
}
return nearest;
}
node_t *nearest_from_distance(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, node_select_t sel)
void nearest_from_distance(coordinates_t *ref, coordinates_t *dst, direction_t dir, node_select_t sel)
{
if (n == NULL) {
return NULL;
}
xcb_rectangle_t rect = get_rectangle(ref->desktop, ref->node);
double md = DBL_MAX;
node_t *target = NULL;
if (n->client == NULL || IS_TILED(n->client)) {
target = find_fence(n, dir);
if (target == NULL) {
return NULL;
}
if (dir == DIR_NORTH || dir == DIR_WEST) {
target = target->first_child;
} else if (dir == DIR_SOUTH || dir == DIR_EAST) {
target = target->second_child;
}
} else {
target = d->root;
}
node_t *nearest = NULL;
direction_t dir2 = DIR_NORTH;
xcb_point_t pt;
xcb_point_t pt2;
get_side_handle(d, n, dir, &pt);
get_opposite(dir, &dir2);
double ds = DBL_MAX;
coordinates_t ref = {m, d, n};
for (node_t *a = first_extrema(target); a != NULL; a = next_leaf(a, target)) {
coordinates_t loc = {m, d, a};
if (a == n ||
a->client == NULL ||
a->hidden ||
!node_matches(&loc, &ref, sel) ||
(n->client != NULL && (IS_TILED(a->client) != IS_TILED(n->client))) ||
(IS_TILED(a->client) && !is_adjacent(n, a, dir))) {
continue;
}
get_side_handle(d, a, dir2, &pt2);
double ds2 = distance(pt, pt2);
if (ds2 < ds) {
ds = ds2;
nearest = a;
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
desktop_t *d = m->desk;
for (node_t *f = first_extrema(d->root); f != NULL; f = next_leaf(f, d->root)) {
coordinates_t loc = {m, d, f};
xcb_rectangle_t r = get_rectangle(d, f);
if (f == ref->node ||
f->client == NULL ||
f->hidden ||
!node_matches(&loc, ref, sel) ||
!on_dir_side(rect, r, dir)) {
continue;
}
double fd = rdistance(rect, r);
if (fd < md) {
md = fd;
*dst = loc;
}
}
}
return nearest;
}
void get_opposite(direction_t src, direction_t *dst)
void nearest_from_history(coordinates_t *ref, coordinates_t *dst, direction_t dir, node_select_t sel)
{
switch (src) {
case DIR_EAST:
*dst = DIR_WEST;
break;
case DIR_SOUTH:
*dst = DIR_NORTH;
break;
case DIR_WEST:
*dst = DIR_EAST;
break;
case DIR_NORTH:
*dst = DIR_SOUTH;
break;
xcb_rectangle_t rect = get_rectangle(ref->desktop, ref->node);
int mr = INT_MAX;
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
desktop_t *d = m->desk;
for (node_t *f = first_extrema(d->root); f != NULL; f = next_leaf(f, d->root)) {
coordinates_t loc = {m, d, f};
xcb_rectangle_t r = get_rectangle(d, f);
if (f == ref->node ||
f->client == NULL ||
f->hidden ||
!node_matches(&loc, ref, sel) ||
!on_dir_side(rect, r, dir)) {
continue;
}
int fr = history_rank(f);
if (fr >= 0 && fr < mr) {
*dst = loc;
mr = fr;
}
}
}
}
@ -1974,30 +1916,6 @@ xcb_rectangle_t get_rectangle(desktop_t *d, node_t *n)
}
}
void get_side_handle(desktop_t *d, node_t *n, direction_t dir, xcb_point_t *pt)
{
xcb_rectangle_t rect = get_rectangle(d, n);
switch (dir) {
case DIR_EAST:
pt->x = rect.x + rect.width;
pt->y = rect.y + (rect.height / 2);
break;
case DIR_SOUTH:
pt->x = rect.x + (rect.width / 2);
pt->y = rect.y + rect.height;
break;
case DIR_WEST:
pt->x = rect.x;
pt->y = rect.y + (rect.height / 2);
break;
case DIR_NORTH:
pt->x = rect.x + (rect.width / 2);
pt->y = rect.y;
break;
}
}
void listen_enter_notify(node_t *n, bool enable)
{
uint32_t mask = CLIENT_EVENT_MASK | (enable ? XCB_EVENT_MASK_ENTER_WINDOW : 0);

8
tree.h
View file

@ -59,14 +59,13 @@ node_t *next_tiled_leaf(node_t *n, node_t *r);
node_t *prev_tiled_leaf(node_t *n, node_t *r);
bool is_adjacent(node_t *a, node_t *b, direction_t dir);
node_t *find_fence(node_t *n, direction_t dir);
node_t *nearest_neighbor(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, node_select_t sel);
bool is_child(node_t *a, node_t *b);
bool is_descendant(node_t *a, node_t *b);
bool find_by_id(uint32_t id, coordinates_t *loc);
node_t *find_by_id_in(node_t *r, uint32_t id);
node_t *nearest_from_history(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, node_select_t sel);
node_t *nearest_from_distance(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, node_select_t sel);
void get_opposite(direction_t src, direction_t *dst);
void find_nearest_neighbor(coordinates_t *ref, coordinates_t *dst, direction_t dir, node_select_t sel);
void nearest_from_distance(coordinates_t *ref, coordinates_t *dst, direction_t dir, node_select_t sel);
void nearest_from_history(coordinates_t *ref, coordinates_t *dst, direction_t dir, node_select_t sel);
unsigned int node_area(desktop_t *d, node_t *n);
int tiled_count(node_t *n);
node_t *find_biggest(monitor_t *m, desktop_t *d, node_t *n, node_select_t sel);
@ -106,7 +105,6 @@ void set_locked(monitor_t *m, desktop_t *d, node_t *n, bool value);
void set_urgent(monitor_t *m, desktop_t *d, node_t *n, bool value);
bool contains(xcb_rectangle_t a, xcb_rectangle_t b);
xcb_rectangle_t get_rectangle(desktop_t *d, node_t *n);
void get_side_handle(desktop_t *d, node_t *n, direction_t dir, xcb_point_t *pt);
void listen_enter_notify(node_t *n, bool enable);
unsigned int sticky_count(node_t *n);