The first is a fairly straightforward update to include all non-override redirect window types, this makes gimp work in tiled mode for example. This can go into master as far as i'm concerned.

The second is a first attempt at exposing and using window groups as an initial placement hint. This works for gimp's splash screen, and screenshots you make (for example). The splash screen for openoffice is part of a different window group, so it doesn't work there. The question is if this behaviour is "sane" enough to be in the C part, i think it is, but I'm open to discussion.

Maarten.
>From d22064b7ff54a8a9b7626b8d2c0e09f924ee128f Mon Sep 17 00:00:00 2001
From: Maarten Maathuis <[EMAIL PROTECTED]>
Date: Sun, 30 Nov 2008 01:47:24 +0100
Subject: [PATCH] ewmh: Support all known non-override redirect window types.

Signed-off-by: Maarten Maathuis <[EMAIL PROTECTED]>
---
 client.c          |   12 ++++++++++++
 common/atoms.list |    5 ++++-
 ewmh.c            |   11 ++++++++++-
 structs.h         |    6 ++++++
 4 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/client.c b/client.c
index 2f0cc43..27b25ca 100644
--- a/client.c
+++ b/client.c
@@ -319,6 +319,9 @@ client_layer_translator(client_t *c)
       case WINDOW_TYPE_DESKTOP:
         return LAYER_DESKTOP;
       case WINDOW_TYPE_DIALOG:
+      case WINDOW_TYPE_MENU:
+      case WINDOW_TYPE_TOOLBAR:
+      case WINDOW_TYPE_UTILITY:
         return LAYER_FLOAT;
       default:
         break;
@@ -1474,6 +1477,15 @@ luaA_client_index(lua_State *L)
           case WINDOW_TYPE_DIALOG:
             lua_pushliteral(L, "dialog");
             break;
+          case WINDOW_TYPE_MENU:
+            lua_pushliteral(L, "menu");
+            break;
+          case WINDOW_TYPE_TOOLBAR:
+            lua_pushliteral(L, "toolbar");
+            break;
+          case WINDOW_TYPE_UTILITY:
+            lua_pushliteral(L, "utility");
+            break;
           default:
             lua_pushliteral(L, "normal");
             break;
diff --git a/common/atoms.list b/common/atoms.list
index c8475de..6ab239d 100644
--- a/common/atoms.list
+++ b/common/atoms.list
@@ -15,11 +15,14 @@ _NET_WM_DESKTOP
 _NET_WM_ICON_NAME
 _NET_WM_VISIBLE_ICON_NAME
 _NET_WM_WINDOW_TYPE
-_NET_WM_WINDOW_TYPE_NORMAL
 _NET_WM_WINDOW_TYPE_DESKTOP
 _NET_WM_WINDOW_TYPE_DOCK
+_NET_WM_WINDOW_TYPE_TOOLBAR
+_NET_WM_WINDOW_TYPE_MENU
+_NET_WM_WINDOW_TYPE_UTILITY
 _NET_WM_WINDOW_TYPE_SPLASH
 _NET_WM_WINDOW_TYPE_DIALOG
+_NET_WM_WINDOW_TYPE_NORMAL
 _NET_WM_ICON
 _NET_WM_PID
 _NET_WM_STATE
diff --git a/ewmh.c b/ewmh.c
index 633261e..a4c241d 100644
--- a/ewmh.c
+++ b/ewmh.c
@@ -63,11 +63,14 @@ ewmh_init(int phys_screen)
         _NET_WM_VISIBLE_ICON_NAME,
         _NET_WM_DESKTOP,
         _NET_WM_WINDOW_TYPE,
-        _NET_WM_WINDOW_TYPE_NORMAL,
         _NET_WM_WINDOW_TYPE_DESKTOP,
         _NET_WM_WINDOW_TYPE_DOCK,
+        _NET_WM_WINDOW_TYPE_TOOLBAR,
+        _NET_WM_WINDOW_TYPE_MENU,
+        _NET_WM_WINDOW_TYPE_UTILITY,
         _NET_WM_WINDOW_TYPE_SPLASH,
         _NET_WM_WINDOW_TYPE_DIALOG,
+        _NET_WM_WINDOW_TYPE_NORMAL,
         _NET_WM_ICON,
         _NET_WM_PID,
         _NET_WM_STATE,
@@ -497,6 +500,12 @@ ewmh_client_check_hints(client_t *c)
                 c->type = MAX(c->type, WINDOW_TYPE_SPLASH);
             else if(state[i] == _NET_WM_WINDOW_TYPE_DOCK)
                 c->type = MAX(c->type, WINDOW_TYPE_DOCK);
+            else if(state[i] == _NET_WM_WINDOW_TYPE_MENU)
+                c->type = MAX(c->type, WINDOW_TYPE_MENU);
+            else if(state[i] == _NET_WM_WINDOW_TYPE_TOOLBAR)
+                c->type = MAX(c->type, WINDOW_TYPE_TOOLBAR);
+            else if(state[i] == _NET_WM_WINDOW_TYPE_UTILITY)
+                c->type = MAX(c->type, WINDOW_TYPE_UTILITY);
     }
 
     p_delete(&reply);
diff --git a/structs.h b/structs.h
index 689ef72..312497b 100644
--- a/structs.h
+++ b/structs.h
@@ -41,6 +41,12 @@ typedef enum
     WINDOW_TYPE_DOCK,
     WINDOW_TYPE_SPLASH,
     WINDOW_TYPE_DIALOG,
+    /* The ones below may have TRANSIENT_FOR, but are not plain dialogs.
+     * They were purposefully placed below DIALOG.
+     */
+    WINDOW_TYPE_MENU,
+    WINDOW_TYPE_TOOLBAR,
+    WINDOW_TYPE_UTILITY
 } window_type_t;
 
 typedef struct button_t button_t;
-- 
1.6.0.4

>From 0488c001a21e637d5c5dfc78e1cc0288bd2a58aa Mon Sep 17 00:00:00 2001
From: Maarten Maathuis <[EMAIL PROTECTED]>
Date: Sun, 30 Nov 2008 14:09:15 +0100
Subject: [PATCH] client,property: expose group and leader id, (initially) place 
group windows on the same tag.

Signed-off-by: Maarten Maathuis <[EMAIL PROTECTED]>
---
 client.c              |   68 +++++++++++++++++++++++++++++++++++++++---------
 common/atoms.list     |    4 +++
 common/tokenize.gperf |    2 +
 property.c            |   47 +++++++++++++++++++++++++++++++++
 property.h            |    1 +
 structs.h             |    6 ++++
 6 files changed, 115 insertions(+), 13 deletions(-)

diff --git a/client.c b/client.c
index 27b25ca..8db4bd0 100644
--- a/client.c
+++ b/client.c
@@ -41,29 +41,51 @@ DO_LUA_GC(client_t, client, "client", client_unref)
 /** Load windows properties, restoring client's tag
  * and floating state before awesome was restarted if any.
  * \param c A client pointer.
- * \param screen A virtual screen.
+ * \param screen_index Index of virtual screen (may be modified).
  * \return True if client had property, false otherwise.
  */
 static bool
-client_loadprops(client_t * c, screen_t *screen)
+client_loadprops(client_t * c, int *screen_index)
 {
+    screen_t *screen = NULL;
     ssize_t len;
-    tag_array_t *tags = &screen->tags;
+    tag_array_t *tags = NULL;
     char *prop = NULL;
-    xcb_get_property_cookie_t floating_q, fullscreen_q;
+    xcb_get_property_cookie_t floating_q, fullscreen_q, screen_q;
     xcb_get_property_reply_t *reply;
     void *data;
 
     if(!xutil_text_prop_get(globalconf.connection, c->win, _AWESOME_TAGS,
-                            &prop, &len))
-        return false;
+                            &prop, &len)) {
+        /* Are we a window with a group history? If so, use the last known 
screen and tags. */
+        if (!xutil_text_prop_get(globalconf.connection, c->group_win, 
_AWESOME_GROUP_LAST_TAGS,
+            &prop, &len))
+            return false; /* No group data found. */
+
+        screen_q = xcb_get_property_unchecked(globalconf.connection, false, 
c->group_win,
+                                             _AWESOME_GROUP_LAST_SCREEN, 
CARDINAL, 0, sizeof(int)*8);
+    } else {
+        /* Send the GetProperty requests which will be processed later */
+        floating_q = xcb_get_property_unchecked(globalconf.connection, false, 
c->win,
+                                                _AWESOME_FLOATING, CARDINAL, 
0, 1);
+
+        fullscreen_q = xcb_get_property_unchecked(globalconf.connection, 
false, c->win,
+                                                 _AWESOME_FULLSCREEN, 
CARDINAL, 0, 1);
+
+        screen_q = xcb_get_property_unchecked(globalconf.connection, false, 
c->win,
+                                                 _AWESOME_SCREEN, CARDINAL, 0, 
sizeof(int)*8);
+    }
 
-    /* Send the GetProperty requests which will be processed later */
-    floating_q = xcb_get_property_unchecked(globalconf.connection, false, 
c->win,
-                                            _AWESOME_FLOATING, CARDINAL, 0, 1);
+    /* check for screen */
+    reply = xcb_get_property_reply(globalconf.connection, screen_q, NULL);
 
-    fullscreen_q = xcb_get_property_unchecked(globalconf.connection, false, 
c->win,
-                                             _AWESOME_FULLSCREEN, CARDINAL, 0, 
1);
+    if(reply && reply->value_len && (data = xcb_get_property_value(reply)))
+        *screen_index = *(int *) data;
+    p_delete(&reply);
+
+    /* Delay until we have the best possible choice of screen index. */
+    screen = &globalconf.screens[*screen_index];
+    tags = &screen->tags;
 
     /* ignore property if the tag count isn't matching */
     if(len == tags->len)
@@ -437,6 +459,7 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t 
*wgeom, int phys_screen,
 
     /* Initial values */
     c->win = w;
+    c->group_store = true;
     c->geometry.x = c->geometries.floating.x = wgeom->x;
     c->geometry.y = c->geometries.floating.y = wgeom->y;
     c->geometry.width = c->geometries.floating.width = wgeom->width;
@@ -452,13 +475,13 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t 
*wgeom, int phys_screen,
     property_update_wm_normal_hints(c, NULL);
     property_update_wm_hints(c, NULL);
     property_update_wm_transient_for(c, NULL);
+    property_update_wm_client_leader(c, NULL);
 
     if(c->transient_for)
         screen = c->transient_for->screen;
 
     /* Try to load props if any */
-    client_loadprops(c, &globalconf.screens[screen]);
-
+    client_loadprops(c, &screen);
 
     /* Then check clients hints */
     ewmh_client_check_hints(c);
@@ -925,6 +948,14 @@ client_saveprops_tags(client_t *c)
         prop[i] = is_client_tagged(c, tags->tab[i]) ? '1' : '0';
 
     xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, c->win, 
_AWESOME_TAGS, STRING, 8, i, prop);
+    xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, c->win, 
_AWESOME_SCREEN, CARDINAL, sizeof(int)*8, 1, &c->screen);
+
+    /* Sometimes you don't want to change this, like upon unmanage where it 
would be emptied. */
+    if (c->group_store) {
+        /* Also save properties in group window, so new windows can follow the 
existing ones. */
+        xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, 
c->group_win, _AWESOME_GROUP_LAST_TAGS, STRING, 8, i, prop);
+        xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, 
c->group_win, _AWESOME_GROUP_LAST_SCREEN, CARDINAL, sizeof(int)*8, 1, 
&c->screen);
+    }
 }
 
 /** Unban a client and move it back into the viewport.
@@ -961,6 +992,8 @@ client_unmanage(client_t *c)
     /* remove client everywhere */
     client_list_detach(&globalconf.clients, c);
     stack_client_delete(c);
+    /* Keep the last saved tags for this group. */
+    c->group_store = false;
     for(int i = 0; i < tags->len; i++)
         untag_client(c, tags->tab[i]);
 
@@ -993,6 +1026,7 @@ client_unmanage(client_t *c)
 
     /* delete properties */
     xcb_delete_property(globalconf.connection, c->win, _AWESOME_TAGS);
+    xcb_delete_property(globalconf.connection, c->win, _AWESOME_SCREEN);
     xcb_delete_property(globalconf.connection, c->win, _AWESOME_FLOATING);
 
     if(client_hasstrut(c))
@@ -1427,6 +1461,8 @@ luaA_client_newindex(lua_State *L)
  * \lfield fullscreen The client is fullscreen or not.
  * \lfield maximized_horizontal The client is maximized horizontally or not.
  * \lfield maximized_vertical The client is maximized vertically or not.
+ * \lfield group_id Return an id unique to a group of windows.
+ * \lfield leader_id Return an id to a session related window.
  * \lfield transient_for Return the client the window is transient for.
  * \lfield size_hints A table with size hints of the client: user_position,
  *         user_size, program_position and program_size.
@@ -1499,6 +1535,12 @@ luaA_client_index(lua_State *L)
         lua_pushstring(L, hint.class);
         xcb_get_wm_class_reply_wipe(&hint);
         break;
+      case A_TK_GROUP_ID:
+        lua_pushnumber(L, (*c)->group_win);
+        break;
+      case A_TK_LEADER_ID:
+        lua_pushnumber(L, (*c)->leader_win);
+        break;
       case A_TK_INSTANCE:
         if(!xcb_get_wm_class_reply(globalconf.connection,
                                    
xcb_get_wm_class_unchecked(globalconf.connection, (*c)->win),
diff --git a/common/atoms.list b/common/atoms.list
index 6ab239d..c0604c9 100644
--- a/common/atoms.list
+++ b/common/atoms.list
@@ -40,6 +40,9 @@ UTF8_STRING
 _AWESOME_FLOATING
 _AWESOME_FULLSCREEN
 _AWESOME_TAGS
+_AWESOME_SCREEN
+_AWESOME_GROUP_LAST_TAGS
+_AWESOME_GROUP_LAST_SCREEN
 WM_PROTOCOLS
 WM_DELETE_WINDOW
 _XEMBED
@@ -53,3 +56,4 @@ _NET_WM_WINDOW_OPACITY
 _NET_SYSTEM_TRAY_ORIENTATION
 WM_CHANGE_STATE
 WM_WINDOW_ROLE
+WM_CLIENT_LEADER
diff --git a/common/tokenize.gperf b/common/tokenize.gperf
index f86e376..72bbb5d 100644
--- a/common/tokenize.gperf
+++ b/common/tokenize.gperf
@@ -31,6 +31,7 @@ font
 fullscreen
 gap
 geometry
+group_id
 grow
 height
 hide
@@ -42,6 +43,7 @@ instance
 invert
 label
 layout
+leader_id
 left
 len
 line
diff --git a/property.c b/property.c
index ddb2291..8357d92 100644
--- a/property.c
+++ b/property.c
@@ -69,6 +69,49 @@ property_handle_wm_transient_for(void *data,
     return 0;
 }
 
+
+/** Update leader hint of a client.
+ * \param c The client.
+ * \param reply (Optional) An existing reply.
+ */
+void
+property_update_wm_client_leader(client_t *c, xcb_get_property_reply_t *reply)
+{
+    xcb_get_property_cookie_t client_leader_q;
+    void *data;
+    bool no_reply = (reply == NULL) ? true : false;
+
+    if (!reply) {
+        client_leader_q = xcb_get_property_unchecked(globalconf.connection, 
false, c->win,
+                                                     WM_CLIENT_LEADER, WINDOW, 
0, 32);
+
+        reply = xcb_get_property_reply(globalconf.connection, client_leader_q, 
NULL);
+    }
+
+    if (reply && reply->value_len && (data = xcb_get_property_value(reply)))
+        c->leader_win = *(xcb_window_t *) data;
+
+    /* Only free when we weren't given a reply. */
+    if (no_reply)
+        p_delete(&reply);
+}
+
+static int
+property_handle_wm_client_leader(void *data,
+                                xcb_connection_t *connection,
+                                uint8_t state,
+                                xcb_window_t window,
+                                xcb_atom_t name,
+                                xcb_get_property_reply_t *reply)
+{
+     client_t *c = client_getbywin(window);
+
+    if (c)
+        property_update_wm_client_leader(c, reply);
+
+    return 0;
+}
+
 /** Update the size hints of a client.
  * \param c The client.
  */
@@ -196,6 +239,8 @@ property_update_wm_hints(client_t *c, 
xcb_get_property_reply_t *reply)
 
     if(wmh.flags & XCB_WM_HINT_INPUT)
         c->nofocus = !wmh.input;
+
+    c->group_win = wmh.window_group;
 }
 
 static int
@@ -395,6 +440,8 @@ void a_xcb_set_property_handlers(void)
     /* ICCCM stuff */
     xcb_property_set_handler(&globalconf.prophs, WM_TRANSIENT_FOR, UINT_MAX,
                              property_handle_wm_transient_for, NULL);
+    xcb_property_set_handler(&globalconf.prophs, WM_CLIENT_LEADER, UINT_MAX,
+                             property_handle_wm_client_leader, NULL);
     xcb_property_set_handler(&globalconf.prophs, WM_NORMAL_HINTS, UINT_MAX,
                              property_handle_wm_normal_hints, NULL);
     xcb_property_set_handler(&globalconf.prophs, WM_HINTS, UINT_MAX,
diff --git a/property.h b/property.h
index f62a520..e00851d 100644
--- a/property.h
+++ b/property.h
@@ -25,6 +25,7 @@
 #include "structs.h"
 
 void property_update_wm_transient_for(client_t *, xcb_get_property_reply_t *);
+void property_update_wm_client_leader(client_t *c, xcb_get_property_reply_t 
*reply);
 void property_update_wm_normal_hints(client_t *, xcb_get_property_reply_t *);
 void property_update_wm_hints(client_t *, xcb_get_property_reply_t *);
 void property_update_wm_name(client_t *);
diff --git a/structs.h b/structs.h
index 312497b..95d2b50 100644
--- a/structs.h
+++ b/structs.h
@@ -199,6 +199,12 @@ struct client_t
     window_type_t type;
     /** Window of the client */
     xcb_window_t win;
+     /** A window unique to a group of windows, possibly a dummy window 
(unmanaged). */
+    xcb_window_t group_win;
+    /** The leader of a session (this doesn't mean awesome supports sessions). 
*/
+    xcb_window_t leader_win;
+    /** Store last set info such as tags in group leader. Typically only 
disabled upon unmanage. */
+    bool group_store;
     /** Client logical screen */
     int screen;
     /** Client physical screen */
-- 
1.6.0.4

Reply via email to