]> git.sur5r.net Git - i3/i3/commitdiff
Implement support for WM_CLIENT_LEADER
authorMichael Stapelberg <michael@stapelberg.de>
Fri, 12 Nov 2010 22:46:03 +0000 (23:46 +0100)
committerMichael Stapelberg <michael@stapelberg.de>
Fri, 12 Nov 2010 22:46:03 +0000 (23:46 +0100)
include/data.h
include/handlers.h
include/window.h
src/floating.c
src/handlers.c
src/main.c
src/manage.c
src/window.c

index ae499126d1c5a8f03a174a33f1cd1c68f6d783dd..7acbb52ca29f376d81c3c232f0f5d37e3c247a9a 100644 (file)
@@ -212,6 +212,10 @@ struct xoutput {
 struct Window {
     xcb_window_t id;
 
+    /** Holds the xcb_window_t (just an ID) for the leader window (logical
+     * parent for toolwindows and similar floating windows) */
+    xcb_window_t leader;
+
     char *class_class;
     char *class_instance;
 
index 185320deeb81e5e11c856a79f51c10c5ace3d885..80096e2ed79983890bc21fe0189eed8cb818c3e3 100644 (file)
@@ -191,6 +191,7 @@ int handle_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t
 int handle_transient_for(void *data, xcb_connection_t *conn, uint8_t state,
                          xcb_window_t window, xcb_atom_t name,
                          xcb_get_property_reply_t *reply);
+#endif
 
 /**
  * Handles changes of the WM_CLIENT_LEADER atom which specifies if this is a
@@ -200,6 +201,5 @@ int handle_transient_for(void *data, xcb_connection_t *conn, uint8_t state,
 int handle_clientleader_change(void *data, xcb_connection_t *conn,
                                uint8_t state, xcb_window_t window,
                                xcb_atom_t name, xcb_get_property_reply_t *prop);
-#endif
 
 #endif
index 044bde708682060f6bfe604ba12e381e8f26cb93..071f4e2865ccd581b87aa26f2e85d5a0946beccd 100644 (file)
@@ -24,4 +24,10 @@ void window_update_name(i3Window *win, xcb_get_property_reply_t *prop);
  */
 void window_update_name_legacy(i3Window *win, xcb_get_property_reply_t *prop);
 
+/**
+ * Updates the CLIENT_LEADER (logical parent window).
+ *
+ */
+void window_update_leader(i3Window *win, xcb_get_property_reply_t *prop);
+
 #endif
index ab41ed609d255cdae57e39b3e5c17e3036b2ee8c..ea39f507ef7d51d95e2384c87235b41d0c555b49 100644 (file)
@@ -53,9 +53,18 @@ void floating_enable(Con *con, bool automatic) {
      * to (0, 0), so we push them to a reasonable position
      * (centered over their leader) */
     if (nc->rect.x == 0 && nc->rect.y == 0) {
-        /* TODO: client_leader support */
-        nc->rect.x = 400;
-        nc->rect.y = 400;
+        Con *leader;
+        if (con->window && con->window->leader != XCB_NONE &&
+            (leader = con_by_window_id(con->window->leader)) != NULL) {
+            DLOG("Centering above leader\n");
+            nc->rect.x = leader->rect.x + (leader->rect.width / 2) - (nc->rect.width / 2);
+            nc->rect.y = leader->rect.y + (leader->rect.height / 2) - (nc->rect.height / 2);
+        } else {
+            /* center the window on workspace as fallback */
+            Con *ws = nc->parent;
+            nc->rect.x = ws->rect.x + (ws->rect.width / 2) - (nc->rect.width / 2);
+            nc->rect.y = ws->rect.y + (ws->rect.height / 2) - (nc->rect.height / 2);
+        }
     }
 
     TAILQ_INSERT_TAIL(&(nc->nodes_head), con, nodes);
index a339abdf3591352aa286c39760bd53be6d7e2e38..d8b230f870b740b590eed145ccc92f106d69c91e 100644 (file)
@@ -846,6 +846,7 @@ int handle_transient_for(void *data, xcb_connection_t *conn, uint8_t state, xcb_
 
         return 1;
 }
+#endif
 
 /*
  * Handles changes of the WM_CLIENT_LEADER atom which specifies if this is a
@@ -854,25 +855,18 @@ int handle_transient_for(void *data, xcb_connection_t *conn, uint8_t state, xcb_
  */
 int handle_clientleader_change(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
                         xcb_atom_t name, xcb_get_property_reply_t *prop) {
-        if (prop == NULL) {
-                prop = xcb_get_property_reply(conn, xcb_get_property_unchecked(conn,
-                                        false, window, WM_CLIENT_LEADER, WINDOW, 0, 32), NULL);
-                if (prop == NULL)
-                        return 1;
-        }
-
-        Client *client = table_get(&by_child, window);
-        if (client == NULL)
-                return 1;
-
-        xcb_window_t *leader = xcb_get_property_value(prop);
-        if (leader == NULL)
-                return 1;
+    if (prop == NULL) {
+        prop = xcb_get_property_reply(conn, xcb_get_property_unchecked(conn,
+                                false, window, WM_CLIENT_LEADER, WINDOW, 0, 32), NULL);
+        if (prop == NULL)
+            return 1;
+    }
 
-        DLOG("Client leader changed to %08x\n", *leader);
+    Con *con;
+    if ((con = con_by_window_id(window)) == NULL || con->window == NULL)
+        return 1;
 
-        client->leader = *leader;
+    window_update_leader(con->window, prop);
 
-        return 1;
+    return 1;
 }
-#endif
index 417c2b27d881713e9005150bffc500aef987ebe5..6ca3075ea2767e6a0d8267fe5115e1160ba8970e 100644 (file)
@@ -267,6 +267,9 @@ int main(int argc, char *argv[]) {
     /* Watch WM_NORMAL_HINTS (aspect ratio, size increments, …) */
     xcb_property_set_handler(&prophs, WM_NORMAL_HINTS, UINT_MAX, handle_normal_hints, NULL);
 
+    /* Watch WM_CLIENT_LEADER (= logical parent window for toolbars etc.) */
+    xcb_property_set_handler(&prophs, atoms[WM_CLIENT_LEADER], UINT_MAX, handle_clientleader_change, NULL);
+
     /* Set up the atoms we support */
     xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, atoms[_NET_SUPPORTED], ATOM, 32, 7, atoms);
     /* Set up the window manager’s name */
index e81d906a6242eb04cc93645358668238aca76fba..0fb2fc9bf20425073b09538b4a1e9a3da252309d 100644 (file)
@@ -144,6 +144,7 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
     window_update_class(cwindow, xcb_get_property_reply(conn, class_cookie, NULL));
     window_update_name_legacy(cwindow, xcb_get_property_reply(conn, title_cookie, NULL));
     window_update_name(cwindow, xcb_get_property_reply(conn, utf8_title_cookie, NULL));
+    window_update_leader(cwindow, xcb_get_property_reply(conn, leader_cookie, NULL));
 
     xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, wm_type_cookie, NULL);
     if (xcb_reply_contains_atom(reply, atoms[_NET_WM_WINDOW_TYPE_DOCK])) {
@@ -321,9 +322,6 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
                 preply = xcb_get_property_reply(conn, class_cookie, NULL);
                 handle_windowclass_change(NULL, conn, 0, new->child, WM_CLASS, preply);
 
-                preply = xcb_get_property_reply(conn, leader_cookie, NULL);
-                handle_clientleader_change(NULL, conn, 0, new->child, atoms[WM_CLIENT_LEADER], preply);
-
                 /* if WM_CLIENT_LEADER is set, we put the new window on the
                  * same window as its leader. This might be overwritten by
                  * assignments afterwards. */
index 93812b3f875bc5c4df761038300a0cc4fd73c446..e22fb1c03bb1dbcc7d0ffa46b719243cea25157d 100644 (file)
@@ -96,3 +96,22 @@ void window_update_name_legacy(i3Window *win, xcb_get_property_reply_t *prop) {
     win->name_json = strdup(new_name);
     win->name_len = strlen(new_name);
 }
+
+/**
+ * Updates the CLIENT_LEADER (logical parent window).
+ *
+ */
+void window_update_leader(i3Window *win, xcb_get_property_reply_t *prop) {
+    if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
+        DLOG("prop == NULL\n");
+        return;
+    }
+
+    xcb_window_t *leader = xcb_get_property_value(prop);
+    if (leader == NULL)
+        return;
+
+    DLOG("Client leader changed to %08x\n", *leader);
+
+    win->leader = *leader;
+}