Implement support for WM_CLIENT_LEADER
This commit is contained in:
parent
1bb6906c56
commit
ad9be5402a
|
@ -212,6 +212,10 @@ struct xoutput {
|
||||||
struct Window {
|
struct Window {
|
||||||
xcb_window_t id;
|
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_class;
|
||||||
char *class_instance;
|
char *class_instance;
|
||||||
|
|
||||||
|
|
|
@ -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,
|
int handle_transient_for(void *data, xcb_connection_t *conn, uint8_t state,
|
||||||
xcb_window_t window, xcb_atom_t name,
|
xcb_window_t window, xcb_atom_t name,
|
||||||
xcb_get_property_reply_t *reply);
|
xcb_get_property_reply_t *reply);
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles changes of the WM_CLIENT_LEADER atom which specifies if this is a
|
* 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,
|
int handle_clientleader_change(void *data, xcb_connection_t *conn,
|
||||||
uint8_t state, xcb_window_t window,
|
uint8_t state, xcb_window_t window,
|
||||||
xcb_atom_t name, xcb_get_property_reply_t *prop);
|
xcb_atom_t name, xcb_get_property_reply_t *prop);
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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);
|
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
|
#endif
|
||||||
|
|
|
@ -53,9 +53,18 @@ void floating_enable(Con *con, bool automatic) {
|
||||||
* to (0, 0), so we push them to a reasonable position
|
* to (0, 0), so we push them to a reasonable position
|
||||||
* (centered over their leader) */
|
* (centered over their leader) */
|
||||||
if (nc->rect.x == 0 && nc->rect.y == 0) {
|
if (nc->rect.x == 0 && nc->rect.y == 0) {
|
||||||
/* TODO: client_leader support */
|
Con *leader;
|
||||||
nc->rect.x = 400;
|
if (con->window && con->window->leader != XCB_NONE &&
|
||||||
nc->rect.y = 400;
|
(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);
|
TAILQ_INSERT_TAIL(&(nc->nodes_head), con, nodes);
|
||||||
|
|
|
@ -846,6 +846,7 @@ int handle_transient_for(void *data, xcb_connection_t *conn, uint8_t state, xcb_
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handles changes of the WM_CLIENT_LEADER atom which specifies if this is a
|
* 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,
|
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) {
|
xcb_atom_t name, xcb_get_property_reply_t *prop) {
|
||||||
if (prop == NULL) {
|
if (prop == NULL) {
|
||||||
prop = xcb_get_property_reply(conn, xcb_get_property_unchecked(conn,
|
prop = xcb_get_property_reply(conn, xcb_get_property_unchecked(conn,
|
||||||
false, window, WM_CLIENT_LEADER, WINDOW, 0, 32), NULL);
|
false, window, WM_CLIENT_LEADER, WINDOW, 0, 32), NULL);
|
||||||
if (prop == NULL)
|
if (prop == NULL)
|
||||||
return 1;
|
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;
|
|
||||||
|
|
||||||
DLOG("Client leader changed to %08x\n", *leader);
|
|
||||||
|
|
||||||
client->leader = *leader;
|
|
||||||
|
|
||||||
|
Con *con;
|
||||||
|
if ((con = con_by_window_id(window)) == NULL || con->window == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
window_update_leader(con->window, prop);
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
|
@ -267,6 +267,9 @@ int main(int argc, char *argv[]) {
|
||||||
/* Watch WM_NORMAL_HINTS (aspect ratio, size increments, …) */
|
/* Watch WM_NORMAL_HINTS (aspect ratio, size increments, …) */
|
||||||
xcb_property_set_handler(&prophs, WM_NORMAL_HINTS, UINT_MAX, handle_normal_hints, NULL);
|
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 */
|
/* Set up the atoms we support */
|
||||||
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, atoms[_NET_SUPPORTED], ATOM, 32, 7, atoms);
|
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, atoms[_NET_SUPPORTED], ATOM, 32, 7, atoms);
|
||||||
/* Set up the window manager’s name */
|
/* Set up the window manager’s name */
|
||||||
|
|
|
@ -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_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_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_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);
|
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])) {
|
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);
|
preply = xcb_get_property_reply(conn, class_cookie, NULL);
|
||||||
handle_windowclass_change(NULL, conn, 0, new->child, WM_CLASS, preply);
|
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
|
/* if WM_CLIENT_LEADER is set, we put the new window on the
|
||||||
* same window as its leader. This might be overwritten by
|
* same window as its leader. This might be overwritten by
|
||||||
* assignments afterwards. */
|
* assignments afterwards. */
|
||||||
|
|
19
src/window.c
19
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_json = strdup(new_name);
|
||||||
win->name_len = strlen(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;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue