We don't need to unfocus currently selected client. Added WM_TAKE_FOCUS atom, so we can implement correct ICCCM, focus behavior, in relation to Input Models ( sections 4.1.7 [1], 4.2.7 [2] ). Currently correctly implemented are, "No Input", and "Passive" models, and additionally works "Locally Active". To test focus-in and focus-out events I used program from [3].
[1] http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.7 [2] http://tronche.com/gui/x/icccm/sec-4.html#s-4.2.7 [3] http://mail.gnome.org/archives/gtk-devel-list/2001-November/msg00334.html Signed-off-by: Mariusz Ceier <[email protected]> --- client.c | 53 ++++++++++++++++++++++++++++++++++++++--------------- common/atoms.list | 1 + 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/client.c b/client.c index ea107f6..0b1d688 100644 --- a/client.c +++ b/client.c @@ -179,6 +179,20 @@ client_getbywin(xcb_window_t w) return c; } +/** Call unfocus hook. + * \param c Client being unfocused + */ +static void +client_unfocus_hook(client_t *c) +{ + /* Call hook */ + if(globalconf.hooks.unfocus != LUA_REFNIL) + { + luaA_client_userdata_new(globalconf.L, c); + luaA_dofunction(globalconf.L, globalconf.hooks.unfocus, 1, 0); + } +} + /** Unfocus a client. * \param c The client. */ @@ -189,16 +203,10 @@ client_unfocus(client_t *c) globalconf.screens[c->phys_screen].client_focus = NULL; /* Set focus on root window, so no events leak to the current window. */ - if (!c->nofocus) - xcb_set_input_focus(globalconf.connection, XCB_INPUT_FOCUS_POINTER_ROOT, + xcb_set_input_focus(globalconf.connection, XCB_INPUT_FOCUS_POINTER_ROOT, root_win, XCB_CURRENT_TIME); - /* Call hook */ - if(globalconf.hooks.unfocus != LUA_REFNIL) - { - luaA_client_userdata_new(globalconf.L, c); - luaA_dofunction(globalconf.L, globalconf.hooks.unfocus, 1, 0); - } + client_unfocus_hook(c); ewmh_update_net_active_window(c->phys_screen); } @@ -244,10 +252,21 @@ client_focus(client_t *c) if(!client_maybevisible(c, c->screen)) return; - /* unfocus current selected client */ + bool takefocus = window_hasproto(c->win, WM_TAKE_FOCUS); + + /* Input Model: No Input */ + if ((!takefocus)&&(c->nofocus)) + return; + + /* unfocus current selected client + * We don't really need to unfocus here, + * because client already received FocusOut event. + * What we need to do is call unfocus hook, to + * inform lua script, about this event. + */ if(globalconf.screen_focus->client_focus && c != globalconf.screen_focus->client_focus) - client_unfocus(globalconf.screen_focus->client_focus); + client_unfocus_hook(globalconf.screen_focus->client_focus); /* stop hiding c */ c->ishidden = false; @@ -259,9 +278,14 @@ client_focus(client_t *c) globalconf.screen_focus = &globalconf.screens[c->phys_screen]; globalconf.screen_focus->client_focus = c; - if (!c->nofocus) - xcb_set_input_focus(globalconf.connection, XCB_INPUT_FOCUS_POINTER_ROOT, - c->win, XCB_CURRENT_TIME); + /* Input Models: Passive, Locally Active */ + xcb_set_input_focus(globalconf.connection, XCB_INPUT_FOCUS_POINTER_ROOT, + c->win, XCB_CURRENT_TIME); + + /* TODO: Currently we don't handle correctly globally active input model + * One fix I know of, is we should handle FocusIn and FocusOut events for windows, + * and use WM_TAKE_FOCUS client message. + */ /* Some layouts use focused client differently, so call them back. * And anyway, we have maybe unhidden */ @@ -1349,8 +1373,7 @@ luaA_client_redraw(lua_State *L) performed on the window where the pointer is currently on because after the unmapping/mapping, the focus is lost */ if(globalconf.screen_focus->client_focus == *c) - xcb_set_input_focus(globalconf.connection, XCB_INPUT_FOCUS_POINTER_ROOT, - (*c)->win, XCB_CURRENT_TIME); + client_focus(*c); return 0; } diff --git a/common/atoms.list b/common/atoms.list index f426fad..dd4c7c9 100644 --- a/common/atoms.list +++ b/common/atoms.list @@ -55,3 +55,4 @@ WM_CHANGE_STATE WM_WINDOW_ROLE WM_CLIENT_LEADER XSEL_DATA +WM_TAKE_FOCUS -- 1.6.1.1 -- To unsubscribe, send mail to [email protected].
