From ad9be5402a47691486f0b55528a7501432ff31e5 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 12 Nov 2010 23:46:03 +0100 Subject: [PATCH] Implement support for WM_CLIENT_LEADER --- include/data.h | 4 ++++ include/handlers.h | 2 +- include/window.h | 6 ++++++ src/floating.c | 15 ++++++++++++--- src/handlers.c | 30 ++++++++++++------------------ src/main.c | 3 +++ src/manage.c | 4 +--- src/window.c | 19 +++++++++++++++++++ 8 files changed, 58 insertions(+), 25 deletions(-) diff --git a/include/data.h b/include/data.h index ae499126..7acbb52c 100644 --- a/include/data.h +++ b/include/data.h @@ -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; diff --git a/include/handlers.h b/include/handlers.h index 185320de..80096e2e 100644 --- a/include/handlers.h +++ b/include/handlers.h @@ -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 diff --git a/include/window.h b/include/window.h index 044bde70..071f4e28 100644 --- a/include/window.h +++ b/include/window.h @@ -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 diff --git a/src/floating.c b/src/floating.c index ab41ed60..ea39f507 100644 --- a/src/floating.c +++ b/src/floating.c @@ -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); diff --git a/src/handlers.c b/src/handlers.c index a339abdf..d8b230f8 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -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 diff --git a/src/main.c b/src/main.c index 417c2b27..6ca3075e 100644 --- a/src/main.c +++ b/src/main.c @@ -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 */ diff --git a/src/manage.c b/src/manage.c index e81d906a..0fb2fc9b 100644 --- a/src/manage.c +++ b/src/manage.c @@ -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. */ diff --git a/src/window.c b/src/window.c index 93812b3f..e22fb1c0 100644 --- a/src/window.c +++ b/src/window.c @@ -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; +} -- 2.39.2