Bugfix: Respect WM_HINTS.input for WM_TAKE_FOCUS clients

This fixes problems with Qt apps (like Quassel) and apparently Eclipse since
the last commit.
This commit is contained in:
Michael Stapelberg 2012-01-18 19:16:57 +00:00
parent e2b97a6fda
commit 2d14ced024
6 changed files with 58 additions and 25 deletions

View File

@ -2,7 +2,7 @@
* vim:ts=4:sw=4:expandtab * vim:ts=4:sw=4:expandtab
* *
* i3 - an improved dynamic tiling window manager * i3 - an improved dynamic tiling window manager
* © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
* *
* include/data.h: This file defines all data structures used by i3 * include/data.h: This file defines all data structures used by i3
* *
@ -293,6 +293,10 @@ struct Window {
/** Whether the application needs to receive WM_TAKE_FOCUS */ /** Whether the application needs to receive WM_TAKE_FOCUS */
bool needs_take_focus; bool needs_take_focus;
/** Whether this window accepts focus. We store this inverted so that the
* default will be 'accepts focus'. */
bool doesnt_accept_focus;
/** Whether the window says it is a dock window */ /** Whether the window says it is a dock window */
enum { W_NODOCK = 0, W_DOCK_TOP = 1, W_DOCK_BOTTOM = 2 } dock; enum { W_NODOCK = 0, W_DOCK_TOP = 1, W_DOCK_BOTTOM = 2 } dock;

View File

@ -57,4 +57,10 @@ void window_update_strut_partial(i3Window *win, xcb_get_property_reply_t *prop);
*/ */
void window_update_role(i3Window *win, xcb_get_property_reply_t *prop, bool before_mgmt); void window_update_role(i3Window *win, xcb_get_property_reply_t *prop, bool before_mgmt);
/**
* Updates the WM_HINTS (we only care about the input focus handling part).
*
*/
void window_update_hints(i3Window *win, xcb_get_property_reply_t *prop);
#endif #endif

View File

@ -855,18 +855,16 @@ static bool handle_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_
xcb_icccm_wm_hints_t hints; xcb_icccm_wm_hints_t hints;
if (reply != NULL) { if (reply == NULL)
if (!xcb_icccm_get_wm_hints_from_reply(&hints, reply)) if (!(reply = xcb_get_property_reply(conn, xcb_icccm_get_wm_hints(conn, window), NULL)))
return false; return false;
} else {
if (!xcb_icccm_get_wm_hints_reply(conn, xcb_icccm_get_wm_hints_unchecked(conn, con->window->id), &hints, NULL)) if (!xcb_icccm_get_wm_hints_from_reply(&hints, reply))
return false; return false;
}
if (!con->urgent && focused == con) { if (!con->urgent && focused == con) {
DLOG("Ignoring urgency flag for current client\n"); DLOG("Ignoring urgency flag for current client\n");
FREE(reply); goto end;
return true;
} }
/* Update the flag on the client directly */ /* Update the flag on the client directly */
@ -882,17 +880,10 @@ static bool handle_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_
tree_render(); tree_render();
#if 0 end:
/* If the workspace this client is on is not visible, we need to redraw if (con->window)
* the workspace bar */ window_update_hints(con->window, reply);
if (!workspace_is_visible(client->workspace)) { else free(reply);
Output *output = client->workspace->output;
render_workspace(conn, output, output->current_workspace);
xcb_flush(conn);
}
#endif
FREE(reply);
return true; return true;
} }

View File

@ -80,7 +80,7 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
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, utf8_title_cookie, title_cookie,
class_cookie, leader_cookie, transient_cookie, class_cookie, leader_cookie, transient_cookie,
role_cookie, startup_id_cookie; role_cookie, startup_id_cookie, wm_hints_cookie;
geomc = xcb_get_geometry(conn, d); geomc = xcb_get_geometry(conn, d);
@ -142,6 +142,7 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
class_cookie = GET_PROPERTY(XCB_ATOM_WM_CLASS, 128); class_cookie = GET_PROPERTY(XCB_ATOM_WM_CLASS, 128);
role_cookie = GET_PROPERTY(A_WM_WINDOW_ROLE, 128); role_cookie = GET_PROPERTY(A_WM_WINDOW_ROLE, 128);
startup_id_cookie = GET_PROPERTY(A__NET_STARTUP_ID, 512); startup_id_cookie = GET_PROPERTY(A__NET_STARTUP_ID, 512);
wm_hints_cookie = xcb_icccm_get_wm_hints(conn, window);
/* TODO: also get wm_normal_hints here. implement after we got rid of xcb-event */ /* TODO: also get wm_normal_hints here. implement after we got rid of xcb-event */
DLOG("Managing window 0x%08x\n", window); DLOG("Managing window 0x%08x\n", window);
@ -169,6 +170,7 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
window_update_transient_for(cwindow, xcb_get_property_reply(conn, transient_cookie, NULL)); window_update_transient_for(cwindow, xcb_get_property_reply(conn, transient_cookie, NULL));
window_update_strut_partial(cwindow, xcb_get_property_reply(conn, strut_cookie, NULL)); window_update_strut_partial(cwindow, xcb_get_property_reply(conn, strut_cookie, NULL));
window_update_role(cwindow, xcb_get_property_reply(conn, role_cookie, NULL), true); window_update_role(cwindow, xcb_get_property_reply(conn, role_cookie, NULL), true);
window_update_hints(cwindow, xcb_get_property_reply(conn, wm_hints_cookie, NULL));
xcb_get_property_reply_t *startup_id_reply; xcb_get_property_reply_t *startup_id_reply;
startup_id_reply = xcb_get_property_reply(conn, startup_id_cookie, NULL); startup_id_reply = xcb_get_property_reply(conn, startup_id_cookie, NULL);

View File

@ -2,7 +2,7 @@
* vim:ts=4:sw=4:expandtab * vim:ts=4:sw=4:expandtab
* *
* i3 - an improved dynamic tiling window manager * i3 - an improved dynamic tiling window manager
* © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
* *
* window.c: Updates window attributes (X11 hints/properties). * window.c: Updates window attributes (X11 hints/properties).
* *
@ -251,3 +251,28 @@ void window_update_role(i3Window *win, xcb_get_property_reply_t *prop, bool befo
free(prop); free(prop);
} }
/*
* Updates the WM_HINTS (we only care about the input focus handling part).
*
*/
void window_update_hints(i3Window *win, xcb_get_property_reply_t *prop) {
if (prop == NULL || xcb_get_property_value_length(prop) == 0) {
DLOG("WM_HINTS not set.\n");
FREE(prop);
return;
}
xcb_icccm_wm_hints_t hints;
if (!xcb_icccm_get_wm_hints_from_reply(&hints, prop)) {
DLOG("Could not get WM_HINTS\n");
free(prop);
return;
}
win->doesnt_accept_focus = !hints.input;
LOG("WM_HINTS.input changed to \"%d\"\n", hints.input);
free(prop);
}

11
src/x.c
View File

@ -2,7 +2,7 @@
* vim:ts=4:sw=4:expandtab * vim:ts=4:sw=4:expandtab
* *
* i3 - an improved dynamic tiling window manager * i3 - an improved dynamic tiling window manager
* © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
* *
* x.c: Interface to X11, transfers our in-memory state to X11 (see also * x.c: Interface to X11, transfers our in-memory state to X11 (see also
* render.c). Basically a big state machine. * render.c). Basically a big state machine.
@ -849,12 +849,17 @@ void x_push_changes(Con *con) {
/* Invalidate focused_id to correctly focus new windows with the same ID */ /* Invalidate focused_id to correctly focus new windows with the same ID */
focused_id = XCB_NONE; focused_id = XCB_NONE;
} else { } else {
bool set_focus = true;
if (focused->window != NULL && if (focused->window != NULL &&
focused->window->needs_take_focus) { focused->window->needs_take_focus) {
DLOG("Updating focus by sending WM_TAKE_FOCUS to window 0x%08x only (focused: %p / %s)\n", DLOG("Updating focus by sending WM_TAKE_FOCUS to window 0x%08x (focused: %p / %s)\n",
to_focus, focused, focused->name); to_focus, focused, focused->name);
send_take_focus(to_focus); send_take_focus(to_focus);
} else { set_focus = !focused->window->doesnt_accept_focus;
DLOG("set_focus = %d\n", set_focus);
}
if (set_focus) {
DLOG("Updating focus (focused: %p / %s)\n", focused, focused->name); DLOG("Updating focus (focused: %p / %s)\n", focused, focused->name);
/* We remove XCB_EVENT_MASK_FOCUS_CHANGE from the event mask to get /* We remove XCB_EVENT_MASK_FOCUS_CHANGE from the event mask to get
* no focus change events for our own focus changes. We only want * no focus change events for our own focus changes. We only want