client: fix focus subsystem

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 <mceier@gmail.com>
Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Mariusz Ceier 2009-02-11 18:32:27 +01:00 committed by Julien Danjou
parent 93386ff08f
commit 01eff69bf4
2 changed files with 37 additions and 15 deletions

View File

@ -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,
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,19 @@ client_focus(client_t *c)
if(!client_maybevisible(c, c->screen))
return;
/* unfocus current selected client */
/* Input Model: No Input */
if (!window_hasproto(c->win, WM_TAKE_FOCUS) && 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,10 +276,15 @@ client_focus(client_t *c)
globalconf.screen_focus = &globalconf.screens[c->phys_screen];
globalconf.screen_focus->client_focus = c;
if (!c->nofocus)
/* 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 */
client_need_arrange(c);
@ -1349,8 +1371,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;
}

View File

@ -55,3 +55,4 @@ WM_CHANGE_STATE
WM_WINDOW_ROLE
WM_CLIENT_LEADER
XSEL_DATA
WM_TAKE_FOCUS