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 <psychon@znc.in>
This commit is contained in:
Uli Schlachter 2016-02-28 13:29:25 +01:00
parent 89a29b5404
commit e54d911a94
3 changed files with 35 additions and 6 deletions

View File

@ -645,7 +645,7 @@ event_handle_key(xcb_key_press_event_t *ev)
/* get keysym ignoring all modifiers */
xcb_keysym_t keysym = keyresolv_get_keysym(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(globalconf.L, c);
event_key_callback(ev, &c->keys, -1, 1, &keysym);
@ -836,6 +836,8 @@ event_handle_mappingnotify(xcb_mapping_notify_event_t *ev)
client_t *c = *_c;
xcb_ungrab_key(globalconf.connection, XCB_GRAB_ANY, c->window, XCB_BUTTON_MASK_ANY);
xwindow_grabkeys(c->window, &c->keys);
if (c->nofocus_window)
xwindow_grabkeys(c->nofocus_window, &c->keys);
}
}
}

View File

@ -164,6 +164,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.
@ -326,6 +336,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)
{
@ -344,11 +368,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);
@ -1226,6 +1246,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();
@ -2275,6 +2297,8 @@ luaA_client_keys(lua_State *L)
luaA_object_emit_signal(L, 1, "property::keys", 0);
xcb_ungrab_key(globalconf.connection, XCB_GRAB_ANY, c->window, XCB_BUTTON_MASK_ANY);
xwindow_grabkeys(c->window, keys);
if (c->nofocus_window)
xwindow_grabkeys(c->nofocus_window, &c->keys);
}
return luaA_key_array_get(L, 1, keys);

View File

@ -56,6 +56,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 */
@ -137,6 +139,7 @@ LUA_OBJECT_FUNCS(client_class, client_t, client)
bool client_maybevisible(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 *);