]> git.lizzy.rs Git - bspwm.git/commitdiff
Add node flag: hidden
authorBastien Dejean <nihilhill@gmail.com>
Sat, 16 Apr 2016 16:13:31 +0000 (18:13 +0200)
committerBastien Dejean <nihilhill@gmail.com>
Sat, 16 Apr 2016 16:13:31 +0000 (18:13 +0200)
Fixes #229.

15 files changed:
bspwm.c
doc/TODO.md
doc/bspwm.1
doc/bspwm.1.asciidoc
events.c
history.c
messages.c
parse.c
query.c
restore.c
rule.c
tree.c
tree.h
types.h
window.c

diff --git a/bspwm.c b/bspwm.c
index b7a30fc9258f937d9f7f26d1c8ed6cc5312baacb..c79563d7d53152a4caa9deffb7accb2c233580e6 100644 (file)
--- a/bspwm.c
+++ b/bspwm.c
@@ -248,6 +248,7 @@ void setup(void)
                                  ewmh->_NET_CLOSE_WINDOW,
                                  ewmh->_NET_WM_DESKTOP,
                                  ewmh->_NET_WM_STATE,
+                                 ewmh->_NET_WM_STATE_HIDDEN,
                                  ewmh->_NET_WM_STATE_FULLSCREEN,
                                  ewmh->_NET_WM_STATE_BELOW,
                                  ewmh->_NET_WM_STATE_ABOVE,
index 602c175efc746760ef86f696016edf0cfb7bf3ca..73b1f9ec403f3f8476236a38033dd31b6a1a624a 100644 (file)
@@ -1,3 +1,2 @@
-- Add support for showing/hiding nodes.
 - Add zoom feature (view point distinct from root).
 - Use BSD `sys/{queue/tree}.h` for {list,tree} structures?
index eaa801c65febe42aee540ec380cfe28627d91077..9c84975e841f1719504390b161be92010479000b 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: bspwm
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 04/14/2016
+.\"      Date: 04/16/2016
 .\"    Manual: Bspwm Manual
-.\"    Source: Bspwm 0.9.1-26-g789cb8a
+.\"    Source: Bspwm 0.9.1-32-g828c93f
 .\"  Language: English
 .\"
-.TH "BSPWM" "1" "04/14/2016" "Bspwm 0\&.9\&.1\-26\-g789cb8a" "Bspwm Manual"
+.TH "BSPWM" "1" "04/16/2016" "Bspwm 0\&.9\&.1\-32\-g828c93f" "Bspwm Manual"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -98,7 +98,7 @@ NODE_SEL := (DIR|CYCLE_DIR|PATH|last|older|newer|focused|biggest|<node_id>)[\&.[
 
 STATE := tiled|pseudo_tiled|floating|fullscreen
 
-FLAG := urgent|sticky|private|locked
+FLAG := hidden|sticky|private|locked|urgent
 
 LAYER := below|normal|above
 
@@ -243,7 +243,7 @@ Only consider windows in or not in the given state\&.
 Only consider windows that have or don\(cqt have the same class as the current window\&.
 .RE
 .PP
-[!](private|urgent|sticky|locked)
+[!](hidden|sticky|private|locked|urgent)
 .RS 4
 Only consider windows that have or don\(cqt have the given flag set\&.
 .RE
@@ -458,11 +458,9 @@ Fills its monitor rectangle and has no borders\&. It is send in the ABOVE layer
 .RE
 .SH "NODE FLAGS"
 .PP
-locked
+hidden
 .RS 4
-Ignores the
-\fBnode \-\-close\fR
-message\&.
+Is hidden and doesn\(cqt occupy any tiling space\&.
 .RE
 .PP
 sticky
@@ -475,6 +473,13 @@ private
 Tries to keep the same tiling position/size\&.
 .RE
 .PP
+locked
+.RS 4
+Ignores the
+\fBnode \-\-close\fR
+message\&.
+.RE
+.PP
 urgent
 .RS 4
 Has its urgency hint set\&. This flag is set externally\&.
@@ -609,7 +614,7 @@ Set the state of the selected window\&. If
 is present and the current state matches the given state, then the argument is interpreted as the last state\&.
 .RE
 .PP
-\fB\-g\fR, \fB\-\-flag\fR locked|sticky|private[=on|off]
+\fB\-g\fR, \fB\-\-flag\fR hidden|sticky|private|locked[=on|off]
 .RS 4
 Set or toggle the given flag for the selected node\&.
 .RE
@@ -887,7 +892,7 @@ rule \fICOMMANDS\fR
 \fBCommands\fR
 .RS 4
 .PP
-\fB\-a\fR, \fB\-\-add\fR (<class_name>|*)[:(<instance_name>|*)] [\fB\-o\fR|\fB\-\-one\-shot\fR] [monitor=MONITOR_SEL|desktop=DESKTOP_SEL|node=NODE_SEL] [state=STATE] [layer=LAYER] [split_dir=DIR] [split_ratio=RATIO] [(locked|sticky|private|center|follow|manage|focus|border)=(on|off)]
+\fB\-a\fR, \fB\-\-add\fR (<class_name>|*)[:(<instance_name>|*)] [\fB\-o\fR|\fB\-\-one\-shot\fR] [monitor=MONITOR_SEL|desktop=DESKTOP_SEL|node=NODE_SEL] [state=STATE] [layer=LAYER] [split_dir=DIR] [split_ratio=RATIO] [(hidden|sticky|private|locked|center|follow|manage|focus|border)=(on|off)]
 .RS 4
 Create a new rule\&.
 .RE
@@ -1290,7 +1295,7 @@ The geometry of a window changed\&.
 The state of a window changed\&.
 .RE
 .PP
-\fInode_flag <monitor_id> <desktop_id> <node_id> sticky|private|locked|urgent on|off\fR
+\fInode_flag <monitor_id> <desktop_id> <node_id> hidden|sticky|private|locked|urgent on|off\fR
 .RS 4
 One of the flags of a node changed\&.
 .RE
index 41701dc104d5b97abb1a5159bdfeb2a6abbb1b6d..adc65b42dc3c903862dfdfb5dc21d31a26676675 100644 (file)
@@ -70,7 +70,7 @@ NODE_SEL := (DIR|CYCLE_DIR|PATH|last|older|newer|focused|biggest|<node_id>)[.[!]
 
 STATE := tiled|pseudo_tiled|floating|fullscreen
 
-FLAG := urgent|sticky|private|locked
+FLAG := hidden|sticky|private|locked|urgent
 
 LAYER := below|normal|above
 
@@ -153,7 +153,7 @@ Modifiers
 [!]same_class::
        Only consider windows that have or don't have the same class as the current window.
 
-[!](private|urgent|sticky|locked)::
+[!](hidden|sticky|private|locked|urgent)::
        Only consider windows that have or don't have the given flag set.
 
 [!](below|normal|above)::
@@ -282,8 +282,8 @@ fullscreen::
 Node Flags
 ----------
 
-locked::
-       Ignores the *node --close* message.
+hidden::
+       Is hidden and doesn't occupy any tiling space.
 
 sticky::
        Stays in the focused desktop of its monitor.
@@ -291,6 +291,9 @@ sticky::
 private::
        Tries to keep the same tiling position/size.
 
+locked::
+       Ignores the *node --close* message.
+
 urgent::
        Has its urgency hint set. This flag is set externally.
 
@@ -367,7 +370,7 @@ Commands
 *-t*, *--state* [~](tiled|pseudo_tiled|floating|fullscreen)::
        Set the state of the selected window. If *~* is present and the current state matches the given state, then the argument is interpreted as the last state.
 
-*-g*, *--flag* locked|sticky|private[=on|off]::
+*-g*, *--flag* hidden|sticky|private|locked[=on|off]::
        Set or toggle the given flag for the selected node.
 
 *-l*, *--layer* below|normal|above::
@@ -521,7 +524,7 @@ rule 'COMMANDS'
 Commands
 ^^^^^^^^
 
-*-a*, *--add* (<class_name>|\*)[:(<instance_name>|\*)] [*-o*|*--one-shot*] [monitor=MONITOR_SEL|desktop=DESKTOP_SEL|node=NODE_SEL] [state=STATE] [layer=LAYER] [split_dir=DIR] [split_ratio=RATIO] [(locked|sticky|private|center|follow|manage|focus|border)=(on|off)]::
+*-a*, *--add* (<class_name>|\*)[:(<instance_name>|\*)] [*-o*|*--one-shot*] [monitor=MONITOR_SEL|desktop=DESKTOP_SEL|node=NODE_SEL] [state=STATE] [layer=LAYER] [split_dir=DIR] [split_ratio=RATIO] [(hidden|sticky|private|locked|center|follow|manage|focus|border)=(on|off)]::
        Create a new rule.
 
 *-r*, *--remove* ^<n>|head|tail|(<class_name>|\*)[:(<instance_name>|*)]...::
@@ -766,7 +769,7 @@ Events
 'node_state <monitor_id> <desktop_id> <node_id> tiled|pseudo_tiled|floating|fullscreen on|off'::
        The state of a window changed.
 
-'node_flag <monitor_id> <desktop_id> <node_id> sticky|private|locked|urgent on|off'::
+'node_flag <monitor_id> <desktop_id> <node_id> hidden|sticky|private|locked|urgent on|off'::
        One of the flags of a node changed.
 
 'node_layer <monitor_id> <desktop_id> <node_id> below|normal|above'::
index ec936238c9e3d88222833fbbda175fcf36b1a1fc..421576f1423c6524960d41387aafba8288e745bf 100644 (file)
--- a/events.c
+++ b/events.c
@@ -400,6 +400,14 @@ void handle_state(monitor_t *m, desktop_t *d, node_t *n, xcb_atom_t state, unsig
                } else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
                        set_layer(m, d, n, n->client->layer == LAYER_ABOVE ? n->client->last_layer : LAYER_ABOVE);
                }
+       } else if (state == ewmh->_NET_WM_STATE_HIDDEN) {
+               if (action == XCB_EWMH_WM_STATE_ADD) {
+                       set_hidden(m, d, n, true);
+               } else if (action == XCB_EWMH_WM_STATE_REMOVE) {
+                       set_hidden(m, d, n, false);
+               } else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
+                       set_hidden(m, d, n, !n->hidden);
+               }
        } else if (state == ewmh->_NET_WM_STATE_STICKY) {
                if (action == XCB_EWMH_WM_STATE_ADD) {
                        set_sticky(m, d, n, true);
@@ -432,7 +440,6 @@ void handle_state(monitor_t *m, desktop_t *d, node_t *n, xcb_atom_t state, unsig
        HANDLE_WM_STATE(SHADED)
        HANDLE_WM_STATE(SKIP_TASKBAR)
        HANDLE_WM_STATE(SKIP_PAGER)
-       HANDLE_WM_STATE(HIDDEN)
        }
 #undef HANDLE_WM_STATE
 }
index 7da76f79c97b80730e93406f18ef416238487447..be3665ad3e037fc7cc6634eab21acb89d5a33764 100644 (file)
--- a/history.c
+++ b/history.c
@@ -163,7 +163,8 @@ void empty_history(void)
 node_t *history_last_node(desktop_t *d, node_t *n)
 {
        for (history_t *h = history_tail; h != NULL; h = h->prev) {
-               if (h->latest && h->loc.node != NULL && !is_descendant(h->loc.node, n) && h->loc.desktop == d) {
+               if (h->latest && h->loc.node != NULL && !h->loc.node->hidden &&
+                   !is_descendant(h->loc.node, n) && h->loc.desktop == d) {
                        return h->loc.node;
                }
        }
@@ -201,6 +202,7 @@ bool history_find_node(history_dir_t hdi, coordinates_t *ref, coordinates_t *dst
                if (!h->latest ||
                    h->loc.node == NULL ||
                    h->loc.node == ref->node ||
+                   h->loc.node->hidden ||
                    !node_matches(&h->loc, ref, sel)) {
                        continue;
                }
index 85818595d16b6bba4407bfb9374381142462aca2..c8f516a7d9c7b9e400be10bb989a4224b79ea4ea 100644 (file)
@@ -312,12 +312,15 @@ void cmd_node(char **args, int num, FILE *rsp)
                                        break;
                                }
                        }
-                       if (streq("locked", key)) {
-                               set_locked(trg.monitor, trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->locked));
+                       if (streq("hidden", key)) {
+                               set_hidden(trg.monitor, trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->hidden));
+                               changed = true;
                        } else if (streq("sticky", key)) {
                                set_sticky(trg.monitor, trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->sticky));
                        } else if (streq("private", key)) {
                                set_private(trg.monitor, trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->private));
+                       } else if (streq("locked", key)) {
+                               set_locked(trg.monitor, trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->locked));
                        } else {
                                fail(rsp, "node %s: Invalid key: '%s'.\n", *(args - 1), key);
                                break;
diff --git a/parse.c b/parse.c
index aad97f749533e22aca5c8397f877030c5af91ad2..1b41259bde775bab89b0618825cb9d43f6403b46 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -441,9 +441,10 @@ bool parse_node_modifiers(char *desc, node_select_t *sel)
                GET_MOD(pseudo_tiled)
                GET_MOD(floating)
                GET_MOD(fullscreen)
-               GET_MOD(locked)
+               GET_MOD(hidden)
                GET_MOD(sticky)
                GET_MOD(private)
+               GET_MOD(locked)
                GET_MOD(urgent)
                GET_MOD(same_class)
                GET_MOD(below)
diff --git a/query.c b/query.c
index 73297d5d97a00d36b6fd0da641e77a0411897fa0..6bf3cb1cf53ab19800d145478f5168e101bb0855 100644 (file)
--- a/query.c
+++ b/query.c
@@ -118,6 +118,7 @@ void query_node(node_t *n, FILE *rsp)
                fprintf(rsp, "\"splitRatio\":%lf,", n->split_ratio);
                fprintf(rsp, "\"birthRotation\":%i,", n->birth_rotation);
                fprintf(rsp, "\"vacant\":%s,", BOOL_STR(n->vacant));
+               fprintf(rsp, "\"hidden\":%s,", BOOL_STR(n->hidden));
                fprintf(rsp, "\"sticky\":%s,", BOOL_STR(n->sticky));
                fprintf(rsp, "\"private\":%s,", BOOL_STR(n->private));
                fprintf(rsp, "\"locked\":%s,", BOOL_STR(n->locked));
@@ -162,7 +163,7 @@ void query_client(client_t *c, FILE *rsp)
                fprintf(rsp, "\"layer\":\"%s\",", LAYER_STR(c->layer));
                fprintf(rsp, "\"lastLayer\":\"%s\",", LAYER_STR(c->last_layer));
                fprintf(rsp, "\"urgent\":%s,", BOOL_STR(c->urgent));
-               fprintf(rsp, "\"visible\":%s,", BOOL_STR(c->visible));
+               fprintf(rsp, "\"shown\":%s,", BOOL_STR(c->shown));
                fprintf(rsp, "\"tiledRectangle\":");
                query_rectangle(c->tiled_rectangle, rsp);
                fprintf(rsp,",");
@@ -240,6 +241,9 @@ int query_node_ids_in(node_t *n, desktop_t *d, monitor_t *m, coordinates_t loc,
                    (sel == NULL || node_matches(&trg, &ref, *sel))) {
                        fprintf(rsp, "0x%08X\n", n->id);
                        count++;
+                       if (sel != NULL) {
+                               return count;
+                       }
                }
                count += query_node_ids_in(n->first_child, d, m, loc, sel, rsp);
                count += query_node_ids_in(n->second_child, d, m, loc, sel, rsp);
@@ -344,9 +348,10 @@ node_select_t make_node_select(void)
                .pseudo_tiled = OPTION_NONE,
                .floating = OPTION_NONE,
                .fullscreen = OPTION_NONE,
-               .locked = OPTION_NONE,
+               .hidden = OPTION_NONE,
                .sticky = OPTION_NONE,
                .private = OPTION_NONE,
+               .locked = OPTION_NONE,
                .urgent = OPTION_NONE,
                .same_class = OPTION_NONE,
                .below = OPTION_NONE,
@@ -801,6 +806,7 @@ bool node_matches(coordinates_t *loc, coordinates_t *ref, node_select_t sel)
            : sel.p == OPTION_FALSE) { \
                return false; \
        }
+       NFLAG(hidden)
        NFLAG(sticky)
        NFLAG(private)
        NFLAG(locked)
index 2b436461ad218eff6d4fa68d00d11dda8bfc91a2..0b700c10c5bef0e5d16944c030ef8a0959c187d1 100644 (file)
--- a/restore.c
+++ b/restore.c
@@ -343,6 +343,7 @@ node_t *restore_node(jsmntok_t **t, char *json)
                        RESTORE_DOUBLE(splitRatio, &n->split_ratio)
                        RESTORE_INT(birthRotation, &n->birth_rotation)
                        RESTORE_BOOL(vacant, &n->vacant)
+                       RESTORE_BOOL(hidden, &n->hidden)
                        RESTORE_BOOL(sticky, &n->sticky)
                        RESTORE_BOOL(private, &n->private)
                        RESTORE_BOOL(locked, &n->locked)
@@ -433,7 +434,7 @@ client_t *restore_client(jsmntok_t **t, char *json)
                        RESTORE_ANY(lastLayer, &c->last_layer, parse_stack_layer)
                        RESTORE_UINT(borderWidth, &c->border_width)
                        RESTORE_BOOL(urgent, &c->urgent)
-                       RESTORE_BOOL(visible, &c->visible)
+                       RESTORE_BOOL(shown, &c->shown)
                        } else if (keyeq("tiledRectangle", *t, json)) {
                                (*t)++;
                                restore_rectangle(&c->tiled_rectangle, t, json);
diff --git a/rule.c b/rule.c
index 9e2f5ef38889a73d0545427b1b55493378854e71..c6853d4c90030f5fed22eb36365e1e07d358964a 100644 (file)
--- a/rule.c
+++ b/rule.c
@@ -342,13 +342,14 @@ void parse_key_value(char *key, char *value, rule_consequence_t *csq)
                        csq->split_ratio = rat;
                }
        } else if (parse_bool(value, &v)) {
-               if (streq("locked", key))
-                       csq->locked = true;
+               if (streq("hidden", key))
+                       csq->hidden = true;
 #define SETCSQ(name) \
                else if (streq(#name, key)) \
                        csq->name = v;
                SETCSQ(sticky)
                SETCSQ(private)
+               SETCSQ(locked)
                SETCSQ(center)
                SETCSQ(follow)
                SETCSQ(manage)
diff --git a/tree.c b/tree.c
index b1bf9943d9973391c79cc06b0c96e76c245263f6..f0aac423385658503bd798ce100605f2564793ed 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -395,12 +395,11 @@ node_t *insert_node(monitor_t *m, desktop_t *d, node_t *n, node_t *f)
                        }
                        cancel_presel(m, d, f);
                }
-               if (f->vacant) {
-                       propagate_vacant_state(m, d, f);
-               }
        }
 
-       if (d->focus == NULL && !IS_RECEPTACLE(n)) {
+       propagate_flags_upward(m, d, n);
+
+       if (d->focus == NULL && is_focusable(n)) {
                d->focus = n;
        }
 
@@ -415,7 +414,7 @@ void insert_receptacle(monitor_t *m, desktop_t *d, node_t *n)
 
 bool activate_node(monitor_t *m, desktop_t *d, node_t *n)
 {
-       if (d == mon->desk || IS_RECEPTACLE(n)) {
+       if (d == mon->desk || (n != NULL && !is_focusable(n))) {
                return false;
        }
 
@@ -473,7 +472,7 @@ void transfer_sticky_nodes(monitor_t *m, desktop_t *ds, desktop_t *dd, node_t *n
 
 bool focus_node(monitor_t *m, desktop_t *d, node_t *n)
 {
-       if (IS_RECEPTACLE(n)) {
+       if (n != NULL && !is_focusable(n)) {
                return false;
        }
 
@@ -561,12 +560,16 @@ void hide_node(node_t *n)
        if (n == NULL) {
                return;
        } else {
-               if (n->presel != NULL) {
-                       window_hide(n->presel->feedback);
+               if (!n->hidden) {
+                       if (n->presel != NULL) {
+                               window_hide(n->presel->feedback);
+                       }
+                       if (n->client != NULL) {
+                               window_hide(n->id);
+                       }
                }
                if (n->client != NULL) {
-                       window_hide(n->id);
-                       n->client->visible = false;
+                       n->client->shown = false;
                }
                hide_node(n->first_child);
                hide_node(n->second_child);
@@ -578,12 +581,16 @@ void show_node(node_t *n)
        if (n == NULL) {
                return;
        } else {
-               if (n->client != NULL) {
-                       window_show(n->id);
-                       n->client->visible = true;
+               if (!n->hidden) {
+                       if (n->client != NULL) {
+                               window_show(n->id);
+                       }
+                       if (n->presel != NULL) {
+                               window_show(n->presel->feedback);
+                       }
                }
-               if (n->presel != NULL) {
-                       window_show(n->presel->feedback);
+               if (n->client != NULL) {
+                       n->client->shown = true;
                }
                show_node(n->first_child);
                show_node(n->second_child);
@@ -598,7 +605,7 @@ node_t *make_node(uint32_t id)
        node_t *n = malloc(sizeof(node_t));
        n->id = id;
        n->parent = n->first_child = n->second_child = NULL;
-       n->vacant = n->sticky = n->private = n->locked = false;
+       n->vacant = n->hidden = n->sticky = n->private = n->locked = false;
        n->split_ratio = split_ratio;
        n->split_type = TYPE_VERTICAL;
        n->birth_rotation = 0;
@@ -609,13 +616,16 @@ node_t *make_node(uint32_t id)
 
 client_t *make_client(void)
 {
-       client_t *c = calloc(1, sizeof(client_t));
+       client_t *c = malloc(sizeof(client_t));
        c->state = c->last_state = STATE_TILED;
        c->layer = c->last_layer = LAYER_NORMAL;
        snprintf(c->class_name, sizeof(c->class_name), "%s", MISSING_VALUE);
        snprintf(c->instance_name, sizeof(c->instance_name), "%s", MISSING_VALUE);
        c->border_width = border_width;
+       c->wm_flags = 0;
        c->icccm_props.input_hint = true;
+       c->icccm_props.take_focus = false;
+       c->size_hints.flags = 0;
        return c;
 }
 
@@ -661,6 +671,16 @@ void initialize_client(node_t *n)
        xcb_icccm_get_wm_normal_hints_reply(dpy, xcb_icccm_get_wm_normal_hints(dpy, win), &c->size_hints, NULL);
 }
 
+bool is_focusable(node_t *n)
+{
+       for (node_t *f = first_extrema(n); f != NULL; f = next_leaf(f, n)) {
+               if (f->client != NULL && !f->hidden) {
+                       return true;
+               }
+       }
+       return false;
+}
+
 bool is_leaf(node_t *n)
 {
        return (n != NULL && n->first_child == NULL && n->second_child == NULL);
@@ -724,7 +744,7 @@ node_t *second_extrema(node_t *n)
 node_t *first_focusable_leaf(node_t *n)
 {
        for (node_t *f = first_extrema(n); f != NULL; f = next_leaf(f, n)) {
-               if (f->client != NULL) {
+               if (f->client != NULL && !f->hidden) {
                        return f;
                }
        }
@@ -764,7 +784,7 @@ node_t *prev_leaf(node_t *n, node_t *r)
 node_t *next_tiled_leaf(node_t *n, node_t *r)
 {
        node_t *next = next_leaf(n, r);
-       if (next == NULL || (next->client != NULL && IS_TILED(next->client))) {
+       if (next == NULL || (next->client != NULL && !next->vacant)) {
                return next;
        } else {
                return next_tiled_leaf(next, r);
@@ -774,7 +794,7 @@ node_t *next_tiled_leaf(node_t *n, node_t *r)
 node_t *prev_tiled_leaf(node_t *n, node_t *r)
 {
        node_t *prev = prev_leaf(n, r);
-       if (prev == NULL || (prev->client != NULL && IS_TILED(prev->client))) {
+       if (prev == NULL || (prev->client != NULL && !prev->vacant)) {
                return prev;
        } else {
                return prev_tiled_leaf(prev, r);
@@ -1001,6 +1021,7 @@ node_t *nearest_from_distance(monitor_t *m, desktop_t *d, node_t *n, direction_t
                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))) {
@@ -1222,7 +1243,7 @@ void unlink_node(monitor_t *m, desktop_t *d, node_t *n)
                }
                free(p);
 
-               propagate_vacant_state(m, d, b);
+               propagate_flags_upward(m, d, b);
        }
 }
 
@@ -1353,10 +1374,8 @@ bool swap_nodes(monitor_t *m1, desktop_t *d1, node_t *n1, monitor_t *m2, desktop
        n1->birth_rotation = br2;
        n2->birth_rotation = br1;
 
-       if (n1->vacant != n2->vacant) {
-               propagate_vacant_state(m2, d2, n1);
-               propagate_vacant_state(m1, d1, n2);
-       }
+       propagate_flags_upward(m2, d2, n1);
+       propagate_flags_upward(m1, d1, n2);
 
        if (d1 != d2) {
                if (d1->root == n1) {
@@ -1518,7 +1537,7 @@ node_t *closest_node(monitor_t *m, desktop_t *d, node_t *n, cycle_dir_t dir, nod
        coordinates_t ref = {m, d, n};
        while (f != n) {
                coordinates_t loc = {m, d, f};
-               if (f->client != NULL && node_matches(&loc, &ref, sel)) {
+               if (f->client != NULL && !f->hidden && node_matches(&loc, &ref, sel)) {
                        return f;
                }
                f = (dir == CYCLE_PREV ? prev_leaf(f, d->root) : next_leaf(f, d->root));
@@ -1560,24 +1579,41 @@ void circulate_leaves(monitor_t *m, desktop_t *d, node_t *n, circulate_dir_t dir
        }
 }
 
-void set_vacant_state(monitor_t *m, desktop_t *d, node_t *n, bool value)
+void set_vacant(monitor_t *m, desktop_t *d, node_t *n, bool value)
+{
+       if (n->vacant == value) {
+               return;
+       }
+
+       propagate_vacant_downward(m, d, n, value);
+       propagate_vacant_upward(m, d, n);
+}
+
+void set_vacant_local(monitor_t *m, desktop_t *d, node_t *n, bool value)
 {
        n->vacant = value;
 
        if (value) {
                unrotate_brother(n);
+               cancel_presel(m, d, n);
        } else {
                rotate_brother(n);
        }
+}
 
-       if (value) {
-               cancel_presel(m, d, n);
+void propagate_vacant_downward(monitor_t *m, desktop_t *d, node_t *n, bool value)
+{
+       if (n == NULL) {
+               return;
        }
 
-       propagate_vacant_state(m, d, n);
+       set_vacant_local(m, d, n, value);
+
+       propagate_vacant_downward(m, d, n->first_child, value);
+       propagate_vacant_downward(m, d, n->second_child, value);
 }
 
-void propagate_vacant_state(monitor_t *m, desktop_t *d, node_t *n)
+void propagate_vacant_upward(monitor_t *m, desktop_t *d, node_t *n)
 {
        if (n == NULL) {
                return;
@@ -1585,13 +1621,11 @@ void propagate_vacant_state(monitor_t *m, desktop_t *d, node_t *n)
 
        node_t *p = n->parent;
 
-       while (p != NULL) {
-               p->vacant = (p->first_child->vacant && p->second_child->vacant);
-               if (p->vacant) {
-                       cancel_presel(m, d, p);
-               }
-               p = p->parent;
+       if (p != NULL) {
+               set_vacant_local(m, d, p, (p->first_child->vacant && p->second_child->vacant));
        }
+
+       propagate_vacant_upward(m, d, p);
 }
 
 bool set_layer(monitor_t *m, desktop_t *d, node_t *n, stack_layer_t l)
@@ -1679,7 +1713,7 @@ void set_floating(monitor_t *m, desktop_t *d, node_t *n, bool value)
        }
 
        cancel_presel(m, d, n);
-       set_vacant_state(m, d, n, value);
+       set_vacant(m, d, n, value);
 
        if (!value && d->focus == n) {
                neutralize_occluding_windows(m, d, n);
@@ -1697,7 +1731,7 @@ void set_fullscreen(monitor_t *m, desktop_t *d, node_t *n, bool value)
        client_t *c = n->client;
 
        cancel_presel(m, d, n);
-       set_vacant_state(m, d, n, value);
+       set_vacant(m, d, n, value);
 
        if (value) {
                c->wm_flags |= WM_FLAG_FULLSCREEN;
@@ -1732,21 +1766,91 @@ void neutralize_occluding_windows(monitor_t *m, desktop_t *d, node_t *n)
        }
 }
 
-void set_locked(monitor_t *m, desktop_t *d, node_t *n, bool value)
+void propagate_flags_upward(monitor_t *m, desktop_t *d, node_t *n)
 {
-       if (n == NULL || n->locked == value) {
+       if (n == NULL) {
                return;
        }
 
-       n->locked = value;
+       node_t *p = n->parent;
 
-       put_status(SBSC_MASK_NODE_FLAG, "node_flag 0x%08X 0x%08X 0x%08X locked %s\n", m->id, d->id, n->id, ON_OFF_STR(value));
+       if (p != NULL) {
+               set_vacant_local(m, d, p, (p->first_child->vacant && p->second_child->vacant));
+               set_hidden_local(m, d, p, (p->first_child->hidden && p->second_child->hidden));
+       }
 
-       if (n == m->desk->focus) {
-               put_status(SBSC_MASK_REPORT);
+       propagate_flags_upward(m, d, p);
+}
+
+void set_hidden(monitor_t *m, desktop_t *d, node_t *n, bool value)
+{
+       if (n == NULL || n->hidden == value) {
+               return;
+       }
+
+       bool held_focus = is_descendant(d->focus, n);
+
+       propagate_hidden_downward(m, d, n, value);
+       propagate_hidden_upward(m, d, n);
+
+       put_status(SBSC_MASK_NODE_FLAG, "node_flag 0x%08X 0x%08X 0x%08X hidden %s\n", m->id, d->id, n->id, ON_OFF_STR(value));
+
+       if (held_focus || d->focus == NULL) {
+               if (d->focus != NULL) {
+                       d->focus = NULL;
+                       draw_border(n, false, (mon == m));
+               }
+               if (d == mon->desk) {
+                       focus_node(m, d, d->focus);
+               } else {
+                       activate_node(m, d, d->focus);
+               }
+       }
+}
+
+void set_hidden_local(monitor_t *m, desktop_t *d, node_t *n, bool value)
+{
+       n->hidden = value;
+       if (n->client != NULL) {
+               window_set_visibility(n->id, !value);
+               if (IS_TILED(n->client)) {
+                       set_vacant(m, d, n, value);
+               }
+               if (value) {
+                       n->client->wm_flags |= WM_FLAG_HIDDEN;
+               } else {
+                       n->client->wm_flags &= ~WM_FLAG_HIDDEN;
+               }
        }
 }
 
+void propagate_hidden_downward(monitor_t *m, desktop_t *d, node_t *n, bool value)
+{
+       if (n == NULL) {
+               return;
+       }
+
+       set_hidden_local(m, d, n, value);
+
+       propagate_hidden_downward(m, d, n->first_child, value);
+       propagate_hidden_downward(m, d, n->second_child, value);
+}
+
+void propagate_hidden_upward(monitor_t *m, desktop_t *d, node_t *n)
+{
+       if (n == NULL) {
+               return;
+       }
+
+       node_t *p = n->parent;
+
+       if (p != NULL) {
+               set_hidden_local(m, d, p, p->first_child->hidden && p->second_child->hidden);
+       }
+
+       propagate_hidden_upward(m, d, p);
+}
+
 void set_sticky(monitor_t *m, desktop_t *d, node_t *n, bool value)
 {
        if (n == NULL || n->sticky == value) {
@@ -1797,6 +1901,21 @@ void set_private(monitor_t *m, desktop_t *d, node_t *n, bool value)
        }
 }
 
+void set_locked(monitor_t *m, desktop_t *d, node_t *n, bool value)
+{
+       if (n == NULL || n->locked == value) {
+               return;
+       }
+
+       n->locked = value;
+
+       put_status(SBSC_MASK_NODE_FLAG, "node_flag 0x%08X 0x%08X 0x%08X locked %s\n", m->id, d->id, n->id, ON_OFF_STR(value));
+
+       if (n == m->desk->focus) {
+               put_status(SBSC_MASK_REPORT);
+       }
+}
+
 void set_urgent(monitor_t *m, desktop_t *d, node_t *n, bool value)
 {
        if (value && mon->desk->focus == n) {
diff --git a/tree.h b/tree.h
index 5980a287e5628ae9d6080f936d23331292c394e7..37fcb995d280e606bcd0995a3a22ed54da90f4a8 100644 (file)
--- a/tree.h
+++ b/tree.h
@@ -44,6 +44,7 @@ void show_node(node_t *n);
 node_t *make_node(uint32_t id);
 client_t *make_client(void);
 void initialize_client(node_t *n);
+bool is_focusable(node_t *n);
 bool is_leaf(node_t *n);
 bool is_first_child(node_t *n);
 bool is_second_child(node_t *n);
@@ -86,16 +87,23 @@ bool swap_nodes(monitor_t *m1, desktop_t *d1, node_t *n1, monitor_t *m2, desktop
 bool transfer_node(monitor_t *ms, desktop_t *ds, node_t *ns, monitor_t *md, desktop_t *dd, node_t *nd);
 node_t *closest_node(monitor_t *m, desktop_t *d, node_t *n, cycle_dir_t dir, node_select_t sel);
 void circulate_leaves(monitor_t *m, desktop_t *d, node_t *n, circulate_dir_t dir);
-void set_vacant_state(monitor_t *m, desktop_t *d, node_t *n, bool value);
-void propagate_vacant_state(monitor_t *m, desktop_t *d, node_t *n);
+void set_vacant(monitor_t *m, desktop_t *d, node_t *n, bool value);
+void set_vacant_local(monitor_t *m, desktop_t *d, node_t *n, bool value);
+void propagate_vacant_downward(monitor_t *m, desktop_t *d, node_t *n, bool value);
+void propagate_vacant_upward(monitor_t *m, desktop_t *d, node_t *n);
 bool set_layer(monitor_t *m, desktop_t *d, node_t *n, stack_layer_t l);
 bool set_state(monitor_t *m, desktop_t *d, node_t *n, client_state_t s);
 void set_floating(monitor_t *m, desktop_t *d, node_t *n, bool value);
 void set_fullscreen(monitor_t *m, desktop_t *d, node_t *n, bool value);
 void neutralize_occluding_windows(monitor_t *m, desktop_t *d, node_t *n);
-void set_locked(monitor_t *m, desktop_t *d, node_t *n, bool value);
+void propagate_flags_upward(monitor_t *m, desktop_t *d, node_t *n);
+void set_hidden(monitor_t *m, desktop_t *d, node_t *n, bool value);
+void set_hidden_local(monitor_t *m, desktop_t *d, node_t *n, bool value);
+void propagate_hidden_downward(monitor_t *m, desktop_t *d, node_t *n, bool value);
+void propagate_hidden_upward(monitor_t *m, desktop_t *d, node_t *n);
 void set_sticky(monitor_t *m, desktop_t *d, node_t *n, bool value);
 void set_private(monitor_t *m, desktop_t *d, node_t *n, bool value);
+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);
diff --git a/types.h b/types.h
index 4fdeedc28710a9ae5cff951c890fd67bc4e56bad..2f8a568802533199648a9aacd0b8fdca55d70a24 100644 (file)
--- a/types.h
+++ b/types.h
@@ -148,9 +148,10 @@ typedef struct {
        option_bool_t pseudo_tiled;
        option_bool_t floating;
        option_bool_t fullscreen;
-       option_bool_t locked;
+       option_bool_t hidden;
        option_bool_t sticky;
        option_bool_t private;
+       option_bool_t locked;
        option_bool_t urgent;
        option_bool_t same_class;
        option_bool_t below;
@@ -181,7 +182,7 @@ typedef struct {
        char instance_name[3 * SMALEN / 2];
        unsigned int border_width;
        bool urgent;
-       bool visible;
+       bool shown;
        client_state_t state;
        client_state_t last_state;
        stack_layer_t layer;
@@ -209,6 +210,7 @@ struct node_t {
        presel_t *presel;
        xcb_rectangle_t rectangle;
        bool vacant;
+       bool hidden;
        bool sticky;
        bool private;
        bool locked;
@@ -309,9 +311,10 @@ typedef struct {
        double split_ratio;
        stack_layer_t *layer;
        client_state_t *state;
-       bool locked;
+       bool hidden;
        bool sticky;
        bool private;
+       bool locked;
        bool center;
        bool follow;
        bool manage;
index 3f4f3f6c5566047761797d29b5fd76c747ee06cc..f95ba211f763b1a546b5fd2ebd76bb2103e13207 100644 (file)
--- a/window.c
+++ b/window.c
@@ -167,18 +167,22 @@ void manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
                c->last_state = c->state;
        }
 
-       set_locked(m, d, n, csq->locked);
+       set_hidden(m, d, n, csq->hidden);
        set_sticky(m, d, n, csq->sticky);
        set_private(m, d, n, csq->private);
+       set_locked(m, d, n, csq->locked);
 
        arrange(m, d);
 
-       bool give_focus = (csq->focus && (d == mon->desk || csq->follow));
+       bool focused = false;
 
-       if (give_focus) {
-               focus_node(m, d, n);
-       } else if (csq->focus) {
-               activate_node(m, d, n);
+       if (!csq->hidden && csq->focus) {
+               if (d == mon->desk || csq->follow) {
+                       focused = true;
+                       focus_node(m, d, n);
+               } else {
+                       activate_node(m, d, n);
+               }
        } else {
                stack(d, n, false);
        }
@@ -193,7 +197,7 @@ void manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
        }
 
        /* the same function is already called in `focus_node` but has no effects on unmapped windows */
-       if (give_focus) {
+       if (focused) {
                xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT, win, XCB_CURRENT_TIME);
        }
 
@@ -654,7 +658,7 @@ void query_pointer(xcb_window_t *win, xcb_point_t *pt)
                        *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->visible) {
+                               if (!s->node->client->shown || s->node->hidden) {
                                        continue;
                                }
                                xcb_rectangle_t rect = get_rectangle(NULL, s->node);