From 17f0ce3713203d3f73e6b5af1b6a41c016e9b521 Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Mon, 6 Jul 2015 15:46:02 -0400 Subject: [PATCH] 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 --- src/bin/e_comp_x.c | 53 +++++++++++++++++++++++++++++++++++++++++++ src/bin/e_grabinput.c | 30 ------------------------ 2 files changed, 53 insertions(+), 30 deletions(-) diff --git a/src/bin/e_comp_x.c b/src/bin/e_comp_x.c index 7998eca24..ff329effa 100644 --- a/src/bin/e_comp_x.c +++ b/src/bin/e_comp_x.c @@ -40,6 +40,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; @@ -2154,6 +2156,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 (_e_comp_x_client_data_get(ec)->deleted) return ECORE_CALLBACK_RENEW; + mouse_client = ec; e_client_mouse_in(ec, e_comp_canvas_x_root_adjust(ev->root.x), e_comp_canvas_x_root_adjust(ev->root.y)); return ECORE_CALLBACK_RENEW; } @@ -2174,6 +2177,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 (_e_comp_x_client_data_get(ec)->deleted) return ECORE_CALLBACK_RENEW; + if (mouse_client == ec) mouse_client = NULL; e_client_mouse_out(ec, e_comp_canvas_x_root_adjust(ev->root.x), e_comp_canvas_x_root_adjust(ev->root.y)); return ECORE_CALLBACK_RENEW; } @@ -2571,6 +2575,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->ee, &x, &y); + if (E_INSIDE(x, y, mouse_client->x, mouse_client->y, mouse_client->w, mouse_client->h)) + { + if (!_e_comp_x_client_data_get(mouse_client)->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) { @@ -2614,6 +2662,10 @@ _e_comp_x_focus_in(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_W /* should be equal, maybe some clients don't 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; } @@ -4325,6 +4377,7 @@ _e_comp_x_hook_client_del(void *d EINA_UNUSED, E_Client *ec) pwin = _e_comp_x_client_util_pwin_get(ec); cd = _e_comp_x_client_data_get(ec); + if (mouse_client == ec) mouse_client = NULL; if ((!stopping) && cd && (!cd->deleted)) ecore_x_window_prop_card32_set(win, E_ATOM_MANAGED, &visible, 1); if ((!ec->already_unparented) && cd && cd->reparented) diff --git a/src/bin/e_grabinput.c b/src/bin/e_grabinput.c index d835c0104..7fc156181 100644 --- a/src/bin/e_grabinput.c +++ b/src/bin/e_grabinput.c @@ -12,9 +12,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; -#ifndef HAVE_WAYLAND_ONLY -static Ecore_Timer *focus_fix_timer = NULL; -#endif static E_Focus_Method focus_fix_method = E_FOCUS_METHOD_NO_INPUT; /* externally accessible functions */ @@ -27,9 +24,6 @@ e_grabinput_init(void) EINTERN int e_grabinput_shutdown(void) { -#ifndef HAVE_WAYLAND_ONLY - E_FREE_FUNC(focus_fix_timer, ecore_timer_del); -#endif return 1; } @@ -194,26 +188,6 @@ e_grabinput_mouse_win_get(void) return grab_mouse_win; } -#ifndef HAVE_WAYLAND_ONLY -static Eina_Bool -_e_grabinput_focus_check(void *data EINA_UNUSED) -{ - if (!e_comp->root) - { - focus_fix_timer = NULL; - return EINA_FALSE; - } - - 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); - } - focus_fix_timer = NULL; - return EINA_FALSE; -} -#endif - static void _e_grabinput_focus_do(Ecore_Window win, E_Focus_Method method) { @@ -289,8 +263,4 @@ _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(); -#ifndef HAVE_WAYLAND_ONLY - if (focus_fix_timer) ecore_timer_del(focus_fix_timer); - focus_fix_timer = ecore_timer_add(0.2, _e_grabinput_focus_check, NULL); -#endif }