From d87e6c0f773e189a3a62b2d066b982b3a4e2bd56 Mon Sep 17 00:00:00 2001 From: Bastien Dejean Date: Tue, 28 Jul 2020 11:14:28 +0200 Subject: [PATCH] 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. --- doc/bspwm.1 | 14 ++++++------- doc/bspwm.1.asciidoc | 8 +++---- examples/sxhkdrc | 8 +++---- src/query.c | 19 ++++++++++++++++- src/query.h | 1 + src/tree.c | 50 ++++++++++++++++++++++++++++++++++++++++---- src/tree.h | 2 ++ src/window.c | 34 +++++++++++++++++++++--------- 8 files changed, 106 insertions(+), 30 deletions(-) diff --git a/doc/bspwm.1 b/doc/bspwm.1 index 9c3e99f..b5171be 100644 --- a/doc/bspwm.1 +++ b/doc/bspwm.1 @@ -2,12 +2,12 @@ .\" Title: bspwm .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" 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 diff --git a/doc/bspwm.1.asciidoc b/doc/bspwm.1.asciidoc index 0923f94..9d2a42b 100644 --- a/doc/bspwm.1.asciidoc +++ b/doc/bspwm.1.asciidoc @@ -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. :: Selects the node with the given ID. diff --git a/examples/sxhkdrc b/examples/sxhkdrc index 0e5ea5a..7528afb 100644 --- a/examples/sxhkdrc +++ b/examples/sxhkdrc @@ -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} diff --git a/src/query.c b/src/query.c index c3a6077..23ae367 100644 --- a/src/query.c +++ b/src/query.c @@ -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) { diff --git a/src/query.h b/src/query.h index 9d87e5b..a6bca75 100644 --- a/src/query.h +++ b/src/query.h @@ -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); diff --git a/src/tree.c b/src/tree.c index 127da6d..c9f55bd 100644 --- a/src/tree.c +++ b/src/tree.c @@ -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; diff --git a/src/tree.h b/src/tree.h index c4d1d0b..5a83a01 100644 --- a/src/tree.h +++ b/src/tree.h @@ -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); diff --git a/src/window.c b/src/window.c index 1f5738f..9b85016 100644 --- a/src/window.c +++ b/src/window.c @@ -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; + 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; + } + } } - 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; + } 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; } } } -- 2.44.0