move grabinput focus fix timer to x11 compositor and fix it to Work Better

see inline comments about x11 focus eventing for details

fix T2547
This commit is contained in:
Mike Blumenkrantz 2015-07-06 15:46:02 -04:00
parent 2342a4d38f
commit 4f8af72fe3
2 changed files with 56 additions and 19 deletions

View File

@ -36,6 +36,8 @@ struct _E_Comp_X_Data
};
static unsigned int focus_time = 0;
static Ecore_Timer *focus_timer;
static E_Client *mouse_client;
static Eina_List *handlers = NULL;
static Eina_Hash *clients_win_hash = NULL;
static Eina_Hash *damages_hash = NULL;
@ -2032,6 +2034,7 @@ _e_comp_x_mouse_in(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_M
ec = _e_comp_x_client_find_by_window(ev->win);
if (!ec) return ECORE_CALLBACK_RENEW;
if (ec->comp_data->deleted) return ECORE_CALLBACK_RENEW;
mouse_client = ec;
if (ec->input_object) return ECORE_CALLBACK_RENEW;
e_client_mouse_in(ec, e_comp_canvas_x_root_adjust(ec->comp, ev->root.x), e_comp_canvas_x_root_adjust(ec->comp, ev->root.y));
return ECORE_CALLBACK_RENEW;
@ -2053,6 +2056,7 @@ _e_comp_x_mouse_out(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_
ec = _e_comp_x_client_find_by_window(ev->win);
if (!ec) return ECORE_CALLBACK_RENEW;
if (ec->comp_data->deleted) return ECORE_CALLBACK_RENEW;
if (mouse_client == ec) mouse_client = NULL;
if (ec->input_object) return ECORE_CALLBACK_RENEW;
e_client_mouse_out(ec, e_comp_canvas_x_root_adjust(ec->comp, ev->root.x), e_comp_canvas_x_root_adjust(ec->comp, ev->root.y));
return ECORE_CALLBACK_RENEW;
@ -2450,6 +2454,50 @@ _e_comp_x_move_resize_request(void *data EINA_UNUSED, int type EINA_UNUSED, Ecor
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_e_comp_x_focus_timer_cb(void *d EINA_UNUSED)
{
E_Client *focused;
/* if mouse-based focus policy clients exist for [focused] and [mouse_client],
* [mouse_client] should have focus here.
* race conditions in x11 focus setting can result in a scenario such that:
* -> set focus on A
* -> set focus on B
* -> receive focus event on A
* -> re-set focus on A
* -> receive focus event on B
* -> receive focus event on A
* ...
* where the end state is that the cursor is over a client which does not have focus.
* this timer is triggered only when such eventing occurs in order to adjust the focused
* client as necessary
*/
focused = e_client_focused_get();
if (mouse_client && focused && (!e_client_focus_policy_click(focused)) && (mouse_client != focused))
{
int x, y;
ecore_evas_pointer_xy_get(e_comp_get(NULL)->ee, &x, &y);
if (E_INSIDE(x, y, mouse_client->x, mouse_client->y, mouse_client->w, mouse_client->h))
{
if (!mouse_client->comp_data->deleted)
e_client_mouse_in(mouse_client, x, y);
}
}
focus_timer = NULL;
return EINA_FALSE;
}
static void
_e_comp_x_focus_timer(void)
{
if (focus_timer)
ecore_timer_reset(focus_timer);
else /* focus has changed twice in .002 seconds; .01 seconds should be more than enough delay */
focus_timer = ecore_timer_add(0.01, _e_comp_x_focus_timer_cb, NULL);
}
static Eina_Bool
_e_comp_x_focus_in(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Focus_In *ev)
{
@ -2493,6 +2541,10 @@ _e_comp_x_focus_in(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_W
/* should be equal, maybe some clients dont reply with the proper timestamp ? */
if (ev->time >= focus_time)
evas_object_focus_set(ec->frame, 1);
/* handle case of someone trying to benchmark focus handling */
if ((!e_client_focus_policy_click(ec)) && (focused && (!e_client_focus_policy_click(focused))) &&
(ev->time - focus_time <= 2))
_e_comp_x_focus_timer();
return ECORE_CALLBACK_PASS_ON;
}
@ -4211,6 +4263,7 @@ _e_comp_x_hook_client_del(void *d EINA_UNUSED, E_Client *ec)
win = e_client_util_win_get(ec);
if ((!stopping) && (!ec->comp_data->deleted))
if (mouse_client == ec) mouse_client = NULL;
ecore_x_window_prop_card32_set(win, E_ATOM_MANAGED, &visible, 1);
if ((!ec->already_unparented) && ec->comp_data->reparented)
{

View File

@ -13,7 +13,6 @@ static E_Focus_Method focus_method = E_FOCUS_METHOD_NO_INPUT;
static double last_focus_time = 0.0;
static Ecore_Window focus_fix_win = 0;
static Ecore_Timer *focus_fix_timer = NULL;
static E_Focus_Method focus_fix_method = E_FOCUS_METHOD_NO_INPUT;
/* externally accessible functions */
@ -26,11 +25,6 @@ e_grabinput_init(void)
EINTERN int
e_grabinput_shutdown(void)
{
if (focus_fix_timer)
{
ecore_timer_del(focus_fix_timer);
focus_fix_timer = NULL;
}
return 1;
}
@ -149,18 +143,10 @@ e_grabinput_key_win_get(void)
return grab_key_win;
}
static Eina_Bool
_e_grabinput_focus_check(void *data __UNUSED__)
E_API Ecore_Window
e_grabinput_mouse_win_get(void)
{
#ifndef HAVE_WAYLAND_ONLY
if (ecore_x_window_focus_get() != focus_fix_win)
{
/* fprintf(stderr, "foc do 2\n"); */
_e_grabinput_focus_do(focus_fix_win, focus_fix_method);
}
#endif
focus_fix_timer = NULL;
return EINA_FALSE;
return grab_mouse_win;
}
static void
@ -204,7 +190,5 @@ _e_grabinput_focus(Ecore_Window win, E_Focus_Method method)
/* fprintf(stderr, "foc do 1\n"); */
_e_grabinput_focus_do(win, method);
last_focus_time = ecore_loop_time_get();
if (focus_fix_timer) ecore_timer_del(focus_fix_timer);
focus_fix_timer = ecore_timer_add(0.2, _e_grabinput_focus_check, NULL);
}