Handle the EWMH atom _NET_WM_DESKTOP.
We already claim _NET_WM_DESKTOP support in _NET_SUPPORTED since around 2009, but haven't actually done anything with it. However, especially pagers like gnome-panel rely on this property to be updated and many tools, like GTK, want to use the corresponding client messages to make a window sticky, move it around etc. This patch implements full support according to the EWMH spec. This means: * We set the property on all windows when managing it. * We keep the property updated on all windows at all times. * We read and respect the property upon managing a window if it was set before mapping the window. * We react to client messages for it. * We remove the property on withdrawn windows. Note that the special value 0xFFFFFFFF, according to the spec, means that the window shall be shown on all workspaces. We do this by making it sticky and float it. This shows it on all workspaces at least on the output it is on. Furthermore, the spec gives us the freedom to ignore _NET_WM_DESKTOP when managing a window if we have good reason to. In our case, we give window swallowing a higher priority since the user would likely expect that and we want to keep placeholder windows only around for as long as we have to. However, we do prioritize this property over, for example, startup notifications. fixes #2153 fixes #1507 fixes #938
This commit is contained in:
46
src/manage.c
46
src/manage.c
@ -90,7 +90,7 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
|
||||
utf8_title_cookie, title_cookie,
|
||||
class_cookie, leader_cookie, transient_cookie,
|
||||
role_cookie, startup_id_cookie, wm_hints_cookie,
|
||||
wm_normal_hints_cookie, motif_wm_hints_cookie, wm_user_time_cookie;
|
||||
wm_normal_hints_cookie, motif_wm_hints_cookie, wm_user_time_cookie, wm_desktop_cookie;
|
||||
|
||||
geomc = xcb_get_geometry(conn, d);
|
||||
|
||||
@ -162,6 +162,7 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
|
||||
wm_normal_hints_cookie = xcb_icccm_get_wm_normal_hints(conn, window);
|
||||
motif_wm_hints_cookie = GET_PROPERTY(A__MOTIF_WM_HINTS, 5 * sizeof(uint64_t));
|
||||
wm_user_time_cookie = GET_PROPERTY(A__NET_WM_USER_TIME, UINT32_MAX);
|
||||
wm_desktop_cookie = GET_PROPERTY(A__NET_WM_DESKTOP, UINT32_MAX);
|
||||
|
||||
DLOG("Managing window 0x%08x\n", window);
|
||||
|
||||
@ -194,6 +195,16 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
|
||||
char *startup_ws = startup_workspace_for_window(cwindow, startup_id_reply);
|
||||
DLOG("startup workspace = %s\n", startup_ws);
|
||||
|
||||
/* Get _NET_WM_DESKTOP if it was set. */
|
||||
xcb_get_property_reply_t *wm_desktop_reply;
|
||||
wm_desktop_reply = xcb_get_property_reply(conn, wm_desktop_cookie, NULL);
|
||||
cwindow->wm_desktop = NET_WM_DESKTOP_NONE;
|
||||
if (wm_desktop_reply != NULL && xcb_get_property_value_length(wm_desktop_reply) != 0) {
|
||||
uint32_t *wm_desktops = xcb_get_property_value(wm_desktop_reply);
|
||||
cwindow->wm_desktop = (int32_t)wm_desktops[0];
|
||||
}
|
||||
FREE(wm_desktop_reply);
|
||||
|
||||
/* check if the window needs WM_TAKE_FOCUS */
|
||||
cwindow->needs_take_focus = window_supports_protocol(cwindow->id, A_WM_TAKE_FOCUS);
|
||||
|
||||
@ -244,6 +255,8 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
|
||||
nc = con_for_window(search_at, cwindow, &match);
|
||||
const bool match_from_restart_mode = (match && match->restart_mode);
|
||||
if (nc == NULL) {
|
||||
Con *wm_desktop_ws = NULL;
|
||||
|
||||
/* If not, check if it is assigned to a specific workspace */
|
||||
if ((assignment = assignment_for(cwindow, A_TO_WORKSPACE))) {
|
||||
DLOG("Assignment matches (%p)\n", match);
|
||||
@ -258,9 +271,23 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
|
||||
/* set the urgency hint on the window if the workspace is not visible */
|
||||
if (!workspace_is_visible(assigned_ws))
|
||||
urgency_hint = true;
|
||||
} else if (cwindow->wm_desktop != NET_WM_DESKTOP_NONE &&
|
||||
cwindow->wm_desktop != NET_WM_DESKTOP_ALL &&
|
||||
(wm_desktop_ws = ewmh_get_workspace_by_index(cwindow->wm_desktop)) != NULL) {
|
||||
/* If _NET_WM_DESKTOP is set to a specific desktop, we open it
|
||||
* there. Note that we ignore the special value 0xFFFFFFFF here
|
||||
* since such a window will be made sticky anyway. */
|
||||
|
||||
DLOG("Using workspace %p / %s because _NET_WM_DESKTOP = %d.\n",
|
||||
wm_desktop_ws, wm_desktop_ws->name, cwindow->wm_desktop);
|
||||
|
||||
nc = con_descend_tiling_focused(wm_desktop_ws);
|
||||
if (nc->type == CT_WORKSPACE)
|
||||
nc = tree_open_con(nc, cwindow);
|
||||
else
|
||||
nc = tree_open_con(nc->parent, cwindow);
|
||||
} else if (startup_ws) {
|
||||
/* If it’s not assigned, but was started on a specific workspace,
|
||||
* we want to open it there */
|
||||
/* If it was started on a specific workspace, we want to open it there. */
|
||||
DLOG("Using workspace on which this application was started (%s)\n", startup_ws);
|
||||
nc = con_descend_tiling_focused(workspace_get(startup_ws, NULL));
|
||||
DLOG("focused on ws %s: %p / %s\n", startup_ws, nc, nc->name);
|
||||
@ -393,6 +420,12 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
|
||||
if (xcb_reply_contains_atom(state_reply, A__NET_WM_STATE_STICKY))
|
||||
nc->sticky = true;
|
||||
|
||||
if (cwindow->wm_desktop == NET_WM_DESKTOP_ALL) {
|
||||
DLOG("This window has _NET_WM_DESKTOP = 0xFFFFFFFF. Will float it and make it sticky.\n");
|
||||
nc->sticky = true;
|
||||
want_floating = true;
|
||||
}
|
||||
|
||||
FREE(state_reply);
|
||||
FREE(type_reply);
|
||||
|
||||
@ -574,6 +607,13 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
|
||||
* needs to be on the final workspace first. */
|
||||
con_set_urgency(nc, urgency_hint);
|
||||
|
||||
/* Update _NET_WM_DESKTOP. We invalidate the cached value first to force an update. */
|
||||
cwindow->wm_desktop = NET_WM_DESKTOP_NONE;
|
||||
ewmh_update_wm_desktop();
|
||||
|
||||
/* If a sticky window was mapped onto another workspace, make sure to pop it to the front. */
|
||||
output_push_sticky_windows(focused);
|
||||
|
||||
geom_out:
|
||||
free(geom);
|
||||
out:
|
||||
|
Reference in New Issue
Block a user