Bugfix: Only set ENTER_WINDOW event mask for mapped windows (fixes focus problems)
Fixes focus problems when switching to empty workspaces or when going in/out of fullscreen.
This commit is contained in:
parent
23d4917e43
commit
71741d7620
@ -439,9 +439,10 @@ static int handle_screen_change(xcb_generic_event_t *e) {
|
||||
*
|
||||
*/
|
||||
static int handle_unmap_notify_event(xcb_unmap_notify_event_t *event) {
|
||||
// XXX: this is commented out because in src/x.c we disable EnterNotify events
|
||||
/* we need to ignore EnterNotify events which will be generated because a
|
||||
* different window is visible now */
|
||||
add_ignore_event(event->sequence, XCB_ENTER_NOTIFY);
|
||||
//add_ignore_event(event->sequence, XCB_ENTER_NOTIFY);
|
||||
|
||||
DLOG("UnmapNotify for 0x%08x (received from 0x%08x), serial %d\n", event->window, event->event, event->sequence);
|
||||
Con *con = con_by_window_id(event->window);
|
||||
|
@ -117,16 +117,14 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
|
||||
goto out;
|
||||
}
|
||||
|
||||
uint32_t mask = 0;
|
||||
uint32_t values[1];
|
||||
|
||||
/* Set a temporary event mask for the new window, consisting only of
|
||||
* PropertyChange. We need to be notified of PropertyChanges because the
|
||||
* client can change its properties *after* we requested them but *before*
|
||||
* we actually reparented it and have set our final event mask. */
|
||||
mask = XCB_CW_EVENT_MASK;
|
||||
values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE;
|
||||
xcb_change_window_attributes(conn, window, mask, values);
|
||||
xcb_change_window_attributes(conn, window, XCB_CW_EVENT_MASK, values);
|
||||
|
||||
#define GET_PROPERTY(atom, len) xcb_get_property_unchecked(conn, false, window, atom, XCB_GET_PROPERTY_TYPE_ANY, 0, len)
|
||||
|
||||
@ -326,9 +324,8 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
|
||||
goto out;
|
||||
}
|
||||
|
||||
mask = XCB_CW_EVENT_MASK;
|
||||
values[0] = CHILD_EVENT_MASK;
|
||||
xcb_change_window_attributes(conn, window, mask, values);
|
||||
values[0] = CHILD_EVENT_MASK & ~XCB_EVENT_MASK_ENTER_WINDOW;
|
||||
xcb_change_window_attributes(conn, window, XCB_CW_EVENT_MASK, values);
|
||||
xcb_flush(conn);
|
||||
|
||||
reply = xcb_get_property_reply(conn, state_cookie, NULL);
|
||||
|
47
src/x.c
47
src/x.c
@ -18,6 +18,7 @@ xcb_window_t focused_id = XCB_NONE;
|
||||
typedef struct con_state {
|
||||
xcb_window_t id;
|
||||
bool mapped;
|
||||
bool unmap_now;
|
||||
bool child_mapped;
|
||||
|
||||
/* For reparenting, we have a flag (need_reparent) and the X ID of the old
|
||||
@ -78,9 +79,9 @@ void x_con_init(Con *con) {
|
||||
mask |= XCB_CW_OVERRIDE_REDIRECT;
|
||||
values[0] = 1;
|
||||
|
||||
/* We want to know when… */
|
||||
/* see include/xcb.h for the FRAME_EVENT_MASK */
|
||||
mask |= XCB_CW_EVENT_MASK;
|
||||
values[1] = FRAME_EVENT_MASK;
|
||||
values[1] = FRAME_EVENT_MASK & ~XCB_EVENT_MASK_ENTER_WINDOW;
|
||||
|
||||
Rect dims = { -15, -15, 10, 10 };
|
||||
con->frame = create_window(conn, dims, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCURSOR_CURSOR_POINTER, false, mask, values);
|
||||
@ -612,21 +613,29 @@ void x_push_node(Con *con) {
|
||||
A_WM_STATE, A_WM_STATE, 32, 2, data);
|
||||
}
|
||||
|
||||
uint32_t values[1];
|
||||
if (!state->child_mapped && con->window != NULL) {
|
||||
cookie = xcb_map_window(conn, con->window->id);
|
||||
|
||||
/* We are interested in EnterNotifys as soon as the window is
|
||||
* mapped */
|
||||
values[0] = CHILD_EVENT_MASK;
|
||||
xcb_change_window_attributes(conn, con->window->id, XCB_CW_EVENT_MASK, values);
|
||||
DLOG("mapping child window (serial %d)\n", cookie.sequence);
|
||||
/* Ignore enter_notifies which are generated when mapping */
|
||||
add_ignore_event(cookie.sequence, 0);
|
||||
state->child_mapped = true;
|
||||
}
|
||||
|
||||
cookie = xcb_map_window(conn, con->frame);
|
||||
DLOG("mapping container (serial %d)\n", cookie.sequence);
|
||||
/* Ignore enter_notifies which are generated when mapping */
|
||||
add_ignore_event(cookie.sequence, 0);
|
||||
|
||||
values[0] = FRAME_EVENT_MASK;
|
||||
xcb_change_window_attributes(conn, con->frame, XCB_CW_EVENT_MASK, values);
|
||||
|
||||
DLOG("mapping container %08x (serial %d)\n", con->frame, cookie.sequence);
|
||||
state->mapped = con->mapped;
|
||||
}
|
||||
|
||||
state->unmap_now = (state->mapped != con->mapped) && !con->mapped;
|
||||
|
||||
if (fake_notify) {
|
||||
DLOG("Sending fake configure notify\n");
|
||||
fake_absolute_configure_notify(con);
|
||||
@ -658,8 +667,7 @@ static void x_push_node_unmaps(Con *con) {
|
||||
/* map/unmap if map state changed, also ensure that the child window
|
||||
* is changed if we are mapped *and* in initial state (meaning the
|
||||
* container was empty before, but now got a child) */
|
||||
if ((state->mapped != con->mapped || (con->mapped && state->initial)) &&
|
||||
!con->mapped) {
|
||||
if (state->unmap_now) {
|
||||
xcb_void_cookie_t cookie;
|
||||
if (con->window != NULL) {
|
||||
/* Set WM_STATE_WITHDRAWN, it seems like Java apps need it */
|
||||
@ -677,8 +685,6 @@ static void x_push_node_unmaps(Con *con) {
|
||||
con->ignore_unmap++;
|
||||
DLOG("ignore_unmap for con %p (frame 0x%08x) now %d\n", con, con->frame, con->ignore_unmap);
|
||||
}
|
||||
/* Ignore enter_notifies which are generated when unmapping */
|
||||
add_ignore_event(cookie.sequence, 0);
|
||||
state->mapped = con->mapped;
|
||||
}
|
||||
|
||||
@ -731,8 +737,10 @@ void x_push_changes(Con *con) {
|
||||
state->initial = false;
|
||||
}
|
||||
//DLOG("Re-enabling EnterNotify\n");
|
||||
values[0] = FRAME_EVENT_MASK;
|
||||
CIRCLEQ_FOREACH_REVERSE(state, &state_head, state) {
|
||||
values[0] = FRAME_EVENT_MASK;
|
||||
if (!state->mapped)
|
||||
values[0] &= ~XCB_EVENT_MASK_ENTER_WINDOW;
|
||||
xcb_change_window_attributes(conn, state->id, XCB_CW_EVENT_MASK, values);
|
||||
}
|
||||
//DLOG("Done, EnterNotify re-enabled\n");
|
||||
@ -785,6 +793,21 @@ void x_push_changes(Con *con) {
|
||||
xcb_flush(conn);
|
||||
DLOG("\n\n ENDING CHANGES\n\n");
|
||||
|
||||
/* Disable EnterWindow events for windows which will be unmapped in
|
||||
* x_push_node_unmaps() now. Unmapping windows happens when switching
|
||||
* workspaces. We want to avoid getting EnterNotifies during that phase
|
||||
* because they would screw up our focus. One of these cases is having a
|
||||
* stack with two windows. If the first window is focused and gets
|
||||
* unmapped, the second one appears under the cursor and therefore gets an
|
||||
* EnterNotify event. */
|
||||
values[0] = FRAME_EVENT_MASK & ~XCB_EVENT_MASK_ENTER_WINDOW;
|
||||
CIRCLEQ_FOREACH_REVERSE(state, &state_head, state) {
|
||||
if (!state->unmap_now)
|
||||
continue;
|
||||
xcb_change_window_attributes(conn, state->id, XCB_CW_EVENT_MASK, values);
|
||||
}
|
||||
|
||||
/* Push all pending unmaps */
|
||||
x_push_node_unmaps(con);
|
||||
|
||||
/* save the current stack as old stack */
|
||||
|
Loading…
Reference in New Issue
Block a user