From 4f8af72fe3fe71d5811c6b955dd1c3e509002cc8 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 | 22 +++--------------- 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/src/bin/e_comp_x.c b/src/bin/e_comp_x.c index 07f4ae268..cb63be9d4 100644 --- a/src/bin/e_comp_x.c +++ b/src/bin/e_comp_x.c @@ -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) { diff --git a/src/bin/e_grabinput.c b/src/bin/e_grabinput.c index 5f4b2e8dd..b40a74267 100644 --- a/src/bin/e_grabinput.c +++ b/src/bin/e_grabinput.c @@ -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); }