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;
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
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
*/
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
* 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);
return 1;
}
+#endif
/*
* Handles changes of the WM_CLIENT_LEADER atom which specifies if this is a
*/
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
/* 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 */
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])) {
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. */
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;
+}