]> git.lizzy.rs Git - bspwm.git/commitdiff
Implement frames
authorBastien Dejean <nihilhill@gmail.com>
Thu, 10 Oct 2013 16:24:21 +0000 (18:24 +0200)
committerBastien Dejean <nihilhill@gmail.com>
Thu, 10 Oct 2013 16:24:21 +0000 (18:24 +0200)
20 files changed:
bspwm.c
bspwm.h
contrib/bash_completion
contrib/create_frame.c [new file with mode: 0644]
contrib/zsh_completion
doc/bspwm.1
doc/bspwm.1.txt
events.c
events.h
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 f485ff5302997a989ead12ac33e3b6761fb1c9e9..78bf629b59e62debcc17b28924d5d6fe5ec2c3bd 100644 (file)
--- a/bspwm.c
+++ b/bspwm.c
@@ -252,6 +252,7 @@ void setup(void)
     GETATOM(WM_DELETE_WINDOW)
     GETATOM(WM_TAKE_FOCUS)
     GETATOM(_BSPWM_FLOATING_WINDOW)
+    GETATOM(_NET_WM_WINDOW_OPACITY)
 #undef GETATOM
 
     const xcb_query_extension_reply_t *qep = xcb_get_extension_data(dpy, &xcb_randr_id);
diff --git a/bspwm.h b/bspwm.h
index cd145870fd4a2bae2ff7ba063fcccc71e17902bf..d5c46d003313055df1554d9cb1062c25af3ad9e8 100644 (file)
--- a/bspwm.h
+++ b/bspwm.h
@@ -29,7 +29,6 @@
 
 #define ROOT_EVENT_MASK        (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY)
 #define CLIENT_EVENT_MASK      (XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_FOCUS_CHANGE)
-#define CLIENT_EVENT_MASK_FFP  (CLIENT_EVENT_MASK | XCB_EVENT_MASK_ENTER_WINDOW)
 
 xcb_connection_t *dpy;
 int default_screen, screen_width, screen_height;
@@ -61,6 +60,7 @@ pointer_state_t *frozen_pointer;
 xcb_window_t motion_recorder;
 xcb_atom_t WM_TAKE_FOCUS;
 xcb_atom_t WM_DELETE_WINDOW;
+xcb_atom_t _NET_WM_WINDOW_OPACITY;
 xcb_atom_t _BSPWM_FLOATING_WINDOW;
 int exit_status;
 
index 1c19f141d532a1ddf5dd45cede1a1fe818326e85..e07dff7e6344c3d88d4ce4bfb5f130dd4ae45904 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 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'
+    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 focused_frame_opacity active_frame_opacity normal_frame_opacity 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=()
 
diff --git a/contrib/create_frame.c b/contrib/create_frame.c
new file mode 100644 (file)
index 0000000..6136eee
--- /dev/null
@@ -0,0 +1,59 @@
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <xcb/xcb.h>
+#include <xcb/xcb_event.h>
+#include <xcb/xcb_icccm.h>
+
+#define FRAME_CLASS_NAME     "BSPWM_FRAME"
+#define FRAME_INSTANCE_NAME  "bspwm_frame"
+
+xcb_connection_t *dpy;
+
+bool get_atom(char *name, xcb_atom_t *atom)
+{
+    bool ack = true;
+    xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(dpy, xcb_intern_atom(dpy, 0, strlen(name), name), NULL);
+    if (reply != NULL)
+        *atom = reply->atom;
+    else
+        ack = false;
+    free(reply);
+    return ack;
+}
+
+int main(int argc, char *argv[])
+{
+    dpy = xcb_connect(NULL, NULL);
+    if (dpy == NULL)
+        return EXIT_FAILURE;
+    xcb_atom_t WM_PROTOCOLS, WM_DELETE_WINDOW;
+    if (!get_atom("WM_PROTOCOLS", &WM_PROTOCOLS)
+            || !get_atom("WM_DELETE_WINDOW", &WM_DELETE_WINDOW)) {
+        xcb_disconnect(dpy);
+        return EXIT_FAILURE;
+    }
+    xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(dpy)).data;
+    if (screen == NULL)
+        return EXIT_FAILURE;
+    xcb_window_t root = screen->root;
+    xcb_window_t win = xcb_generate_id(dpy);
+    xcb_create_window(dpy, XCB_COPY_FROM_PARENT, win, root, 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, NULL);
+    xcb_icccm_set_wm_class(dpy, win, strlen(FRAME_CLASS_NAME) + strlen(FRAME_INSTANCE_NAME) + 1, FRAME_INSTANCE_NAME "\0" FRAME_CLASS_NAME);
+    xcb_map_window(dpy, win);
+    xcb_flush(dpy);
+    xcb_generic_event_t *evt;
+    bool running = true;
+    while (running && (evt = xcb_wait_for_event(dpy)) != NULL) {
+        uint8_t rt = XCB_EVENT_RESPONSE_TYPE(evt);
+        if (rt == XCB_CLIENT_MESSAGE)  {
+            xcb_client_message_event_t *cme = (xcb_client_message_event_t *) evt;
+            if (cme->type == WM_PROTOCOLS && cme->data.data32[0] == WM_DELETE_WINDOW)
+                running = false;
+        }
+        free(evt);
+    }
+    xcb_destroy_window(dpy, win);
+    xcb_disconnect(dpy);
+    return EXIT_SUCCESS;
+}
index 789c1c94463679b224a5a0572d0cf61037b8e60f..a668e5a98608b14dda56f7bcc1fa15ae7e9c32f6 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' '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')
+    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' 'focused_frame_opacity' 'active_frame_opacity' 'normal_frame_opacity' '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 26e4f5d05804c34f89b38ace37e653ecf592a0b4..1b5726fd6b61b895480eb0130261c85025af9094 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: 10/08/2013
+.\"      Date: 10/10/2013
 .\"    Manual: Bspwm Manual
 .\"    Source: Bspwm 0.8.5
 .\"  Language: English
 .\"
-.TH "BSPWM" "1" "10/08/2013" "Bspwm 0\&.8\&.5" "Bspwm Manual"
+.TH "BSPWM" "1" "10/10/2013" "Bspwm 0\&.8\&.5" "Bspwm Manual"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -914,7 +914,7 @@ rule \fIOPTIONS\fR
 \fBOptions\fR
 .RS 4
 .PP
-\fB\-a\fR, \fB\-\-add\fR <class_name>|<instance_name> [\-d \fIDESKTOP_SEL\fR [\-\-follow]] [\-\-tags <name>|^<n>[,\&...]][\-\-floating] [\-\-fullscreen] [\-\-locked] [\-\-sticky] [\-\-focus] [\-\-unmanage] [\-\-one\-shot]
+\fB\-a\fR, \fB\-\-add\fR <class_name>|<instance_name> [\-d \fIDESKTOP_SEL\fR [\-\-follow]] [\-\-tags <name>|^<n>[,\&...]][\-\-floating] [\-\-fullscreen] [\-\-locked] [\-\-sticky] [\-\-focus] [\-\-frame] [\-\-unmanage] [\-\-one\-shot]
 .RS 4
 Create a new rule\&.
 .RE
@@ -1023,6 +1023,21 @@ Color of the border of an unfocused sticky window\&.
 Color of the border of an urgent window\&.
 .RE
 .PP
+\fIfocused_frame_opacity\fR
+.RS 4
+Opacity of a focused frame of a focused monitor\&.
+.RE
+.PP
+\fIactive_frame_opacity\fR
+.RS 4
+Opacity of a focused frame of an unfocused monitor\&.
+.RE
+.PP
+\fInormal_frame_opacity\fR
+.RS 4
+Opacity of an unfocused frame\&.
+.RE
+.PP
 \fIsplit_ratio\fR
 .RS 4
 Default split ratio\&.
index 143d28d4409079d58f8447561383db8b58df494c..2bc5fd78a329818bb1fdbf13d58c0ea681862558 100644 (file)
@@ -550,7 +550,7 @@ rule 'OPTIONS'
 Options
 ^^^^^^^
 
-*-a*, *--add* <class_name>|<instance_name> [-d 'DESKTOP_SEL' [--follow]] [--tags <name>|^<n>[,...]][--floating] [--fullscreen] [--locked] [--sticky] [--focus] [--unmanage] [--one-shot]::
+*-a*, *--add* <class_name>|<instance_name> [-d 'DESKTOP_SEL' [--follow]] [--tags <name>|^<n>[,...]][--floating] [--fullscreen] [--locked] [--sticky] [--focus] [--frame] [--unmanage] [--one-shot]::
     Create a new rule.
 
 *-r*, *--remove* <name>|^<n>|tail|head...::
@@ -619,6 +619,15 @@ Global Settings
 'urgent_border_color'::
     Color of the border of an urgent window.
 
+'focused_frame_opacity'::
+    Opacity of a focused frame of a focused monitor.
+
+'active_frame_opacity'::
+    Opacity of a focused frame of an unfocused monitor.
+
+'normal_frame_opacity'::
+    Opacity of an unfocused frame.
+
 'split_ratio'::
     Default split ratio.
 
index 26708000cea681686b769fb3062c24dd486e3868..65274a4152bea22645d5c43106717531e072286d 100644 (file)
--- a/events.c
+++ b/events.c
@@ -63,6 +63,9 @@ void handle_event(xcb_generic_event_t *evt)
         case XCB_FOCUS_IN:
             focus_in(evt);
             break;
+        case XCB_EXPOSE:
+            expose(evt);
+            break;
         default:
             if (randr && resp_type == randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY)
                 import_monitors();
@@ -261,6 +264,17 @@ void focus_in(xcb_generic_event_t *evt)
         update_input_focus();
 }
 
+void expose(xcb_generic_event_t *evt)
+{
+    xcb_expose_event_t *e = (xcb_expose_event_t *) evt;
+
+    PRINTF("expose %X\n", e->window);
+
+    coordinates_t loc;
+    if (locate_window(e->window, &loc) && loc.node->client->frame)
+        draw_frame_background(loc.node, loc.desktop->focus == loc.node, loc.monitor == mon);
+}
+
 void enter_notify(xcb_generic_event_t *evt)
 {
     xcb_enter_notify_event_t *e = (xcb_enter_notify_event_t *) evt;
index 7812dadf7d7a456939479e2da9089fe868829856..096db5b750fac0020c0c013419ddb8e9fee88820 100644 (file)
--- a/events.h
+++ b/events.h
@@ -40,6 +40,7 @@ void unmap_notify(xcb_generic_event_t *evt);
 void property_notify(xcb_generic_event_t *evt);
 void client_message(xcb_generic_event_t *evt);
 void focus_in(xcb_generic_event_t *evt);
+void expose(xcb_generic_event_t *evt);
 void enter_notify(xcb_generic_event_t *evt);
 void motion_notify(xcb_generic_event_t *evt);
 void handle_state(monitor_t *m, desktop_t *d, node_t *n, xcb_atom_t state, unsigned int action);
index d7edf412cb4370ba3f47a752094f48cea6eb3df7..33339dc7c3de027be54b64be753a674e651ec71c 100644 (file)
@@ -768,6 +768,8 @@ bool cmd_rule(char **args, int num, char *rsp)
                     rule->effect.follow = true;
                 } else if (streq("--focus", *args)) {
                     rule->effect.focus = true;
+                } else if (streq("--frame", *args)) {
+                    rule->effect.frame = true;
                 } else if (streq("--unmanage", *args)) {
                     rule->effect.unmanage = true;
                 } else if (streq("--one-shot", *args)) {
@@ -1003,6 +1005,21 @@ bool set_setting(coordinates_t loc, char *name, char *value)
         else
             return false;
         return true;
+#define SETOPACITY(s) \
+    } else if (streq(#s, name)) { \
+        double o; \
+        if (sscanf(value, "%lf", &o) == 1 && o >= 0 && o <= 1) \
+            s = o; \
+        else \
+            return false; \
+        for (monitor_t *m = mon_head; m != NULL; m = m->next) \
+            for (node_t *n = first_extrema(m->desk->root); n != NULL; n = next_leaf(n, m->desk->root)) \
+                if (is_visible(m->desk, n) && n->client->frame) \
+                    draw_frame_background(n, m->desk->focus == n, m == mon);
+    SETOPACITY(focused_frame_opacity)
+    SETOPACITY(active_frame_opacity)
+    SETOPACITY(normal_frame_opacity)
+#undef SETOPACITY
 #define SETCOLOR(s) \
     } else if (streq(#s, name)) { \
         snprintf(s, sizeof(s), "%s", value);
@@ -1021,21 +1038,22 @@ bool set_setting(coordinates_t loc, char *name, char *value)
     } else if (streq("focus_follows_pointer", name)) {
         bool b;
         if (parse_bool(value, &b) && b != focus_follows_pointer) {
-            uint32_t values[] = {(focus_follows_pointer ? CLIENT_EVENT_MASK : CLIENT_EVENT_MASK_FFP)};
+            focus_follows_pointer = b;
             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))
+                    for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
+                        uint32_t values[] = {get_event_mask(n->client)};
                         xcb_change_window_attributes(dpy, n->client->window, XCB_CW_EVENT_MASK, values);
+                    }
             if (focus_follows_pointer) {
-                for (monitor_t *m = mon_head; m != NULL; m = m->next)
-                    window_hide(m->root);
-                disable_motion_recorder();
-            } else {
                 for (monitor_t *m = mon_head; m != NULL; m = m->next)
                     window_show(m->root);
                 enable_motion_recorder();
+            } else {
+                for (monitor_t *m = mon_head; m != NULL; m = m->next)
+                    window_hide(m->root);
+                disable_motion_recorder();
             }
-            focus_follows_pointer = b;
             return true;
         } else {
             return false;
@@ -1091,6 +1109,13 @@ bool get_setting(coordinates_t loc, char *name, char* rsp)
     MONGET(bottom_padding)
     MONGET(left_padding)
 #undef MONGET
+#define GETOPACITY(s) \
+    else if (streq(#s, name)) \
+        snprintf(rsp, BUFSIZ, "%lf", s);
+    GETOPACITY(focused_frame_opacity)
+    GETOPACITY(active_frame_opacity)
+    GETOPACITY(normal_frame_opacity)
+#undef GETOPACITY
 #define GETCOLOR(s) \
     else if (streq(#s, name)) \
         snprintf(rsp, BUFSIZ, "%s", s);
diff --git a/query.c b/query.c
index d8c739d1f6b051f77051c564113734e81e783331..e862d42fd0d7a58bd43f6f10890b853118626d78 100644 (file)
--- a/query.c
+++ b/query.c
@@ -90,7 +90,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 %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->tags_field, 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' : '-'));
+        snprintf(line, sizeof(line), "%c %s 0x%X %u %u %ux%u%+i%+i %c %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->tags_field, 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' : '-'), (c->frame ? 'e' : '-'), (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 92c7037bbd8032c96100137c9d566e7aea4870fe..de7231ece1fed498acfc13bc6b9512c106f2d1ae 100644 (file)
--- a/restore.c
+++ b/restore.c
@@ -136,14 +136,15 @@ void restore_tree(char *file_path)
             } else {
                 client_t *c = make_client(XCB_NONE);
                 num_clients++;
-                char floating, transient, fullscreen, urgent, locked, sticky, sd, sm, end = 0;
-                sscanf(line + level, "%c %s %X %u %u %hux%hu%hi%hi %c %c%c%c%c%c%c%c %c", &br, c->class_name, &c->window, &c->tags_field, &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);
+                char floating, transient, fullscreen, urgent, locked, sticky, frame, sd, sm, end = 0;
+                sscanf(line + level, "%c %s %X %u %u %hux%hu%hi%hi %c %c%c%c%c%c%c%c%c %c", &br, c->class_name, &c->window, &c->tags_field, &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, &frame, &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);
+                c->frame = (frame == '-' ? false : true);
                 n->split_mode = (sm == '-' ? MODE_AUTOMATIC : MODE_MANUAL);
                 if (sd == 'U')
                     n->split_dir = DIR_UP;
@@ -174,7 +175,7 @@ void restore_tree(char *file_path)
     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)) {
-                uint32_t values[] = {(focus_follows_pointer ? CLIENT_EVENT_MASK_FFP : CLIENT_EVENT_MASK)};
+                uint32_t values[] = {get_event_mask(n->client)};
                 xcb_change_window_attributes(dpy, n->client->window, XCB_CW_EVENT_MASK, values);
                 if (n->client->floating || !is_visible(d, n)) {
                     n->vacant = true;
diff --git a/rule.c b/rule.c
index 9d97e0d1b91ad9970b8f6a304db4f2d78b9d28b3..eef471d1061d6a79761959ad8f6901e466f9cc3f 100644 (file)
--- a/rule.c
+++ b/rule.c
@@ -41,6 +41,7 @@ rule_t *make_rule(void)
     r->effect.sticky = false;
     r->effect.follow = false;
     r->effect.focus = false;
+    r->effect.frame = false;
     r->effect.unmanage = false;
     r->one_shot = false;
     r->effect.desc[0] = '\0';
@@ -114,7 +115,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, unsigned int *tags_field, bool *floating, bool *fullscreen, bool *locked, bool *sticky, bool *follow, bool *transient, bool *takes_focus, bool *manage)
+void handle_rules(xcb_window_t win, monitor_t **m, desktop_t **d, unsigned int *tags_field, bool *floating, bool *fullscreen, bool *locked, bool *sticky, bool *follow, bool *transient, bool *takes_focus, bool *frame, bool *manage)
 {
     xcb_ewmh_get_atoms_reply_t win_type;
 
@@ -180,6 +181,8 @@ void handle_rules(xcb_window_t win, monitor_t **m, desktop_t **d, unsigned int *
                 *follow = true;
             if (efc.focus)
                 *takes_focus = true;
+            if (efc.frame)
+                *frame = true;
             if (efc.unmanage)
                 *manage = false;
             if (efc.desc[0] != '\0') {
@@ -238,6 +241,8 @@ void list_rules(char *pattern, char *rsp)
             strncat(rsp, " --follow", REMLEN(rsp));
         if (r->effect.focus)
             strncat(rsp, " --focus", REMLEN(rsp));
+        if (r->effect.frame)
+            strncat(rsp, " --frame", REMLEN(rsp));
         if (r->effect.unmanage)
             strncat(rsp, " --unmanage", REMLEN(rsp));
         if (r->one_shot)
diff --git a/rule.h b/rule.h
index 2bd89331326ca805640fd77cc75a0c0fd4a88847..7d8c35a7bb91980bb7d096de04f75ab3031b5b9e 100644 (file)
--- a/rule.h
+++ b/rule.h
@@ -34,7 +34,7 @@ void remove_rule(rule_t *r);
 void remove_rule_by_name(char *name);
 bool remove_rule_by_index(int idx);
 bool is_match(rule_t *r, xcb_window_t win);
-void handle_rules(xcb_window_t win, monitor_t **m, desktop_t **d, unsigned int *tags_field, bool *floating, bool *fullscreen, bool *locked, bool *sticky, bool *follow, bool *transient, bool *takes_focus, bool *manage);
+void handle_rules(xcb_window_t win, monitor_t **m, desktop_t **d, unsigned int *tags_field, bool *floating, bool *fullscreen, bool *locked, bool *sticky, bool *follow, bool *transient, bool *takes_focus, bool *frame, bool *manage);
 void list_rules(char *pattern, char *rsp);
 
 #endif
index ab04c8219c499c14bd5c4ea65799ae5e42ee7308..2872146f02e36eb4de8ddb275f155603823f918a 100644 (file)
@@ -58,6 +58,10 @@ void load_settings(void)
     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);
 
+    focused_frame_opacity = FOCUSED_FRAME_OPACITY;
+    active_frame_opacity = ACTIVE_FRAME_OPACITY;
+    normal_frame_opacity = NORMAL_FRAME_OPACITY;
+
     split_ratio = SPLIT_RATIO;
     growth_factor = GROWTH_FACTOR;
 
index 894c1a240e67160395ef3af4c8b964df9155dd2b..88ae8fb8432f7bd5b7d8cc37f6284bb118aaab32 100644 (file)
 #define NORMAL_STICKY_BORDER_COLOR  "#3F3E3B"
 #define URGENT_BORDER_COLOR         "#EFA29A"
 
+#define FOCUSED_FRAME_OPACITY       0.5
+#define ACTIVE_FRAME_OPACITY        0.25
+#define NORMAL_FRAME_OPACITY        0.125
+
 #define SPLIT_RATIO    0.5
 #define GROWTH_FACTOR  1.1
 
@@ -68,6 +72,10 @@ char active_sticky_border_color[MAXLEN];
 char normal_sticky_border_color[MAXLEN];
 char urgent_border_color[MAXLEN];
 
+double focused_frame_opacity;
+double active_frame_opacity;
+double normal_frame_opacity;
+
 double split_ratio;
 double growth_factor;
 
diff --git a/tree.c b/tree.c
index d1b1cd190e1e62078f439b1da406b83c1e90a121..c26810697cf1a30ffc77cd113f404fb387d8fda7 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -68,8 +68,9 @@ void apply_layout(monitor_t *m, desktop_t *d, node_t *n, xcb_rectangle_t rect, x
             n->client->floating_rectangle.height += ds;
         }
 
-        if ((borderless_monocle && is_tiled(n->client) && d->layout == LAYOUT_MONOCLE) ||
-                n->client->fullscreen)
+        if ((borderless_monocle && is_tiled(n->client) && d->layout == LAYOUT_MONOCLE)
+                || n->client->fullscreen
+                || n->client->frame)
             n->client->border_width = 0;
         else
             n->client->border_width = d->border_width;
@@ -100,7 +101,7 @@ void apply_layout(monitor_t *m, desktop_t *d, node_t *n, xcb_rectangle_t rect, x
 
         window_move_resize(n->client->window, r.x, r.y, r.width, r.height);
         window_border_width(n->client->window, n->client->border_width);
-        window_draw_border(n, n == d->focus, m == mon);
+        window_draw_border(n, d->focus == n, m == mon);
 
     } else {
         xcb_rectangle_t first_rect;
@@ -343,7 +344,7 @@ client_t *make_client(xcb_window_t win)
     c->border_width = BORDER_WIDTH;
     c->window = win;
     c->floating = c->transient = c->fullscreen = c->locked = c->sticky = c->urgent = false;
-    c->icccm_focus = false;
+    c->frame = 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) {
         if (has_proto(WM_TAKE_FOCUS, &protocols))
diff --git a/types.h b/types.h
index 790e80f13fce0ffe6b079cee9289c87da62dae06..e432908b8cac563da9d4e8d6bd8cab204bb7b709 100644 (file)
--- a/types.h
+++ b/types.h
@@ -161,6 +161,7 @@ typedef struct {
     bool locked;       /* protects window from being closed */
     bool sticky;
     bool urgent;
+    bool frame;
     bool icccm_focus;
     xcb_rectangle_t floating_rectangle;
     xcb_rectangle_t tiled_rectangle;
@@ -249,6 +250,7 @@ typedef struct {
     bool follow;
     bool focus;
     bool unmanage;
+    bool frame;
     char desc[MAXLEN];
     char tags[MAXLEN];
 } rule_effect_t;
index 818c21af182d6115575acefe71ecbf11c771959a..c9ef7e20ca73fb310298b7e1dacf799a18c457fa 100644 (file)
--- a/window.c
+++ b/window.c
@@ -49,9 +49,9 @@ 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, sticky = false, follow = false, transient = false, takes_focus = true, manage = true;
+    bool floating = false, fullscreen = false, locked = false, sticky = false, follow = false, transient = false, takes_focus = true, frame = false, manage = true;
     unsigned int tags_field = 0;
-    handle_rules(win, &m, &d, &tags_field, &floating, &fullscreen, &locked, &sticky, &follow, &transient, &takes_focus, &manage);
+    handle_rules(win, &m, &d, &tags_field, &floating, &fullscreen, &locked, &sticky, &follow, &transient, &takes_focus, &frame, &manage);
 
     if (!manage) {
         disable_floating_atom(win);
@@ -64,6 +64,7 @@ void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win)
     client_t *c = make_client(win);
     update_floating_rectangle(c);
     c->tags_field = (tags_field == 0 ? d->tags_field : tags_field);
+    c->frame = frame;
 
     xcb_icccm_get_wm_class_reply_t reply;
     if (xcb_icccm_get_wm_class_reply(dpy, xcb_icccm_get_wm_class(dpy, win), &reply, NULL) == 1) {
@@ -92,6 +93,13 @@ void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win)
 
     tag_node(m, d, n, d, n->client->tags_field);
 
+    xcb_rectangle_t *frect = &n->client->floating_rectangle;
+    if (frect->x == 0 && frect->y == 0)
+        center(m->rectangle, frect);
+    fit_monitor(m, n->client);
+
+    arrange(m, d);
+
     bool give_focus = (takes_focus && (d == mon->desk || follow));
 
     if (is_visible(d, n)) {
@@ -105,13 +113,8 @@ void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win)
         stack_under(n);
     }
 
-    xcb_rectangle_t *frect = &n->client->floating_rectangle;
-    if (frect->x == 0 && frect->y == 0)
-        center(m->rectangle, frect);
-
-    fit_monitor(m, n->client);
-
-    arrange(m, d);
+    uint32_t values[] = {get_event_mask(n->client)};
+    xcb_change_window_attributes(dpy, c->window, XCB_CW_EVENT_MASK, values);
 
     if (visible && is_visible(d, n)) {
         if (d == m->desk)
@@ -124,9 +127,6 @@ void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win)
     if (give_focus)
         xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT, win, XCB_CURRENT_TIME);
 
-    uint32_t values[] = {(focus_follows_pointer ? CLIENT_EVENT_MASK_FFP : CLIENT_EVENT_MASK)};
-    xcb_change_window_attributes(dpy, c->window, XCB_CW_EVENT_MASK, values);
-
     num_clients++;
     ewmh_set_wm_desktop(n, d);
     ewmh_update_client_list();
@@ -134,8 +134,14 @@ void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win)
 
 void window_draw_border(node_t *n, bool focused_window, bool focused_monitor)
 {
-    if (n == NULL || n->client->border_width < 1)
+    if (n == NULL || (n->client->border_width < 1 && !n->client->frame)) {
+        return;
+    }
+
+    if (n->client->frame) {
+        draw_frame_background(n, focused_window, focused_monitor);
         return;
+    }
 
     xcb_window_t win = n->client->window;
     uint32_t border_color_pxl = get_border_color(n->client, focused_window, focused_monitor);
@@ -207,6 +213,58 @@ void window_draw_border(node_t *n, bool focused_window, bool focused_monitor)
     }
 }
 
+void draw_frame_background(node_t *n, bool focused_window, bool focused_monitor)
+{
+    if (n == NULL)
+        return;
+
+    xcb_window_t win = n->client->window;
+    uint32_t border_color_pxl = get_border_color(n->client, focused_window, focused_monitor);
+    uint32_t opacity = (focused_window ? (focused_monitor ? focused_frame_opacity : active_frame_opacity) : normal_frame_opacity) * 0xffffffff;
+    xcb_change_property(dpy, XCB_PROP_MODE_REPLACE, win, _NET_WM_WINDOW_OPACITY, XCB_ATOM_CARDINAL, 32, 1, &opacity);
+    uint8_t win_depth = root_depth;
+    xcb_get_geometry_reply_t *geo = xcb_get_geometry_reply(dpy, xcb_get_geometry(dpy, win), NULL);
+    if (geo != NULL)
+        win_depth = geo->depth;
+    free(geo);
+    xcb_rectangle_t rectangle = get_rectangle(n->client);
+    rectangle.x = rectangle.y = 0;
+    uint16_t width = rectangle.width;
+    uint16_t height = rectangle.height;
+    xcb_pixmap_t pixmap = xcb_generate_id(dpy);
+    xcb_create_pixmap(dpy, win_depth, pixmap, win, width, height);
+    xcb_gcontext_t gc = xcb_generate_id(dpy);
+    xcb_create_gc(dpy, gc, pixmap, 0, NULL);
+    xcb_change_gc(dpy, gc, XCB_GC_FOREGROUND, &border_color_pxl);
+    xcb_poly_fill_rectangle(dpy, pixmap, gc, 1, &rectangle);
+    if (n->split_mode == MODE_MANUAL) {
+        xcb_rectangle_t presel_rectangle = rectangle;
+        uint32_t presel_border_color_pxl;
+        get_color(presel_border_color, win, &presel_border_color_pxl);
+        xcb_change_gc(dpy, gc, XCB_GC_FOREGROUND, &presel_border_color_pxl);
+        switch (n->split_dir) {
+            case DIR_UP:
+                presel_rectangle.height = n->split_ratio * rectangle.height;
+                break;
+            case DIR_RIGHT:
+                presel_rectangle.width = (1 - n->split_ratio) * rectangle.width;
+                presel_rectangle.x = rectangle.width - presel_rectangle.width;
+                break;
+            case DIR_DOWN:
+                presel_rectangle.height = (1 - n->split_ratio) * rectangle.height;
+                presel_rectangle.y = rectangle.height - presel_rectangle.height;
+                break;
+            case DIR_LEFT:
+                presel_rectangle.width = n->split_ratio * rectangle.width;
+                break;
+        }
+        xcb_poly_fill_rectangle(dpy, pixmap, gc, 1, &presel_rectangle);
+    }
+    xcb_copy_area(dpy, pixmap, win, gc, 0, 0, 0, 0, width, height);
+    xcb_free_gc(dpy, gc);
+    xcb_free_pixmap(dpy, pixmap);
+}
+
 pointer_state_t *make_pointer_state(void)
 {
     pointer_state_t *p = malloc(sizeof(pointer_state_t));
@@ -332,7 +390,7 @@ void window_kill(monitor_t *m, desktop_t *d, node_t *n)
 
 void set_fullscreen(node_t *n, bool value)
 {
-    if (n == NULL || n->client->fullscreen == value)
+    if (n == NULL || n->client->frame || n->client->fullscreen == value)
         return;
 
     client_t *c = n->client;
@@ -349,7 +407,7 @@ void set_fullscreen(node_t *n, bool value)
 
 void set_floating(node_t *n, bool value)
 {
-    if (n == NULL || n->client->transient || n->client->fullscreen || n->client->floating == value)
+    if (n == NULL || n->client->transient || n->client->fullscreen || n->client->frame || n->client->floating == value)
         return;
 
     PRINTF("floating %X: %s\n", n->client->window, BOOLSTR(value));
@@ -404,7 +462,7 @@ void set_sticky(monitor_t *m, desktop_t *d, node_t *n, bool value)
         m->num_sticky--;
     }
 
-    window_draw_border(n, mon->desk->focus == n, m == mon);
+    window_draw_border(n, d->focus == n, m == mon);
 }
 
 void set_urgency(monitor_t *m, desktop_t *d, node_t *n, bool value)
@@ -695,3 +753,8 @@ void send_client_message(xcb_window_t win, xcb_atom_t property, xcb_atom_t value
 
     xcb_send_event(dpy, false, win, XCB_EVENT_MASK_NO_EVENT, (char *) &e);
 }
+
+uint32_t get_event_mask(client_t *c)
+{
+    return CLIENT_EVENT_MASK | (c->frame ? XCB_EVENT_MASK_EXPOSURE : 0) | (focus_follows_pointer ? XCB_EVENT_MASK_ENTER_WINDOW : 0);
+}
index a6f4177c2b76584d7faca27bb05b08a8751126ef..e05095379bd40128baa6468a7e98ea7b68aa0ce1 100644 (file)
--- a/window.h
+++ b/window.h
@@ -33,6 +33,7 @@
 
 void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win);
 void window_draw_border(node_t *n, bool focused_window, bool focused_monitor);
+void draw_frame_background(node_t *n, bool focused_window, bool focused_monitor);
 pointer_state_t *make_pointer_state(void);
 void center(xcb_rectangle_t a, xcb_rectangle_t *b);
 bool contains(xcb_rectangle_t a, xcb_rectangle_t b);
@@ -80,5 +81,6 @@ void get_atom(char *name, xcb_atom_t *atom);
 void set_atom(xcb_window_t win, xcb_atom_t atom, uint32_t value);
 bool has_proto(xcb_atom_t atom, xcb_icccm_get_wm_protocols_reply_t *protocols);
 void send_client_message(xcb_window_t win, xcb_atom_t property, xcb_atom_t value);
+uint32_t get_event_mask(client_t *c);
 
 #endif