Add support for WM_CLIENT_LEADER, put floating windows mapping to (0x0) to center of leader/workspace
This commit is contained in:
parent
af3972aa9f
commit
3114d6821d
|
@ -341,6 +341,10 @@ struct Client {
|
||||||
/** Holds the WM_CLASS, useful for matching the client in commands */
|
/** Holds the WM_CLASS, useful for matching the client in commands */
|
||||||
char *window_class;
|
char *window_class;
|
||||||
|
|
||||||
|
/** Holds the xcb_window_t (just an ID) for the leader window (logical
|
||||||
|
* parent for toolwindows and similar floating windows) */
|
||||||
|
xcb_window_t leader;
|
||||||
|
|
||||||
/** fullscreen is pretty obvious */
|
/** fullscreen is pretty obvious */
|
||||||
bool fullscreen;
|
bool fullscreen;
|
||||||
|
|
||||||
|
|
|
@ -154,4 +154,13 @@ 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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles changes of the WM_CLIENT_LEADER atom which specifies if this is a
|
||||||
|
* toolwindow (or similar) and to which window it belongs (logical parent).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#ifndef _I3_H
|
#ifndef _I3_H
|
||||||
#define _I3_H
|
#define _I3_H
|
||||||
|
|
||||||
#define NUM_ATOMS 17
|
#define NUM_ATOMS 18
|
||||||
|
|
||||||
extern xcb_connection_t *global_conn;
|
extern xcb_connection_t *global_conn;
|
||||||
extern char **start_argv;
|
extern char **start_argv;
|
||||||
|
|
|
@ -60,7 +60,8 @@ enum { _NET_SUPPORTED = 0,
|
||||||
WM_PROTOCOLS,
|
WM_PROTOCOLS,
|
||||||
WM_DELETE_WINDOW,
|
WM_DELETE_WINDOW,
|
||||||
UTF8_STRING,
|
UTF8_STRING,
|
||||||
WM_STATE
|
WM_STATE,
|
||||||
|
WM_CLIENT_LEADER
|
||||||
};
|
};
|
||||||
|
|
||||||
extern unsigned int xcb_numlock_mask;
|
extern unsigned int xcb_numlock_mask;
|
||||||
|
|
|
@ -1064,3 +1064,31 @@ int handle_transient_for(void *data, xcb_connection_t *conn, uint8_t state, xcb_
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handles changes of the WM_CLIENT_LEADER atom which specifies if this is a
|
||||||
|
* toolwindow (or similar) and to which window it belongs (logical parent).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
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) {
|
||||||
|
LOG("client leader changed\n");
|
||||||
|
if (prop == NULL) {
|
||||||
|
prop = xcb_get_property_reply(conn, xcb_get_property_unchecked(conn,
|
||||||
|
false, window, WM_CLIENT_LEADER, WINDOW, 0, 32), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
LOG("changed to %08x\n", *leader);
|
||||||
|
|
||||||
|
client->leader = *leader;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
|
@ -178,6 +178,7 @@ int main(int argc, char *argv[], char *env[]) {
|
||||||
REQUEST_ATOM(WM_DELETE_WINDOW);
|
REQUEST_ATOM(WM_DELETE_WINDOW);
|
||||||
REQUEST_ATOM(UTF8_STRING);
|
REQUEST_ATOM(UTF8_STRING);
|
||||||
REQUEST_ATOM(WM_STATE);
|
REQUEST_ATOM(WM_STATE);
|
||||||
|
REQUEST_ATOM(WM_CLIENT_LEADER);
|
||||||
|
|
||||||
/* TODO: this has to be more beautiful somewhen */
|
/* TODO: this has to be more beautiful somewhen */
|
||||||
int major, minor, error;
|
int major, minor, error;
|
||||||
|
@ -308,6 +309,7 @@ int main(int argc, char *argv[], char *env[]) {
|
||||||
GET_ATOM(WM_DELETE_WINDOW);
|
GET_ATOM(WM_DELETE_WINDOW);
|
||||||
GET_ATOM(UTF8_STRING);
|
GET_ATOM(UTF8_STRING);
|
||||||
GET_ATOM(WM_STATE);
|
GET_ATOM(WM_STATE);
|
||||||
|
GET_ATOM(WM_CLIENT_LEADER);
|
||||||
|
|
||||||
xcb_property_set_handler(&prophs, atoms[_NET_WM_WINDOW_TYPE], UINT_MAX, handle_window_type, NULL);
|
xcb_property_set_handler(&prophs, atoms[_NET_WM_WINDOW_TYPE], UINT_MAX, handle_window_type, NULL);
|
||||||
/* TODO: In order to comply with EWMH, we have to watch _NET_WM_STRUT_PARTIAL */
|
/* TODO: In order to comply with EWMH, we have to watch _NET_WM_STRUT_PARTIAL */
|
||||||
|
@ -324,6 +326,9 @@ int main(int argc, char *argv[], char *env[]) {
|
||||||
/* Watch WM_CLASS (= class of the window) */
|
/* Watch WM_CLASS (= class of the window) */
|
||||||
xcb_property_set_handler(&prophs, WM_CLASS, 128, handle_windowclass_change, NULL);
|
xcb_property_set_handler(&prophs, WM_CLASS, 128, handle_windowclass_change, 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 */
|
||||||
check_error(conn, xcb_change_property_checked(conn, XCB_PROP_MODE_REPLACE, root, atoms[_NET_SUPPORTED],
|
check_error(conn, xcb_change_property_checked(conn, XCB_PROP_MODE_REPLACE, root, atoms[_NET_SUPPORTED],
|
||||||
ATOM, 32, 7, atoms), "Could not set _NET_SUPPORTED");
|
ATOM, 32, 7, atoms), "Could not set _NET_SUPPORTED");
|
||||||
|
|
38
src/manage.c
38
src/manage.c
|
@ -111,6 +111,7 @@ void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *conn,
|
||||||
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NAME);
|
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NAME);
|
||||||
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NORMAL_HINTS);
|
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NORMAL_HINTS);
|
||||||
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_TRANSIENT_FOR);
|
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_TRANSIENT_FOR);
|
||||||
|
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, atoms[WM_CLIENT_LEADER]);
|
||||||
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, atoms[_NET_WM_NAME]);
|
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, atoms[_NET_WM_NAME]);
|
||||||
|
|
||||||
free(geom);
|
free(geom);
|
||||||
|
@ -131,7 +132,8 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
|
||||||
int16_t x, int16_t y, uint16_t width, uint16_t height) {
|
int16_t x, int16_t y, uint16_t width, uint16_t height) {
|
||||||
|
|
||||||
xcb_get_property_cookie_t wm_type_cookie, strut_cookie, state_cookie,
|
xcb_get_property_cookie_t wm_type_cookie, strut_cookie, state_cookie,
|
||||||
utf8_title_cookie, title_cookie, class_cookie;
|
utf8_title_cookie, title_cookie,
|
||||||
|
class_cookie, leader_cookie;
|
||||||
uint32_t mask = 0;
|
uint32_t mask = 0;
|
||||||
uint32_t values[3];
|
uint32_t values[3];
|
||||||
uint16_t original_height = height;
|
uint16_t original_height = height;
|
||||||
|
@ -147,8 +149,9 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
|
||||||
strut_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STRUT_PARTIAL], UINT32_MAX);
|
strut_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STRUT_PARTIAL], UINT32_MAX);
|
||||||
state_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STATE], UINT32_MAX);
|
state_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STATE], UINT32_MAX);
|
||||||
utf8_title_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_NAME], 128);
|
utf8_title_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_NAME], 128);
|
||||||
|
leader_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[WM_CLIENT_LEADER], UINT32_MAX);
|
||||||
title_cookie = xcb_get_any_property_unchecked(conn, false, child, WM_NAME, 128);
|
title_cookie = xcb_get_any_property_unchecked(conn, false, child, WM_NAME, 128);
|
||||||
class_cookie = xcb_get_any_property_unchecked(conn, false, child, WM_CLASS, 128);
|
class_cookie = xcb_get_any_property_unchecked(conn, false, child, WM_CLASS, 128);
|
||||||
|
|
||||||
Client *new = table_get(&by_child, child);
|
Client *new = table_get(&by_child, child);
|
||||||
|
|
||||||
|
@ -253,6 +256,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
|
||||||
new->container = NULL;
|
new->container = NULL;
|
||||||
SLIST_INSERT_HEAD(&(c_ws->screen->dock_clients), new, dock_clients);
|
SLIST_INSERT_HEAD(&(c_ws->screen->dock_clients), new, dock_clients);
|
||||||
/* If it’s a dock we can’t make it float, so we break */
|
/* If it’s a dock we can’t make it float, so we break */
|
||||||
|
new->floating = FLOATING_AUTO_OFF;
|
||||||
break;
|
break;
|
||||||
} else if (atom[i] == atoms[_NET_WM_WINDOW_TYPE_DIALOG] ||
|
} else if (atom[i] == atoms[_NET_WM_WINDOW_TYPE_DIALOG] ||
|
||||||
atom[i] == atoms[_NET_WM_WINDOW_TYPE_UTILITY] ||
|
atom[i] == atoms[_NET_WM_WINDOW_TYPE_UTILITY] ||
|
||||||
|
@ -264,6 +268,12 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* All clients which have a leader should be floating */
|
||||||
|
if (!new->dock && !client_is_floating(new) && new->leader != 0) {
|
||||||
|
LOG("Client has WM_CLIENT_LEADER hint set, setting floating\n");
|
||||||
|
new->floating = FLOATING_AUTO_ON;
|
||||||
|
}
|
||||||
|
|
||||||
if (new->workspace->auto_float) {
|
if (new->workspace->auto_float) {
|
||||||
new->floating = FLOATING_AUTO_ON;
|
new->floating = FLOATING_AUTO_ON;
|
||||||
LOG("workspace is in autofloat mode, setting floating\n");
|
LOG("workspace is in autofloat mode, setting floating\n");
|
||||||
|
@ -304,6 +314,9 @@ 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);
|
||||||
|
|
||||||
LOG("DEBUG: should have all infos now\n");
|
LOG("DEBUG: should have all infos now\n");
|
||||||
struct Assignment *assign;
|
struct Assignment *assign;
|
||||||
TAILQ_FOREACH(assign, &assignments, assignments) {
|
TAILQ_FOREACH(assign, &assignments, assignments) {
|
||||||
|
@ -375,10 +388,27 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
|
||||||
|
|
||||||
new->container = NULL;
|
new->container = NULL;
|
||||||
|
|
||||||
new->floating_rect.x = new->rect.x = x;
|
|
||||||
new->floating_rect.y = new->rect.y = y;
|
|
||||||
new->rect.width = new->floating_rect.width + 2 + 2;
|
new->rect.width = new->floating_rect.width + 2 + 2;
|
||||||
new->rect.height = new->floating_rect.height + (font->height + 2 + 2) + 2;
|
new->rect.height = new->floating_rect.height + (font->height + 2 + 2) + 2;
|
||||||
|
|
||||||
|
/* Some clients (like GIMP’s color picker window) get mapped
|
||||||
|
* to (0, 0), so we push them to a reasonable position
|
||||||
|
* (centered over their leader) */
|
||||||
|
if (new->leader != 0 && x == 0 && y == 0) {
|
||||||
|
LOG("Floating client wants to (0x0), moving it over its leader instead\n");
|
||||||
|
Client *leader = table_get(&by_child, new->leader);
|
||||||
|
if (leader == NULL) {
|
||||||
|
LOG("leader is NULL, centering it over current workspace\n");
|
||||||
|
|
||||||
|
x = c_ws->rect.x + (c_ws->rect.width / 2) - (new->rect.width / 2);
|
||||||
|
y = c_ws->rect.y + (c_ws->rect.height / 2) - (new->rect.height / 2);
|
||||||
|
} else {
|
||||||
|
x = leader->rect.x + (leader->rect.width / 2) - (new->rect.width / 2);
|
||||||
|
y = leader->rect.y + (leader->rect.height / 2) - (new->rect.height / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new->floating_rect.x = new->rect.x = x;
|
||||||
|
new->floating_rect.y = new->rect.y = y;
|
||||||
LOG("copying floating_rect from tiling (%d, %d) size (%d, %d)\n",
|
LOG("copying floating_rect from tiling (%d, %d) size (%d, %d)\n",
|
||||||
new->floating_rect.x, new->floating_rect.y,
|
new->floating_rect.x, new->floating_rect.y,
|
||||||
new->floating_rect.width, new->floating_rect.height);
|
new->floating_rect.width, new->floating_rect.height);
|
||||||
|
|
Loading…
Reference in New Issue