From 76ed7207cd7facb1fcc16acc428d7913a62f6e44 Mon Sep 17 00:00:00 2001
From: Olivier Fourdan <fourdan.olivier@wanadoo.fr>
Date: Fri, 8 Nov 2002 14:25:22 +0000
Subject: [PATCH] Add NET_WM_STATE_ABOVE and NET_WM_STATE_BELOW hints support
 (EWMH 1.2)

(Old svn revision: 10697)
---
 src/client.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++---
 src/client.h |   6 ++-
 src/hints.c  |   6 +++
 src/hints.h  |   4 ++
 4 files changed, 117 insertions(+), 7 deletions(-)

diff --git a/src/client.c b/src/client.c
index 8aabb40dc..770431015 100644
--- a/src/client.c
+++ b/src/client.c
@@ -98,7 +98,7 @@ struct _ButtonPressData
 void clientSetNetState(Client * c)
 {
     int i;
-    Atom data[12];
+    Atom data[16];
 
     g_return_if_fail(c != NULL);
     DBG("entering clientSetNetState\n");
@@ -151,6 +151,16 @@ void clientSetNetState(Client * c)
         DBG("clientSetNetState : fullscreen\n");
         data[i++] = net_wm_state_fullscreen;
     }
+    else if(c->above)
+    {
+        DBG("clientSetNetState : above\n");
+        data[i++] = net_wm_state_above;
+    }
+    else if(c->below)
+    {
+        DBG("clientSetNetState : below\n");
+        data[i++] = net_wm_state_below;
+    }
     if(c->hidden)
     {
         DBG("clientSetNetState : hidden\n");
@@ -206,11 +216,21 @@ static void clientGetNetState(Client * c)
                 c->win_state |= WIN_STATE_MAXIMIZED_VERT;
                 c->maximized = True;
             }
-            else if(atoms[i] == net_wm_state_fullscreen)
+            else if((atoms[i] == net_wm_state_fullscreen) && !(c->above) && !(c->below))
             {
                 DBG("clientGetNetState : fullscreen\n");
                 c->fullscreen = True;
             }
+            else if((atoms[i] == net_wm_state_above) && !(c->fullscreen) && !(c->below))
+            {
+                DBG("clientGetNetState : above\n");
+                c->above = True;
+            }
+            else if((atoms[i] == net_wm_state_below) && !(c->above) && !(c->fullscreen))
+            {
+                DBG("clientGetNetState : below\n");
+                c->below = True;
+            }
             else if(atoms[i] == net_wm_state_modal)
             {
                 DBG("clientGetNetState : modal\n");
@@ -375,7 +395,7 @@ void clientUpdateNetState(Client * c, XClientMessageEvent * ev)
         }
     }
 
-    if((first == net_wm_state_fullscreen) || (second == net_wm_state_fullscreen))
+    if(((first == net_wm_state_fullscreen) || (second == net_wm_state_fullscreen)) && !(c->above) && !(c->below))
     {
         if((action == NET_WM_STATE_ADD) && !(c->fullscreen))
         {
@@ -392,6 +412,40 @@ void clientUpdateNetState(Client * c, XClientMessageEvent * ev)
         clientToggleFullscreen(c);
     }
 
+    if(((first == net_wm_state_above) || (second == net_wm_state_above)) && !(c->fullscreen) && !(c->below))
+    {
+        if((action == NET_WM_STATE_ADD) && !(c->above))
+        {
+            c->above = True;
+        }
+        else if((action == NET_WM_STATE_REMOVE) && (c->above))
+        {
+            c->above = False;
+        }
+        else if(action == NET_WM_STATE_TOGGLE)
+        {
+            c->above = ((c->above) ? False : True);
+        }
+        clientToggleAbove(c);
+    }
+
+    if(((first == net_wm_state_below) || (second == net_wm_state_below)) && !(c->fullscreen) && !(c->above))
+    {
+        if((action == NET_WM_STATE_ADD) && !(c->below))
+        {
+            c->below = True;
+        }
+        else if((action == NET_WM_STATE_REMOVE) && (c->below))
+        {
+            c->below = False;
+        }
+        else if(action == NET_WM_STATE_TOGGLE)
+        {
+            c->below = ((c->below) ? False : True);
+        }
+        clientToggleBelow(c);
+    }
+
     if((first == net_wm_state_skip_pager) || (second == net_wm_state_skip_pager))
     {
         if((action == NET_WM_STATE_ADD) && !(c->skip_pager))
@@ -1680,6 +1734,8 @@ void clientFrame(Window w)
 
     /* Initialize structure */
     c->focus = False;
+    c->above = False;
+    c->below = False;
     c->fullscreen = False;
     c->has_border = True;
     c->has_menu = True;
@@ -2329,13 +2385,13 @@ void clientToggleFullscreen(Client * c)
         c->fullscreen_old_y = c->y;
         c->fullscreen_old_width = c->width;
         c->fullscreen_old_height = c->height;
-        c->fullscreen_old_layer = c->win_layer;
+        c->initial_layer = c->win_layer;
 
         wc.x = 0;
         wc.y = 0;
         wc.width = XDisplayWidth(dpy, screen);
         wc.height = XDisplayHeight(dpy, screen);
-        layer = WIN_LAYER_ABOVE_DOCK;
+        layer = WIN_LAYER_FULLSCREEN;
     }
     else
     {
@@ -2343,13 +2399,53 @@ void clientToggleFullscreen(Client * c)
         wc.y = c->fullscreen_old_y;
         wc.width = c->fullscreen_old_width;
         wc.height = c->fullscreen_old_height;
-        layer = c->fullscreen_old_layer;
+        layer = c->initial_layer;
     }
     clientSetNetState(c);
     clientSetLayer(c, layer);
     clientConfigure(c, &wc, CWX | CWY | CWWidth | CWHeight);
 }
 
+void clientToggleAbove(Client * c)
+{
+    int layer;
+
+    g_return_if_fail(c != NULL);
+    DBG("entering clientToggleAbove\n");
+    DBG("toggle above client \"%s\" (%#lx)\n", c->name, c->window);
+
+    if(c->above)
+    {
+        layer = WIN_LAYER_ABOVE;
+    }
+    else
+    {
+        layer = c->initial_layer;
+    }
+    clientSetNetState(c);
+    clientSetLayer(c, layer);
+}
+
+void clientToggleBelow(Client * c)
+{
+    int layer;
+
+    g_return_if_fail(c != NULL);
+    DBG("entering clientToggleBelow\n");
+    DBG("toggle below client \"%s\" (%#lx)\n", c->name, c->window);
+
+    if(c->below)
+    {
+        layer = WIN_LAYER_BELOW;
+    }
+    else
+    {
+        layer = c->initial_layer;
+    }
+    clientSetNetState(c);
+    clientSetLayer(c, layer);
+}
+
 void clientUpdateFocus(Client * c)
 {
     Client *c2 = ((client_focus != c) ? client_focus : NULL);
diff --git a/src/client.h b/src/client.h
index 114fb5d29..937b4f1c3 100644
--- a/src/client.h
+++ b/src/client.h
@@ -199,12 +199,14 @@ struct _Client
     int fullscreen_old_y;
     int fullscreen_old_width;
     int fullscreen_old_height;
-    int fullscreen_old_layer;
+    int initial_layer;
     int ncmap;
     int button_pressed[BUTTON_COUNT];
     int struts[4];
     char *name;
     unsigned int focus:1;
+    unsigned int above:1;
+    unsigned int below:1;
     unsigned int fullscreen:1;
     unsigned int has_border:1;
     unsigned int has_menu:1;
@@ -267,6 +269,8 @@ void clientToggleSticky(Client *);
 inline void clientRemoveMaximizeFlag(Client *);
 void clientToggleMaximized(Client *, int);
 void clientToggleFullscreen(Client *);
+void clientToggleAbove(Client *);
+void clientToggleBelow(Client *);
 void clientUpdateFocus(Client *);
 inline gboolean clientAcceptFocus(Client * c);
 void clientSetFocus(Client *, int);
diff --git a/src/hints.c b/src/hints.c
index 5bd1b8d7b..57217301d 100644
--- a/src/hints.c
+++ b/src/hints.c
@@ -85,6 +85,8 @@ Atom net_wm_icon_name;
 Atom net_wm_moveresize;
 Atom net_wm_name;
 Atom net_wm_state;
+Atom net_wm_state_above;
+Atom net_wm_state_below;
 Atom net_wm_state_fullscreen;
 Atom net_wm_state_hidden;
 Atom net_wm_state_maximized_horz;
@@ -336,6 +338,8 @@ void initNetHints(Display * dpy)
     net_wm_icon = XInternAtom(dpy, "_NET_WM_ICON", False);
     net_wm_moveresize = XInternAtom(dpy, "_NET_WM_MOVERESIZE", False);
     net_wm_name = XInternAtom(dpy, "_NET_WM_NAME", False);
+    net_wm_state_above = XInternAtom(dpy, "_NET_WM_STATE_ABOVE", False);
+    net_wm_state_below = XInternAtom(dpy, "_NET_WM_STATE_BELOW", False);
     net_wm_state_fullscreen = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
     net_wm_state_hidden = XInternAtom(dpy, "_NET_WM_STATE_HIDDEN", False);
     net_wm_state_maximized_horz = XInternAtom(dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
@@ -414,6 +418,8 @@ void set_net_supported_hint(Display * dpy, int screen, Window check_win)
      */
     atoms[i++] = net_wm_name;
     atoms[i++] = net_wm_state;
+    atoms[i++] = net_wm_state_above;
+    atoms[i++] = net_wm_state_below;
     atoms[i++] = net_wm_state_fullscreen;
     atoms[i++] = net_wm_state_hidden;
     atoms[i++] = net_wm_state_maximized_horz;
diff --git a/src/hints.h b/src/hints.h
index b43c4945d..c118639fc 100644
--- a/src/hints.h
+++ b/src/hints.h
@@ -74,6 +74,8 @@
 #define WIN_LAYER_ONTOP 			6
 #define WIN_LAYER_DOCK  			8
 #define WIN_LAYER_ABOVE_DOCK			10
+#define WIN_LAYER_ABOVE				12
+#define WIN_LAYER_FULLSCREEN			14
 
 #define NET_WM_MOVERESIZE_SIZE_TOPLEFT  	0
 #define NET_WM_MOVERESIZE_SIZE_TOP		1
@@ -148,6 +150,8 @@ extern Atom net_wm_icon_name;
 extern Atom net_wm_moveresize;
 extern Atom net_wm_name;
 extern Atom net_wm_state;
+extern Atom net_wm_state_above;
+extern Atom net_wm_state_below;
 extern Atom net_wm_state_fullscreen;
 extern Atom net_wm_state_hidden;
 extern Atom net_wm_state_maximized_horz;
-- 
GitLab