]> git.lizzy.rs Git - bspwm.git/commitdiff
Implement sticky windows
authorBastien Dejean <nihilhill@gmail.com>
Tue, 1 Oct 2013 16:04:18 +0000 (18:04 +0200)
committerBastien Dejean <nihilhill@gmail.com>
Tue, 1 Oct 2013 16:04:18 +0000 (18:04 +0200)
18 files changed:
bspwm.c
bspwm.h
contrib/bash_completion
contrib/zsh_completion
desktop.c
doc/bspwm.1
doc/bspwm.1.txt
messages.c
query.c
restore.c
rule.c
rule.h
settings.c
settings.h
tree.c
types.h
window.c
window.h

diff --git a/bspwm.c b/bspwm.c
index af9637bf924bcc8528b416bccb712c75cd32a766..a98bb4abd298778e6c1e5ac0e365f41de54eedba 100644 (file)
--- a/bspwm.c
+++ b/bspwm.c
@@ -172,7 +172,7 @@ void init(void)
     status_fifo = NULL;
     last_motion_time = last_motion_x = last_motion_y = 0;
     randr_base = 0;
-    visible = auto_raise = true;
+    visible = auto_raise = sticky_still = true;
     exit_status = 0;
 }
 
diff --git a/bspwm.h b/bspwm.h
index be4c3bd312ca6c0ec9acad29fdadee82eed08fd3..bfc090d9ab7fd67db1a120dc6daeec9023b09796 100644 (file)
--- a/bspwm.h
+++ b/bspwm.h
@@ -42,6 +42,7 @@ int exit_status;
 
 bool visible;
 bool auto_raise;
+bool sticky_still;
 bool running;
 bool randr;
 
index 997edd368df3a29f681fba19b1fa819b01bdffe1..1c19f141d532a1ddf5dd45cede1a1fe818326e85 100644 (file)
@@ -1,7 +1,7 @@
 _bspc() {
     local commands='window desktop monitor query pointer rule restore control config quit'
 
-    local settings='focused_border_color active_border_color normal_border_color presel_border_color focused_locked_border_color active_locked_border_color normal_locked_border_color urgent_border_color border_width window_gap top_padding right_padding bottom_padding left_padding split_ratio growth_factor borderless_monocle gapless_monocle focus_follows_pointer pointer_follows_monitor apply_floating_atom auto_alternate auto_cancel history_aware_focus honor_ewmh_focus'
+    local settings='focused_border_color active_border_color normal_border_color presel_border_color focused_locked_border_color active_locked_border_color normal_locked_border_color focused_sticky_border_color normal_sticky_border_color urgent_border_color border_width window_gap top_padding right_padding bottom_padding left_padding split_ratio growth_factor borderless_monocle gapless_monocle focus_follows_pointer pointer_follows_monitor apply_floating_atom auto_alternate auto_cancel history_aware_focus honor_ewmh_focus'
 
     COMPREPLY=()
 
index 45cfefcbf9c9a4208771bb88135d561050e2b7d4..789c1c94463679b224a5a0572d0cf61037b8e60f 100644 (file)
@@ -3,7 +3,7 @@
 _bspc() {
     local -a commands settings
     commands=('window' 'desktop' 'monitor' 'query' 'pointer' 'rule' 'restore' 'control' 'config' 'quit')
-    settings=('focused_border_color' 'active_border_color' 'normal_border_color' 'presel_border_color' 'focused_locked_border_color' 'active_locked_border_color' 'normal_locked_border_color' 'urgent_border_color' 'border_width' 'window_gap' 'top_padding' 'right_padding' 'bottom_padding' 'left_padding' 'split_ratio' 'growth_factor' 'borderless_monocle' 'gapless_monocle' 'focus_follows_pointer' 'pointer_follows_monitor' 'apply_floating_atom' 'auto_alternate' 'auto_cancel' 'history_aware_focus' 'honor_ewmh_focus')
+    settings=('focused_border_color' 'active_border_color' 'normal_border_color' 'presel_border_color' 'focused_locked_border_color' 'active_locked_border_color' 'normal_locked_border_color' 'focused_sticky_border_color' 'normal_sticky_border_color' 'urgent_border_color' 'border_width' 'window_gap' 'top_padding' 'right_padding' 'bottom_padding' 'left_padding' 'split_ratio' 'growth_factor' 'borderless_monocle' 'gapless_monocle' 'focus_follows_pointer' 'pointer_follows_monitor' 'apply_floating_atom' 'auto_alternate' 'auto_cancel' 'history_aware_focus' 'honor_ewmh_focus')
     if (( CURRENT == 2 )) ; then
         _values 'command' "$commands[@]"
     elif (( CURRENT == 3 )) ; then
index 54fab39ba1640c19418baa71adbdf20dcf6552a2..46ffa8c0f8f53367cbc27574fbcfacd9cc6dabb2 100644 (file)
--- a/desktop.c
+++ b/desktop.c
@@ -95,6 +95,7 @@ desktop_t *make_desktop(const char *name)
     d->root = d->focus = NULL;
     d->window_gap = WINDOW_GAP;
     d->border_width = BORDER_WIDTH;
+    d->num_sticky = 0;
     return d;
 }
 
index 209717a238a26b5470054245663debf1cf393ff1..b4aa87457f5388be6e4b75f853e20f2c6e0ad3f2 100644 (file)
@@ -493,7 +493,7 @@ Set the splitting ratio (or pull, or push) the edge located in the given directi
 Rotate the tree holding the edge located in the given direction in relation to the selected window\&.
 .RE
 .PP
-\fB\-t\fR, \fB\-\-toggle\fR floating|fullscreen|locked[=on|off]
+\fB\-t\fR, \fB\-\-toggle\fR floating|fullscreen|locked|sticky[=on|off]
 .RS 4
 Set or toggle the given state for the selected window\&.
 .RE
@@ -810,7 +810,7 @@ rule \fIOPTIONS\fR
 \fBOptions\fR
 .RS 4
 .PP
-\fB\-a\fR, \fB\-\-add\fR <pattern> [\-d \fIDESKTOP_SEL\fR [\-\-follow]] [\-\-floating] [\-\-fullscreen] [\-\-locked] [\-\-focus] [\-\-unmanage] [\-\-one\-shot]
+\fB\-a\fR, \fB\-\-add\fR <pattern> [\-d \fIDESKTOP_SEL\fR [\-\-follow]] [\-\-floating] [\-\-fullscreen] [\-\-locked] [\-\-sticky] [\-\-focus] [\-\-unmanage] [\-\-one\-shot]
 .RS 4
 Create a new rule (<pattern> must match the class or instance name)\&.
 .RE
@@ -899,6 +899,16 @@ Color of the border of a focused locked window of an unfocused monitor\&.
 Color of the border of an unfocused locked window\&.
 .RE
 .PP
+\fIfocused_sticky_border_color\fR
+.RS 4
+Color of the border of a focused sticky window of a focused monitor\&.
+.RE
+.PP
+\fInormal_sticky_border_color\fR
+.RS 4
+Color of the border of an unfocused sticky window\&.
+.RE
+.PP
 \fIurgent_border_color\fR
 .RS 4
 Color of the border of an urgent window\&.
index 6dde082ed77144f2a98e964553376b0f02d630d8..c0f0a079ee522d2ea8e22a2fe6274ebb60382263 100644 (file)
@@ -319,7 +319,7 @@ Options
 *-R*, *--rotate* 'DIR' '90|270|180'::
     Rotate the tree holding the edge located in the given direction in relation to the selected window.
 
-*-t*, *--toggle* floating|fullscreen|locked[=on|off]::
+*-t*, *--toggle* floating|fullscreen|locked|sticky[=on|off]::
     Set or toggle the given state for the selected window.
 
 *-c*, *--close*::
@@ -495,7 +495,7 @@ rule 'OPTIONS'
 Options
 ^^^^^^^
 
-*-a*, *--add* <pattern> [-d 'DESKTOP_SEL' [--follow]] [--floating] [--fullscreen] [--locked] [--focus] [--unmanage] [--one-shot]::
+*-a*, *--add* <pattern> [-d 'DESKTOP_SEL' [--follow]] [--floating] [--fullscreen] [--locked] [--sticky] [--focus] [--unmanage] [--one-shot]::
     Create a new rule (<pattern> must match the class or instance name).
 
 *-r*, *--remove* <rule_uid>|tail|head...::
@@ -552,6 +552,12 @@ Global Settings
 'normal_locked_border_color'::
     Color of the border of an unfocused locked window.
 
+'focused_sticky_border_color'::
+    Color of the border of a focused sticky window of a focused monitor.
+
+'normal_sticky_border_color'::
+    Color of the border of an unfocused sticky window.
+
 'urgent_border_color'::
     Color of the border of an urgent window.
 
index bc7e6de2d7aa50fcce0239660cff95ebe2a96f63..3be6825e3463080af7a804396bf85978c6e81d82 100644 (file)
@@ -176,6 +176,8 @@ bool cmd_window(char **args, int num)
                 dirty = true;
             } else if (streq("locked", key)) {
                 set_locked(trg.monitor, trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->client->locked));
+            } else if (streq("sticky", key)) {
+                set_sticky(trg.monitor, trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->client->sticky));
             }
         } else if (streq("-p", *args) || streq("--presel", *args)) {
             num--, args++;
@@ -568,6 +570,8 @@ bool cmd_rule(char **args, int num, char *rsp) {
                     rule->effect.fullscreen = true;
                 } else if (streq("--locked", *args)) {
                     rule->effect.locked = true;
+                } else if (streq("--sticky", *args)) {
+                    rule->effect.sticky = true;
                 } else if (streq("--follow", *args)) {
                     rule->effect.follow = true;
                 } else if (streq("--focus", *args)) {
@@ -798,6 +802,8 @@ bool set_setting(coordinates_t loc, char *name, char *value)
     SETCOLOR(focused_locked_border_color)
     SETCOLOR(active_locked_border_color)
     SETCOLOR(normal_locked_border_color)
+    SETCOLOR(focused_sticky_border_color)
+    SETCOLOR(normal_sticky_border_color)
     SETCOLOR(urgent_border_color)
 #undef SETCOLOR
     } else if (streq("focus_follows_pointer", name)) {
@@ -883,6 +889,8 @@ bool get_setting(coordinates_t loc, char *name, char* rsp)
     GETCOLOR(focused_locked_border_color)
     GETCOLOR(active_locked_border_color)
     GETCOLOR(normal_locked_border_color)
+    GETCOLOR(focused_sticky_border_color)
+    GETCOLOR(normal_sticky_border_color)
     GETCOLOR(urgent_border_color)
 #undef GETCOLOR
 #define GETBOOL(s) \
diff --git a/query.c b/query.c
index 256382ef3df1d2ed026f1e4a6628a2e273fc21e8..1ec200521f6869ad00a0322caa25852f5f9a240b 100644 (file)
--- a/query.c
+++ b/query.c
@@ -66,7 +66,7 @@ void query_tree(desktop_t *d, node_t *n, char *rsp, unsigned int depth)
 
     if (is_leaf(n)) {
         client_t *c = n->client;
-        snprintf(line, sizeof(line), "%c %s 0x%X %u %ux%u%+i%+i %c %c%c%c%c%c%c", (n->birth_rotation == 90 ? 'a' : (n->birth_rotation == 270 ? 'c' : 'm')), c->class_name, c->window, c->border_width, c->floating_rectangle.width, c->floating_rectangle.height, c->floating_rectangle.x, c->floating_rectangle.y, (n->split_dir == DIR_UP ? 'U' : (n->split_dir == DIR_RIGHT ? 'R' : (n->split_dir == DIR_DOWN ? 'D' : 'L'))), (c->floating ? 'f' : '-'), (c->transient ? 't' : '-'), (c->fullscreen ? 'F' : '-'), (c->urgent ? 'u' : '-'), (c->locked ? 'l' : '-'), (n->split_mode ? 'p' : '-'));
+        snprintf(line, sizeof(line), "%c %s 0x%X %u %ux%u%+i%+i %c %c%c%c%c%c%c%c", (n->birth_rotation == 90 ? 'a' : (n->birth_rotation == 270 ? 'c' : 'm')), c->class_name, c->window, c->border_width, c->floating_rectangle.width, c->floating_rectangle.height, c->floating_rectangle.x, c->floating_rectangle.y, (n->split_dir == DIR_UP ? 'U' : (n->split_dir == DIR_RIGHT ? 'R' : (n->split_dir == DIR_DOWN ? 'D' : 'L'))), (c->floating ? 'f' : '-'), (c->transient ? 't' : '-'), (c->fullscreen ? 'F' : '-'), (c->urgent ? 'u' : '-'), (c->locked ? 'l' : '-'), (c->sticky ? 's' : '-'), (n->split_mode ? 'p' : '-'));
     } else {
         snprintf(line, sizeof(line), "%c %c %.2f", (n->split_type == TYPE_HORIZONTAL ? 'H' : 'V'), (n->birth_rotation == 90 ? 'a' : (n->birth_rotation == 270 ? 'c' : 'm')), n->split_ratio);
     }
index c3efc5b4ce66f8c50a3723713dcb9e9d30fc8d1e..5cddff2f3ab195cac898e2bfec9970c1e65fe724 100644 (file)
--- a/restore.c
+++ b/restore.c
@@ -111,13 +111,14 @@ void restore_tree(char *file_path)
             } else {
                 client_t *c = make_client(XCB_NONE);
                 num_clients++;
-                char floating, transient, fullscreen, urgent, locked, sd, sm, end = 0;
-                sscanf(line + level, "%c %s %X %u %hux%hu%hi%hi %c %c%c%c%c%c%c %c", &br, c->class_name, &c->window, &c->border_width, &c->floating_rectangle.width, &c->floating_rectangle.height, &c->floating_rectangle.x, &c->floating_rectangle.y, &sd, &floating, &transient, &fullscreen, &urgent, &locked, &sm, &end);
+                char floating, transient, fullscreen, urgent, locked, sticky, sd, sm, end = 0;
+                sscanf(line + level, "%c %s %X %u %hux%hu%hi%hi %c %c%c%c%c%c%c%c %c", &br, c->class_name, &c->window, &c->border_width, &c->floating_rectangle.width, &c->floating_rectangle.height, &c->floating_rectangle.x, &c->floating_rectangle.y, &sd, &floating, &transient, &fullscreen, &urgent, &locked, &sticky, &sm, &end);
                 c->floating = (floating == '-' ? false : true);
                 c->transient = (transient == '-' ? false : true);
                 c->fullscreen = (fullscreen == '-' ? false : true);
                 c->urgent = (urgent == '-' ? false : true);
                 c->locked = (locked == '-' ? false : true);
+                c->sticky = (sticky == '-' ? false : true);
                 n->split_mode = (sm == '-' ? MODE_AUTOMATIC : MODE_MANUAL);
                 if (sd == 'U')
                     n->split_dir = DIR_UP;
@@ -130,6 +131,8 @@ void restore_tree(char *file_path)
                 n->client = c;
                 if (end != 0)
                     d->focus = n;
+                if (c->sticky)
+                    d->num_sticky++;
             }
             if (br == 'a')
                 n->birth_rotation = 90;
diff --git a/rule.c b/rule.c
index 060999a06e245765a7948ed24406575825dfc434..fb45e51084cceae622e38423465adb2520dc2011 100644 (file)
--- a/rule.c
+++ b/rule.c
@@ -13,6 +13,7 @@ rule_t *make_rule(void)
     r->effect.floating = false;
     r->effect.fullscreen = false;
     r->effect.locked = false;
+    r->effect.sticky = false;
     r->effect.follow = false;
     r->effect.focus = false;
     r->effect.unmanage = false;
@@ -79,7 +80,7 @@ bool is_match(rule_t *r, xcb_window_t win)
     return false;
 }
 
-void handle_rules(xcb_window_t win, monitor_t **m, desktop_t **d, bool *floating, bool *fullscreen, bool *locked, bool *follow, bool *transient, bool *takes_focus, bool *manage)
+void handle_rules(xcb_window_t win, monitor_t **m, desktop_t **d, bool *floating, bool *fullscreen, bool *locked, bool *sticky, bool *follow, bool *transient, bool *takes_focus, bool *manage)
 {
     xcb_ewmh_get_atoms_reply_t win_type;
 
@@ -138,6 +139,8 @@ void handle_rules(xcb_window_t win, monitor_t **m, desktop_t **d, bool *floating
                 *fullscreen = true;
             if (efc.locked)
                 *locked = true;
+            if (efc.sticky)
+                *sticky = true;
             if (efc.follow)
                 *follow = true;
             if (efc.focus)
@@ -158,6 +161,11 @@ void handle_rules(xcb_window_t win, monitor_t **m, desktop_t **d, bool *floating
             remove_rule(rule);
         rule = next;
     }
+
+    if (*sticky) {
+        *m = mon;
+        *d = mon->desk;
+    }
 }
 
 void list_rules(char *pattern, char *rsp)
@@ -175,6 +183,8 @@ void list_rules(char *pattern, char *rsp)
             strncat(rsp, " --fullscreen", REMLEN(rsp));
         if (r->effect.locked)
             strncat(rsp, " --locked", REMLEN(rsp));
+        if (r->effect.sticky)
+            strncat(rsp, " --sticky", REMLEN(rsp));
         if (r->effect.follow)
             strncat(rsp, " --follow", REMLEN(rsp));
         if (r->effect.focus)
diff --git a/rule.h b/rule.h
index dd49c8ef90de7d7ef17bfe6c1ea820637cc7f613..0b60d12a12b3bd72b2825ccba239fc9d014ff3aa 100644 (file)
--- a/rule.h
+++ b/rule.h
@@ -10,7 +10,7 @@ void remove_rule_by_uid(unsigned int);
 void prune_rules(desktop_t *);
 rule_t *find_rule(unsigned int);
 bool is_match(rule_t *, xcb_window_t);
-void handle_rules(xcb_window_t, monitor_t **, desktop_t **, bool *, bool *, bool *, bool *, bool *, bool *, bool *);
+void handle_rules(xcb_window_t, monitor_t **, desktop_t **, bool *, bool *, bool *, bool *, bool *, bool *, bool *, bool *);
 void list_rules(char *, char *);
 
 #endif
index a91816cac486c6181f757e37dbba585b62dfa358..2d33bb636dcfb948326f4115e732972b46bc305a 100644 (file)
@@ -29,6 +29,8 @@ void load_settings(void)
     snprintf(focused_locked_border_color, sizeof(focused_locked_border_color), "%s", FOCUSED_LOCKED_BORDER_COLOR);
     snprintf(active_locked_border_color, sizeof(active_locked_border_color), "%s", ACTIVE_LOCKED_BORDER_COLOR);
     snprintf(normal_locked_border_color, sizeof(normal_locked_border_color), "%s", NORMAL_LOCKED_BORDER_COLOR);
+    snprintf(focused_sticky_border_color, sizeof(focused_sticky_border_color), "%s", FOCUSED_STICKY_BORDER_COLOR);
+    snprintf(normal_sticky_border_color, sizeof(normal_sticky_border_color), "%s", NORMAL_STICKY_BORDER_COLOR);
     snprintf(urgent_border_color, sizeof(urgent_border_color), "%s", URGENT_BORDER_COLOR);
 
     split_ratio = SPLIT_RATIO;
index 77e6bb226f767d71c3a06426b7f1c9d6455ff2ac..c1f5ffabe41b213b0bb8e39d60d98e2323b6ed0d 100644 (file)
@@ -14,6 +14,8 @@
 #define FOCUSED_LOCKED_BORDER_COLOR "#C7B579"
 #define ACTIVE_LOCKED_BORDER_COLOR  "#545350"
 #define NORMAL_LOCKED_BORDER_COLOR  "#3F3E3B"
+#define FOCUSED_STICKY_BORDER_COLOR "#E3A5DA"
+#define NORMAL_STICKY_BORDER_COLOR  "#3F3E3B"
 #define URGENT_BORDER_COLOR         "#EFA29A"
 
 #define SPLIT_RATIO    0.5
@@ -36,6 +38,8 @@ char presel_border_color[MAXLEN];
 char focused_locked_border_color[MAXLEN];
 char active_locked_border_color[MAXLEN];
 char normal_locked_border_color[MAXLEN];
+char focused_sticky_border_color[MAXLEN];
+char normal_sticky_border_color[MAXLEN];
 char urgent_border_color[MAXLEN];
 
 double split_ratio;
diff --git a/tree.c b/tree.c
index d1579cd8f2c3f69120b71afde979972d7bd0a7f9..680179d428c30d11193f45f42996cb096c16f20c 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -203,6 +203,8 @@ void insert_node(monitor_t *m, desktop_t *d, node_t *n, node_t *f)
         if (f->vacant)
             update_vacant_state(p);
     }
+    if (n->client->sticky)
+        d->num_sticky++;
     put_status();
 }
 
@@ -222,6 +224,20 @@ void focus_node(monitor_t *m, desktop_t *d, node_t *n)
     if (mon->desk != d || n == NULL)
         clear_input_focus();
 
+    if (mon->desk->num_sticky > 0 && d != mon->desk) {
+        node_t *a = first_extrema(mon->desk->root);
+        sticky_still = false;
+        while (a != NULL) {
+            node_t *b = next_leaf(a, mon->desk->root);
+            if (a->client->sticky)
+                transfer_node(mon, mon->desk, a, m, d, d->focus);
+            a = b;
+        }
+        sticky_still = true;
+        if (n == NULL)
+            n = d->focus;
+    }
+
     if (n != NULL && d->focus != NULL && n != d->focus && d->focus->client->fullscreen) {
         set_fullscreen(d->focus, false);
         arrange(m, d);
@@ -294,7 +310,7 @@ client_t *make_client(xcb_window_t win)
     snprintf(c->class_name, sizeof(c->class_name), "%s", MISSING_VALUE);
     c->border_width = BORDER_WIDTH;
     c->window = win;
-    c->floating = c->transient = c->fullscreen = c->locked = c->urgent = false;
+    c->floating = c->transient = c->fullscreen = c->locked = c->sticky = c->urgent = false;
     c->icccm_focus = false;
     xcb_icccm_get_wm_protocols_reply_t protocols;
     if (xcb_icccm_get_wm_protocols_reply(dpy, xcb_icccm_get_wm_protocols(dpy, win, ewmh->WM_PROTOCOLS), &protocols, NULL) == 1) {
@@ -739,6 +755,8 @@ void unlink_node(desktop_t *d, node_t *n)
 
         update_vacant_state(b->parent);
     }
+    if (n->client->sticky)
+        d->num_sticky--;
     put_status();
 }
 
@@ -777,7 +795,7 @@ void destroy_tree(node_t *n)
 
 void swap_nodes(monitor_t *m1, desktop_t *d1, node_t *n1, monitor_t *m2, desktop_t *d2, node_t *n2)
 {
-    if (n1 == NULL || n2 == NULL || n1 == n2)
+    if (n1 == NULL || n2 == NULL || n1 == n2 || (d1 != d2 && (n1->client->sticky || n2->client->sticky)))
         return;
 
     PRINTF("swap nodes %X %X", n1->client->window, n2->client->window);
@@ -846,7 +864,7 @@ void swap_nodes(monitor_t *m1, desktop_t *d1, node_t *n1, monitor_t *m2, desktop
 
 void transfer_node(monitor_t *ms, desktop_t *ds, node_t *ns, monitor_t *md, desktop_t *dd, node_t *nd)
 {
-    if (ns == NULL || ns == nd)
+    if (ns == NULL || ns == nd || (sticky_still && ns->client->sticky))
         return;
 
     PRINTF("transfer node %X\n", ns->client->window);
@@ -865,10 +883,12 @@ void transfer_node(monitor_t *ms, desktop_t *ds, node_t *ns, monitor_t *md, desk
 
     if (ds != dd) {
         ewmh_set_wm_desktop(ns, dd);
-        if (ds == ms->desk && dd != md->desk)
-            window_hide(ns->client->window);
-        else if (ds != ms->desk && dd == md->desk)
-            window_show(ns->client->window);
+        if (!ns->client->sticky) {
+            if (ds == ms->desk && dd != md->desk)
+                window_hide(ns->client->window);
+            else if (ds != ms->desk && dd == md->desk)
+                window_show(ns->client->window);
+        }
     }
 
     history_transfer_node(md, dd, ns);
diff --git a/types.h b/types.h
index 801a9048feddae858595718cbf4cfe1b8beb746c..ef445608eb5c3310f0175c9454c143be4f9b4718 100644 (file)
--- a/types.h
+++ b/types.h
@@ -140,6 +140,7 @@ typedef struct {
     bool transient;    /* transient window are always floating */
     bool fullscreen;
     bool locked;       /* protects window from being closed */
+    bool sticky;
     bool urgent;
     bool icccm_focus;
     xcb_rectangle_t floating_rectangle;
@@ -171,6 +172,7 @@ struct desktop_t {
     desktop_t *next;
     int window_gap;
     unsigned int border_width;
+    int num_sticky;
 };
 
 typedef struct monitor_t monitor_t;
@@ -220,6 +222,7 @@ typedef struct {
     bool floating;
     bool fullscreen;
     bool locked;
+    bool sticky;
     bool follow;
     bool focus;
     bool unmanage;
index 7ceb5c4d33171e3ede3900b0d4b9dc773e887c69..c0e83923e4305aaaf318a05ada5e2b4ea44e4b32 100644 (file)
--- a/window.c
+++ b/window.c
@@ -24,8 +24,8 @@ void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win)
     if (override_redirect || locate_window(win, &loc))
         return;
 
-    bool floating = false, fullscreen = false, locked = false, follow = false, transient = false, takes_focus = true, manage = true;
-    handle_rules(win, &m, &d, &floating, &fullscreen, &locked, &follow, &transient, &takes_focus, &manage);
+    bool floating = false, fullscreen = false, locked = false, sticky = false, follow = false, transient = false, takes_focus = true, manage = true;
+    handle_rules(win, &m, &d, &floating, &fullscreen, &locked, &sticky, &follow, &transient, &takes_focus, &manage);
 
     if (!manage) {
         disable_floating_atom(win);
@@ -55,6 +55,7 @@ void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win)
     disable_floating_atom(c->window);
     set_floating(n, floating);
     set_locked(m, d, n, locked);
+    set_sticky(m, d, n, sticky);
 
     if (d->focus != NULL && d->focus->client->fullscreen)
         set_fullscreen(d->focus, false);
@@ -353,6 +354,23 @@ void set_locked(monitor_t *m, desktop_t *d, node_t *n, bool value)
     window_draw_border(n, d->focus == n, m == mon);
 }
 
+void set_sticky(monitor_t *m, desktop_t *d, node_t *n, bool value)
+{
+    if (n == NULL || n->client->sticky == value)
+        return;
+
+    client_t *c = n->client;
+
+    PRINTF("set sticky %X: %s\n", c->window, BOOLSTR(value));
+
+    c->sticky = value;
+    if (value)
+        d->num_sticky++;
+    else
+        d->num_sticky--;
+    window_draw_border(n, d->focus == n, m == mon);
+}
+
 void set_urgency(monitor_t *m, desktop_t *d, node_t *n, bool value)
 {
     if (value && mon->desk->focus == n)
@@ -389,6 +407,8 @@ uint32_t get_border_color(client_t *c, bool focused_window, bool focused_monitor
     if (focused_monitor && focused_window) {
         if (c->locked)
             get_color(focused_locked_border_color, c->window, &pxl);
+        else if (c->sticky)
+            get_color(focused_sticky_border_color, c->window, &pxl);
         else
             get_color(focused_border_color, c->window, &pxl);
     } else if (focused_window) {
@@ -403,6 +423,8 @@ uint32_t get_border_color(client_t *c, bool focused_window, bool focused_monitor
             get_color(urgent_border_color, c->window, &pxl);
         else if (c->locked)
             get_color(normal_locked_border_color, c->window, &pxl);
+        else if (c->sticky)
+            get_color(normal_sticky_border_color, c->window, &pxl);
         else
             get_color(normal_border_color, c->window, &pxl);
     }
index 9a527c34d4a93686c78d97076b3673b01f087d69..2690bba3eb5b98d299d32d0042ad90fc2cbd118b 100644 (file)
--- a/window.h
+++ b/window.h
@@ -26,6 +26,7 @@ void window_kill(desktop_t *, node_t *);
 void set_fullscreen(node_t *, bool);
 void set_floating(node_t *, bool);
 void set_locked(monitor_t *, desktop_t *, node_t *, bool);
+void set_sticky(monitor_t *, desktop_t *, node_t *, bool);
 void set_urgency(monitor_t *, desktop_t *, node_t *, bool);
 void set_floating_atom(xcb_window_t, uint32_t);
 void enable_floating_atom(xcb_window_t);