Generalize a few node descriptors

- `next` and `prev` might now return any node in the context of a
  depth-first in-order tree traversal.
- `biggest`, `smallest` and `pointed` now return leaves instead of
  windows. In particular, `pointed` can now be used to get the id of a
  pointed receptacle.

Fixes #1113.
This commit is contained in:
Bastien Dejean 2020-07-28 11:14:28 +02:00
parent a54ab707cf
commit d87e6c0f77
8 changed files with 107 additions and 31 deletions

View file

@ -2,12 +2,12 @@
.\" Title: bspwm
.\" Author: [see the "Author" section]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
.\" Date: 07/27/2020
.\" Date: 07/28/2020
.\" Manual: Bspwm Manual
.\" Source: Bspwm 0.9.9-25-g8f41d79
.\" Source: Bspwm 0.9.9-26-ga54ab70
.\" Language: English
.\"
.TH "BSPWM" "1" "07/27/2020" "Bspwm 0\&.9\&.9\-25\-g8f41d79" "Bspwm Manual"
.TH "BSPWM" "1" "07/28/2020" "Bspwm 0\&.9\&.9\-26\-ga54ab70" "Bspwm Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@ -135,7 +135,7 @@ Selects the window in the given (spacial) direction relative to the reference no
.PP
\fICYCLE_DIR\fR
.RS 4
Selects the window in the given (cyclic) direction relative to the reference node\&.
Selects the node in the given (cyclic) direction relative to the reference node within a depth\-first in\-order traversal of the tree\&.
.RE
.PP
\fIPATH\fR
@ -180,17 +180,17 @@ Selects the currently focused node\&.
.PP
pointed
.RS 4
Selects the window under the pointer\&.
Selects the leaf under the pointer\&.
.RE
.PP
biggest
.RS 4
Selects the biggest window\&.
Selects the biggest leaf\&.
.RE
.PP
smallest
.RS 4
Selects the smallest window\&.
Selects the smallest leaf\&.
.RE
.PP
<node_id>

View file

@ -98,7 +98,7 @@ Descriptors
Selects the window in the given (spacial) direction relative to the reference node.
'CYCLE_DIR'::
Selects the window in the given (cyclic) direction relative to the reference node.
Selects the node in the given (cyclic) direction relative to the reference node within a depth-first in-order traversal of the tree.
'PATH'::
Selects the node at the given path.
@ -125,13 +125,13 @@ focused::
Selects the currently focused node.
pointed::
Selects the window under the pointer.
Selects the leaf under the pointer.
biggest::
Selects the biggest window.
Selects the biggest leaf.
smallest::
Selects the smallest window.
Selects the smallest leaf.
<node_id>::
Selects the node with the given ID.

View file

@ -34,9 +34,9 @@ super + m
super + y
bspc node newest.marked.local -n newest.!automatic.local
# swap the current node and the biggest node
# swap the current node and the biggest window
super + g
bspc node -s biggest
bspc node -s biggest.window
#
# state/flags
@ -62,9 +62,9 @@ super + {_,shift + }{h,j,k,l}
super + {p,b,comma,period}
bspc node -f @{parent,brother,first,second}
# focus the next/previous node in the current desktop
# focus the next/previous window in the current desktop
super + {_,shift + }c
bspc node -f {next,prev}.local
bspc node -f {next,prev}.local.!hidden.window
# focus the next/previous desktop in the current monitor
super + bracket{left,right}

View file

@ -570,7 +570,7 @@ int node_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
} else if (streq("pointed", desc)) {
xcb_window_t win = XCB_NONE;
query_pointer(&win, NULL);
if (locate_window(win, dst) && node_matches(dst, ref, &sel)) {
if (locate_leaf(win, dst) && node_matches(dst, ref, &sel)) {
return SELECTOR_OK;
} else {
return SELECTOR_INVALID;
@ -882,6 +882,23 @@ end:
return SELECTOR_OK;
}
bool locate_leaf(xcb_window_t win, coordinates_t *loc)
{
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
if (n->id == win) {
loc->monitor = m;
loc->desktop = d;
loc->node = n;
return true;
}
}
}
}
return false;
}
bool locate_window(xcb_window_t win, coordinates_t *loc)
{
for (monitor_t *m = mon_head; m != NULL; m = m->next) {

View file

@ -77,6 +77,7 @@ monitor_select_t make_monitor_select(void);
int node_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst);
int desktop_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst);
int monitor_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst);
bool locate_leaf(xcb_window_t win, coordinates_t *loc);
bool locate_window(xcb_window_t win, coordinates_t *loc);
bool locate_desktop(char *name, coordinates_t *loc);
bool locate_monitor(char *name, coordinates_t *loc);

View file

@ -841,6 +841,48 @@ node_t *first_focusable_leaf(node_t *n)
return NULL;
}
node_t *next_node(node_t *n)
{
if (n == NULL) {
return NULL;
}
if (n->second_child != NULL) {
return first_extrema(n->second_child);
} else {
node_t *p = n;
while (p != NULL && is_second_child(p)) {
p = p->parent;
}
if (is_first_child(p)) {
return p->parent;
} else {
return NULL;
}
}
}
node_t *prev_node(node_t *n)
{
if (n == NULL) {
return NULL;
}
if (n->first_child != NULL) {
return second_extrema(n->first_child);
} else {
node_t *p = n;
while (p != NULL && is_first_child(p)) {
p = p->parent;
}
if (is_second_child(p)) {
return p->parent;
} else {
return NULL;
}
}
}
node_t *next_leaf(node_t *n, node_t *r)
{
if (n == NULL) {
@ -1097,7 +1139,7 @@ void find_by_area(area_peak_t ap, coordinates_t *ref, coordinates_t *dst, node_s
for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
for (node_t *f = first_extrema(d->root); f != NULL; f = next_leaf(f, d->root)) {
coordinates_t loc = {m, d, f};
if (f->client == NULL || f->vacant || !node_matches(&loc, ref, sel)) {
if (f->vacant || !node_matches(&loc, ref, sel)) {
continue;
}
unsigned int f_area = node_area(d, f);
@ -1618,7 +1660,7 @@ bool find_closest_node(coordinates_t *ref, coordinates_t *dst, cycle_dir_t dir,
monitor_t *m = ref->monitor;
desktop_t *d = ref->desktop;
node_t *n = ref->node;
n = (dir == CYCLE_PREV ? prev_leaf(n, d->root) : next_leaf(n, d->root));
n = (dir == CYCLE_PREV ? prev_node(n) : next_node(n));
#define HANDLE_BOUNDARIES(m, d, n) \
while (n == NULL) { \
@ -1639,11 +1681,11 @@ bool find_closest_node(coordinates_t *ref, coordinates_t *dst, cycle_dir_t dir,
while (n != ref->node) {
coordinates_t loc = {m, d, n};
if (n->client != NULL && !n->hidden && node_matches(&loc, ref, sel)) {
if (node_matches(&loc, ref, sel)) {
*dst = loc;
return true;
}
n = (dir == CYCLE_PREV ? prev_leaf(n, d->root) : next_leaf(n, d->root));
n = (dir == CYCLE_PREV ? prev_node(n) : next_node(n));
HANDLE_BOUNDARIES(m, d, n);
if (ref->node == NULL && d == ref->desktop) {
break;

View file

@ -56,6 +56,8 @@ node_t *brother_tree(node_t *n);
node_t *first_extrema(node_t *n);
node_t *second_extrema(node_t *n);
node_t *first_focusable_leaf(node_t *n);
node_t *next_node(node_t *n);
node_t *prev_node(node_t *n);
node_t *next_leaf(node_t *n, node_t *r);
node_t *prev_leaf(node_t *n, node_t *r);
node_t *next_tiled_leaf(node_t *n, node_t *r);

View file

@ -733,18 +733,32 @@ void query_pointer(xcb_window_t *win, xcb_point_t *pt)
if (qpr != NULL) {
if (win != NULL) {
*win = qpr->child;
xcb_point_t pt = {qpr->root_x, qpr->root_y};
for (stacking_list_t *s = stack_tail; s != NULL; s = s->prev) {
if (!s->node->client->shown || s->node->hidden) {
continue;
}
xcb_rectangle_t rect = get_rectangle(NULL, NULL, s->node);
if (is_inside(pt, rect)) {
if (s->node->id == qpr->child || is_presel_window(qpr->child)) {
*win = s->node->id;
if (qpr->child == XCB_NONE) {
xcb_point_t mpt = (xcb_point_t) {qpr->root_x, qpr->root_y};
monitor_t *m = monitor_from_point(mpt);
if (m != NULL) {
desktop_t *d = m->desk;
for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
if (n->client == NULL && is_inside(mpt, get_rectangle(m, d, n))) {
*win = n->id;
break;
}
}
}
} else {
*win = qpr->child;
xcb_point_t pt = {qpr->root_x, qpr->root_y};
for (stacking_list_t *s = stack_tail; s != NULL; s = s->prev) {
if (!s->node->client->shown || s->node->hidden) {
continue;
}
xcb_rectangle_t rect = get_rectangle(NULL, NULL, s->node);
if (is_inside(pt, rect)) {
if (s->node->id == qpr->child || is_presel_window(qpr->child)) {
*win = s->node->id;
}
break;
}
break;
}
}
}