[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] Double Window Borders



Hi,

I managed to implement double window borders (through
`XSetWindowBorderPixmap`).

Greetings,
-- 
 b.d
(| |)
 ^ ^
>From f1c8f9502a06a61d0a7800685ffa5e134ff0eccd Mon Sep 17 00:00:00 2001
From: Bastien Dejean <nihilhill _at_ gmail _dot_ com>
Date: Sat, 21 Jul 2012 20:16:19 +0200
Subject: [PATCH] New settings: double_window_borders and window_border_inner_color

---
 BUGS                 |  2 --
 NEWS                 |  2 ++
 doc/herbstluftwm.txt |  8 ++++++++
 src/clientlist.c     | 49 ++++++++++++++++++++++++++++++++++++++++++-------
 src/clientlist.h     |  1 +
 src/settings.c       |  4 +++-
 src/utils.c          | 36 ++++++++++++++++++++++++++++++++++++
 src/utils.h          |  5 +++++
 8 files changed, 97 insertions(+), 10 deletions(-)

diff --git a/BUGS b/BUGS
index 3c91bb1..4f54572 100644
--- a/BUGS
+++ b/BUGS
@@ -49,8 +49,6 @@ Planned features:
     - or: chain commands like: cmdchain 4 cmd1 arg1a arg1b arg1c cmd2 arg2a
       arg2b
     - alias commands: alias shortcmd = cmd default arg, alias shortcmd --delete
-    - double window border to give a good contrast to dark backgrounded and
-      light backgrounded windows.
     - provide multiple mechanisms to split clients to child frames:
          * 100:0 (and vice versa)
          * 50:50
diff --git a/NEWS b/NEWS
index b3f003e..1f93f6b 100644
--- a/NEWS
+++ b/NEWS
@@ -27,6 +27,8 @@ Changes:
     * only one Makefile for herbstluftwm and herbstclient. The herbstclient
       binary now is put in the main directory.
     * new settings: smart_frame_surroundings and smart_window_surroundings
+    * new setting: double_window_borders
+    * new setting: window_border_inner_color
     * new option --skip-invisible for cycle_all
 
 Release 0.3 on 2012-04-12
diff --git a/doc/herbstluftwm.txt b/doc/herbstluftwm.txt
index d7da1fb..bae0e01 100644
--- a/doc/herbstluftwm.txt
+++ b/doc/herbstluftwm.txt
@@ -589,6 +589,9 @@ window_border_normal_color (String/Color)::
 window_border_urgent_color (String/Color)::
     Border color of an unfocused but urgent window.
 
+window_border_inner_color (String/Color)::
+    Color of the inner border of a window.
+
 always_show_frame (Integer)::
     If set, all frames are displayed. If unset, only frames with focus or with
     windows in it are displayed.
@@ -627,6 +630,11 @@ smart_window_surroundings (Integer)::
     If set, window borders and gaps will be removed when there's no ambiguity
     regarding the focused window.
 
+double_window_borders (Integer)::
+    If set, one pixel inner window borders will be drawn in addition to the
+    regular window borders. It will only activate if window_border_width is
+    greater than one.
+
 focus_follows_shift (Integer)::
     If set, focus stays in the window, if window is shifted to another frame.
     If unset, focus stays in the frame.
diff --git a/src/clientlist.c b/src/clientlist.c
index b67be6f..69c927d 100644
--- a/src/clientlist.c
+++ b/src/clientlist.c
@@ -34,9 +34,11 @@ int* g_window_border_width;
 int* g_raise_on_focus;
 int* g_snap_gap;
 int* g_smart_window_surroundings;
+int* g_double_window_borders;
 unsigned long g_window_border_active_color;
-unsigned long g_window_border_urgent_color;
 unsigned long g_window_border_normal_color;
+unsigned long g_window_border_urgent_color;
+unsigned long g_window_border_inner_color;
 
 GHashTable* g_clients; // container of all clients
 
@@ -61,6 +63,7 @@ static void fetch_colors() {
     g_window_gap = &(settings_find("window_gap")->value.i);
     g_snap_gap = &(settings_find("snap_gap")->value.i);
     g_smart_window_surroundings = &(settings_find("smart_window_surroundings")->value.i);
+    g_double_window_borders = &(settings_find("double_window_borders")->value.i);
     g_raise_on_focus = &(settings_find("raise_on_focus")->value.i);
     char* str = settings_find("window_border_normal_color")->value.s;
     g_window_border_normal_color = getcolor(str);
@@ -68,6 +71,8 @@ static void fetch_colors() {
     g_window_border_active_color = getcolor(str);
     str = settings_find("window_border_urgent_color")->value.s;
     g_window_border_urgent_color = getcolor(str);
+    str = settings_find("window_border_inner_color")->value.s;
+    g_window_border_inner_color = getcolor(str);
 }
 
 void clientlist_init() {
@@ -217,11 +222,17 @@ void client_destroy(HSClient* client) {
 }
 
 void window_unfocus(Window window) {
-    XSetWindowBorder(g_display, window, g_window_border_normal_color);
+    if (*g_double_window_borders)
+        set_window_double_border(window, g_window_border_inner_color, g_window_border_normal_color);
+    else
+        XSetWindowBorder(g_display, window, g_window_border_normal_color);
     HSClient* c = get_client_from_window(window);
     if (c) {
         if (c->urgent) {
-            XSetWindowBorder(g_display, window, g_window_border_urgent_color);
+            if (*g_double_window_borders)
+                set_window_double_border(window, g_window_border_inner_color, g_window_border_urgent_color);
+            else
+                XSetWindowBorder(g_display, window, g_window_border_urgent_color);
         }
         grab_client_buttons(c, false);
     }
@@ -246,7 +257,10 @@ void window_focus(Window window) {
     // unfocus last one
     window_unfocus(lastfocus);
     // change window-colors
-    XSetWindowBorder(g_display, window, g_window_border_active_color);
+    if (*g_double_window_borders)
+        set_window_double_border(window, g_window_border_inner_color, g_window_border_active_color);
+    else
+        XSetWindowBorder(g_display, window, g_window_border_active_color);
     // set keyboardfocus
     XSetInputFocus(g_display, window, RevertToPointerRoot, CurrentTime);
     if (window != lastfocus) {
@@ -278,10 +292,15 @@ void client_setup_border(HSClient* client, bool focused) {
         g_window_border_active_color,
     };
     if (client->urgent) {
-        XSetWindowBorder(g_display, client->window,
-                         g_window_border_urgent_color);
+        if (*g_double_window_borders)
+            set_window_double_border(client->window, g_window_border_inner_color, g_window_border_urgent_color);
+        else
+            XSetWindowBorder(g_display, client->window, g_window_border_urgent_color);
     } else {
-        XSetWindowBorder(g_display, client->window, colors[focused ? 1 : 0]);
+        if (*g_double_window_borders)
+            set_window_double_border(client->window, g_window_border_inner_color, colors[focused ? 1 : 0]);
+        else
+            XSetWindowBorder(g_display, client->window, colors[focused ? 1 : 0]);
     }
 }
 
@@ -353,6 +372,10 @@ void client_resize(HSClient* client, XRectangle rect, HSFrame* frame) {
 
     XSetWindowBorderWidth(g_display, win, border_width);
     XMoveResizeWindow(g_display, win, rect.x, rect.y, rect.width, rect.height);
+    if (*g_double_window_borders) {
+        unsigned long current_border_color = get_window_border_color(client);
+        set_window_double_border(win, g_window_border_inner_color, current_border_color);
+    }
     //// send new size to client
     //// WHY SHOULD I? -> faster? only one call?
     //XConfigureEvent ce;
@@ -411,6 +434,10 @@ void client_resize_floating(HSClient* client, HSMonitor* m) {
     XSetWindowBorderWidth(g_display, client->window, *g_window_border_width);
     XMoveResizeWindow(g_display, client->window,
         rect.x, rect.y, rect.width, rect.height);
+    if (*g_double_window_borders) {
+        unsigned long current_border_color = get_window_border_color(client);
+        set_window_double_border(client->window, g_window_border_inner_color, current_border_color);
+    }
 }
 
 XRectangle client_outer_floating_rect(HSClient* client) {
@@ -597,6 +624,14 @@ int client_set_property_command(int argc, char** argv) {
     return 0;
 }
 
+unsigned long get_window_border_color(HSClient* client) {
+    Window win = client->window;
+    unsigned long current_border_color = (win == frame_focused_window(g_cur_frame) ? g_window_border_active_color : g_window_border_normal_color);
+    if (client->urgent)
+        current_border_color = g_window_border_urgent_color;
+    return current_border_color;
+}
+
 static bool is_client_urgent(void* key, HSClient* client, void* data) {
     (void) key;
     (void) data;
diff --git a/src/clientlist.h b/src/clientlist.h
index b484aa2..5c2812b 100644
--- a/src/clientlist.h
+++ b/src/clientlist.h
@@ -76,6 +76,7 @@ void window_show(Window win);
 void window_hide(Window win);
 void window_set_visible(Window win, bool visible);
 
+unsigned long get_window_border_color(HSClient* client);
 
 #endif
 
diff --git a/src/settings.c b/src/settings.c
index c036a0b..2da2d6a 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -52,6 +52,7 @@ SettingsPair g_settings[] = {
     SET_STRING( "window_border_active_color",      "red",       CL_COLORS   ),
     SET_STRING( "window_border_normal_color",      "blue",      CL_COLORS   ),
     SET_STRING( "window_border_urgent_color",      "orange",    CL_COLORS   ),
+    SET_STRING( "window_border_inner_color",       "black",     CL_COLORS   ),
     SET_INT(    "always_show_frame",               0,           RELAYOUT    ),
     SET_INT(    "default_direction_external_only", 0,           NULL        ),
     SET_INT(    "default_frame_layout",            0,           FR_COLORS   ),
@@ -62,8 +63,9 @@ SettingsPair g_settings[] = {
     SET_INT(    "raise_on_focus",                  0,           NULL        ),
     SET_INT(    "raise_on_click",                  1,           NULL        ),
     SET_INT(    "gapless_grid",                    1,           RELAYOUT    ),
-    SET_INT(    "smart_window_surroundings",       0,           RELAYOUT    ),
     SET_INT(    "smart_frame_surroundings",        0,           RELAYOUT    ),
+    SET_INT(    "smart_window_surroundings",       0,           RELAYOUT    ),
+    SET_INT(    "double_window_borders",           0,           RELAYOUT    ),
     SET_INT(    "monitors_locked",                 0,           LOCK_CHANGED),
     SET_INT(    "auto_detect_monitors",            0,           NULL        ),
     SET_STRING( "tree_style",                      "*| +`--.",  FR_COLORS   ),
diff --git a/src/utils.c b/src/utils.c
index 0a4d203..1130b1b 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -304,4 +304,40 @@ void* table_find(void* start, size_t elem_size, size_t count,
     return NULL;
 }
 
+void set_window_double_border(Window win, unsigned long inner_border_color, unsigned long outer_border_color) {
+    XWindowAttributes wa;
+
+    if (!XGetWindowAttributes(g_display, win, &wa))
+        return;
+
+    int border_width = wa.border_width;
 
+    if (border_width < 2)
+        return;
+
+    int width = wa.width;
+    int height = wa.height;
+
+    unsigned int g_depth = DefaultDepth(g_display, DefaultScreen(g_display));
+
+    int full_width = width + 2 * border_width;
+    int full_height = height + 2 * border_width;
+
+    XSegment segments[4] =
+    {
+        { width, 0, width, height },
+        { full_width - 1, 0, full_width - 1, height },
+        { 0, height, width, height },
+        { 0, full_height - 1, width, full_height - 1 }
+    };
+
+    Pixmap pix = XCreatePixmap(g_display, g_root, full_width, full_height, g_depth);
+    GC gc = XCreateGC(g_display, pix, 0, NULL);
+    XSetForeground(g_display, gc, outer_border_color);
+    XFillRectangle(g_display, pix, gc, 0, 0, full_width, full_height);
+    XSetForeground(g_display, gc, inner_border_color);
+    XDrawSegments(g_display, pix, gc, segments, 4);
+    XDrawPoint(g_display, pix, gc, full_width - 1, full_height - 1);
+    XSetWindowBorderPixmap(g_display, win, pix);
+    XFreePixmap(g_display, pix);
+}
diff --git a/src/utils.h b/src/utils.h
index 99412dc..cbff41b 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -63,6 +63,11 @@ bool memberequals_int(void* pmember, void* needle);
 
 void* table_find(void* start, size_t elem_size, size_t count,
                  size_t member_offset, MemberEquals equals, void* needle);
+
+void set_window_double_border(Window win,
+                              unsigned long inner_border_color,
+                              unsigned long outer_border_color);
+
 #define STATIC_TABLE_FIND(TYPE, TABLE, MEMBER, EQUALS, NEEDLE)  \
     ((TYPE*) table_find((TABLE),                                \
                         sizeof(TABLE[0]),                       \
-- 
1.7.11.2

------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/