From aae960e99ed748a0d6451e531e2b0ec353572ae1 Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sun, 28 Feb 2016 13:29:25 +0100 Subject: [PATCH] Make client key bindings for e.g. xeyes work again Instead of focusing the root window, we now create a "focus window" inside of our frame window. This window is placed so that it is not visible, but we can grab key bindings on it to simulate the window having the input focus. Fixes: https://github.com/awesomeWM/awesome/issues/699 Signed-off-by: Uli Schlachter --- event.c | 2 +- objects/client.c | 34 +++++++++++++++++++++++++++++----- objects/client.h | 3 +++ xkb.c | 2 ++ 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/event.c b/event.c index f52723330..bfaae46c5 100644 --- a/event.c +++ b/event.c @@ -673,7 +673,7 @@ event_handle_key(xcb_key_press_event_t *ev) /* get keysym ignoring all modifiers */ xcb_keysym_t keysym = xcb_key_symbols_get_keysym(globalconf.keysyms, ev->detail, 0); client_t *c; - if((c = client_getbywin(ev->event))) + if((c = client_getbywin(ev->event)) || (c = client_getbynofocuswin(ev->event))) { luaA_object_push(L, c); event_key_callback(ev, &c->keys, L, -1, 1, &keysym); diff --git a/objects/client.c b/objects/client.c index 5a61869a3..bffc44d5f 100644 --- a/objects/client.c +++ b/objects/client.c @@ -254,6 +254,16 @@ client_getbywin(xcb_window_t w) return NULL; } +client_t * +client_getbynofocuswin(xcb_window_t w) +{ + foreach(c, globalconf.clients) + if((*c)->nofocus_window == w) + return *c; + + return NULL; +} + /** Get a client by its frame window. * \param w The client window to find. * \return A client pointer if found, NULL otherwise. @@ -416,6 +426,20 @@ client_focus(client_t *c) globalconf.focus.need_update = true; } +static xcb_window_t +client_get_nofocus_window(client_t *c) +{ + if (c->nofocus_window == XCB_NONE) { + c->nofocus_window = xcb_generate_id(globalconf.connection); + xcb_create_window(globalconf.connection, globalconf.default_depth, c->nofocus_window, c->frame_window, + -2, -2, 1, 1, 0, XCB_COPY_FROM_PARENT, globalconf.visual->visual_id, + 0, NULL); + xcb_map_window(globalconf.connection, c->nofocus_window); + xwindow_grabkeys(c->nofocus_window, &c->keys); + } + return c->nofocus_window; +} + void client_focus_refresh(void) { @@ -434,11 +458,7 @@ client_focus_refresh(void) if(!c->nofocus) win = c->window; else - /* Move the focus away from whatever has it to make sure the - * previously focused client doesn't get any input in case - * WM_TAKE_FOCUS gets ignored. - */ - win = globalconf.focus.window_no_focus; + win = client_get_nofocus_window(c); if(client_hasproto(c, WM_TAKE_FOCUS)) xwindow_takefocus(c->window); @@ -1360,6 +1380,8 @@ client_unmanage(client_t *c, bool window_valid) /* Ignore all spurious enter/leave notify events */ client_ignore_enterleave_events(); + if (c->nofocus_window != XCB_NONE) + xcb_destroy_window(globalconf.connection, c->nofocus_window); xcb_destroy_window(globalconf.connection, c->frame_window); client_restore_enterleave_events(); @@ -2499,6 +2521,8 @@ luaA_client_keys(lua_State *L) luaA_key_array_set(L, 1, 2, keys); luaA_object_emit_signal(L, 1, "property::keys", 0); xwindow_grabkeys(c->window, keys); + if (c->nofocus_window) + xwindow_grabkeys(c->nofocus_window, &c->keys); } return luaA_key_array_get(L, 1, keys); diff --git a/objects/client.h b/objects/client.h index 86a28c9c2..2468fb89e 100644 --- a/objects/client.h +++ b/objects/client.h @@ -51,6 +51,8 @@ typedef enum { struct client_t { WINDOW_OBJECT_HEADER + /** Window we use for input focus and no-input clients */ + xcb_window_t nofocus_window; /** Client logical screen */ screen_t *screen; /** Client name */ @@ -139,6 +141,7 @@ LUA_OBJECT_FUNCS(client_class, client_t, client) bool client_on_selected_tags(client_t *); client_t * client_getbywin(xcb_window_t); +client_t * client_getbynofocuswin(xcb_window_t); client_t * client_getbyframewin(xcb_window_t); void client_ban(client_t *); diff --git a/xkb.c b/xkb.c index c206e44ff..f96944457 100644 --- a/xkb.c +++ b/xkb.c @@ -199,6 +199,8 @@ xkb_reload_keymap(void) { client_t *c = *_c; xwindow_grabkeys(c->window, &c->keys); + if (c->nofocus_window) + xwindow_grabkeys(c->nofocus_window, &c->keys); } }