From b53f3edd15b0590d0c6059e2bfb8f5829a7a7ae8 Mon Sep 17 00:00:00 2001 From: Marcel Hollerbach Date: Wed, 7 Dec 2016 16:59:13 +0100 Subject: [PATCH] elm_widget: update focus register work now it trackes changes of the parent manager. And registers more reliable. --- src/lib/elementary/elm_widget.c | 189 ++++++++++++++++++++++++++++----------- src/lib/elementary/elm_widget.eo | 8 ++ src/lib/elementary/elm_widget.h | 5 +- 3 files changed, 151 insertions(+), 51 deletions(-) diff --git a/src/lib/elementary/elm_widget.c b/src/lib/elementary/elm_widget.c index 0bc4cec..13479fc 100644 --- a/src/lib/elementary/elm_widget.c +++ b/src/lib/elementary/elm_widget.c @@ -205,7 +205,7 @@ _tree_unfocusable(Eo *obj) Elm_Widget *wid = obj; do { - ELM_WIDGET_DATA_GET(obj, wid_pd); + ELM_WIDGET_DATA_GET(wid, wid_pd); if (wid_pd->tree_unfocusable) return EINA_TRUE; } while((wid = elm_widget_parent_widget_get(wid))); @@ -213,33 +213,70 @@ _tree_unfocusable(Eo *obj) return EINA_FALSE; } + +static void _full_eval(Eo *obj, Elm_Widget_Smart_Data *pd); + static void +_manager_changed_cb(void *data, const Efl_Event *event EINA_UNUSED) +{ + ELM_WIDGET_DATA_GET(data, pd); + + _full_eval(data, pd); +} + +static Efl_Ui_Focus_Object* _focus_manager_eval(Eo *obj, Elm_Widget_Smart_Data *pd) { - Evas_Object *parent = obj; - Efl_Ui_Focus_Manager *new = NULL; + Evas_Object *provider = NULL; + Evas_Object *parent; + Efl_Ui_Focus_Manager *new = NULL, *old = NULL; - do + parent = elm_widget_parent_get(obj); + if (efl_isa(parent, EFL_UI_FOCUS_MANAGER_CLASS)) { - if (efl_isa(parent, EFL_UI_FOCUS_MANAGER_CLASS)) - new = parent; + new = parent; + } + else + { + new = efl_ui_focus_user_manager_get(parent); + provider = parent; } - while(!new && (parent = elm_widget_parent_get(parent))); - if (new != pd->focus.chained_manager) + if (new != pd->manager.manager ) { - efl_event_callback_call(obj, EFL_UI_FOCUS_USER_EVENT_MANAGER_CHANGED, new); - pd->focus.chained_manager = new; + old = pd->manager.manager; + + if (pd->manager.provider) + efl_event_callback_del(pd->manager.provider, EFL_UI_FOCUS_USER_EVENT_MANAGER_CHANGED, _manager_changed_cb, obj); + + pd->manager.manager = new; + pd->manager.provider = provider; + + if (pd->manager.provider) + efl_event_callback_add(pd->manager.provider, EFL_UI_FOCUS_USER_EVENT_MANAGER_CHANGED, _manager_changed_cb, obj); } - if (!new) - ERR("Failed to find manager object"); + + return old; +} + +EOLIAN static void +_elm_widget_focus_register(Eo *obj, Elm_Widget_Smart_Data *pd, + Efl_Ui_Focus_Manager *manager, + Efl_Ui_Focus_Object *logical, Eina_Bool full) +{ + if (full) + efl_ui_focus_manager_register(manager, obj, logical, NULL); + else + efl_ui_focus_manager_register_logical(manager, obj, logical); } + static void _focus_state_eval(Eo *obj, Elm_Widget_Smart_Data *pd) { Eina_Bool should = EINA_FALSE; Eina_Bool want_full = EINA_FALSE; + Efl_Ui_Focus_Manager *manager = efl_ui_focus_user_manager_get(obj); //there are two reasons to be registered, the child count is bigger than 0, or the widget is flagged to be able to handle focus if (pd->can_focus) @@ -257,18 +294,27 @@ _focus_state_eval(Eo *obj, Elm_Widget_Smart_Data *pd) if (pd->logical.child_count > 0) should = EINA_TRUE; + if (!manager || + //check if we have changed the manager + (pd->focus.manager != manager && should) || + //check if we are already registered but in a different state + (pd->focus.manager && should && want_full == pd->focus.logical) + ) + { + efl_ui_focus_manager_unregister(pd->focus.manager, obj); + pd->focus.manager = NULL; + } + //now register in the manager if (should && !pd->focus.manager) { - pd->focus.manager = efl_ui_focus_user_manager_get(obj); - pd->focus.logical = !want_full; - - if (pd->focus.manager != obj) + if (manager != obj) { - if (want_full) - efl_ui_focus_manager_register(pd->focus.manager, obj, pd->logical.parent, NULL); - else - efl_ui_focus_manager_register_logical(pd->focus.manager, obj, pd->logical.parent); + pd->focus.manager = manager; + + elm_obj_widget_focus_register(obj, pd->focus.manager, pd->logical.parent, want_full); + + pd->focus.logical = !want_full; } } else if (!should && pd->focus.manager) @@ -276,49 +322,85 @@ _focus_state_eval(Eo *obj, Elm_Widget_Smart_Data *pd) efl_ui_focus_manager_unregister(pd->focus.manager, obj); pd->focus.manager = NULL; } - else if (should && pd->focus.manager && pd->focus.logical && want_full) - { - //the case when we before registered as logical, but now wanted to be a normal node - efl_ui_focus_manager_unregister(pd->focus.manager, obj); - efl_ui_focus_manager_register(pd->focus.manager, obj, pd->focus.manager, NULL); - } } -static void -_event_cb_focus_state_eval(void *data EINA_UNUSED, const Efl_Event *event) -{ - ELM_WIDGET_DATA_GET(event->object, pd); - - _focus_state_eval(event->object, pd); -} - -static void -_logical_parent_eval(Eo *obj, Elm_Widget_Smart_Data *pd) +static Efl_Ui_Focus_Object* +_logical_parent_eval(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd) { Elm_Widget *parent; parent = pd->parent_obj; if (pd->logical.parent != parent) { + Efl_Ui_Focus_Object *old = NULL; + //update old logical parent; if (pd->logical.parent) { ELM_WIDGET_DATA_GET(pd->logical.parent, logical_wd); + if (!logical_wd) + { + ERR("Widget parent has the wrong type!"); + return NULL; + } logical_wd->logical.child_count --; - _focus_state_eval(pd->logical.parent, logical_wd); + old = pd->logical.parent; pd->logical.parent = NULL; } - efl_event_callback_call(obj, - EFL_UI_FOCUS_USER_EVENT_LOGICAL_CHANGED, parent); - if (parent) + if (parent) { ELM_WIDGET_DATA_GET(parent, logical_wd); + if (!logical_wd) + { + ERR("Widget parent has the wrong type!"); + return NULL; + } logical_wd->logical.child_count ++; - _focus_state_eval(parent, logical_wd); pd->logical.parent = parent; efl_weak_ref(&pd->logical.parent); } + return old; } + return NULL; } + +static void +_full_eval(Eo *obj, Elm_Widget_Smart_Data *pd) +{ + Efl_Ui_Focus_Object *old_parent, *old_manager; + + old_parent = _logical_parent_eval(obj, pd); + old_manager = _focus_manager_eval(obj, pd); + + if (old_parent) + { + //emit signal and focus eval old and new + ELM_WIDGET_DATA_GET(old_parent, old_pd); + _focus_state_eval(old_parent, old_pd); + + } + + if (pd->logical.parent) + { + ELM_WIDGET_DATA_GET(pd->logical.parent, new_pd); + _focus_state_eval(pd->logical.parent, new_pd); + } + + if (old_parent != pd->logical.parent) + { + efl_event_callback_call(obj, + EFL_UI_FOCUS_USER_EVENT_LOGICAL_CHANGED, old_parent); + } + + if (old_manager != pd->manager.manager) + { + //emit signal + efl_event_callback_call(obj, + EFL_UI_FOCUS_USER_EVENT_MANAGER_CHANGED, old_manager); + } + + _focus_state_eval(obj, pd); +} + /** * @internal * @@ -934,7 +1016,7 @@ _elm_widget_focus_region_show(const Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNU Evas_Coord sx, sy; elm_interface_scrollable_content_region_get(o, &sx, &sy, NULL, NULL); - // Get the object's on_focus_region position relative to the scroller. + // Get the object's on_focus_region position relative to the scroller. Evas_Coord rx, ry; rx = ox + x - px + sx; ry = oy + y - py + sy; @@ -1287,8 +1369,7 @@ _elm_widget_sub_object_add(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *sobj } sdc->parent_obj = obj; - _logical_parent_eval(sobj, sdc); - _focus_manager_eval(sobj, sdc); + _full_eval(sobj, sdc); if (!sdc->on_create) elm_obj_widget_orientation_set(sobj, sd->orient_mode); @@ -1456,8 +1537,7 @@ _elm_widget_sub_object_del(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *sobj ELM_WIDGET_DATA_GET(sobj, sdc); sdc->parent_obj = NULL; - _logical_parent_eval(sobj, sdc); - _focus_manager_eval(sobj, sdc); + _full_eval(sobj, sdc); } if (sd->resize_obj == sobj) sd->resize_obj = NULL; @@ -6015,9 +6095,6 @@ _elm_widget_efl_object_constructor(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSE elm_interface_atspi_accessible_role_set(obj, ELM_ATSPI_ROLE_UNKNOWN); - efl_event_callback_add(obj, EFL_UI_FOCUS_USER_EVENT_LOGICAL_CHANGED, _event_cb_focus_state_eval, NULL); - efl_event_callback_add(obj, EFL_UI_FOCUS_USER_EVENT_MANAGER_CHANGED , _event_cb_focus_state_eval, NULL); - return obj; } @@ -6041,6 +6118,10 @@ _elm_widget_efl_object_destructor(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSED efl_destructor(efl_super(obj, ELM_WIDGET_CLASS)); sd->on_destroy = EINA_FALSE; + if (sd->manager.provider) + efl_event_callback_del(sd->manager.provider, EFL_UI_FOCUS_USER_EVENT_MANAGER_CHANGED, _manager_changed_cb, obj); + sd->manager.provider = NULL; + elm_interface_atspi_accessible_removed(obj); } @@ -6308,7 +6389,7 @@ _elm_widget_efl_ui_focus_user_parent_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_D EOLIAN static Efl_Ui_Focus_Manager* _elm_widget_efl_ui_focus_user_manager_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd EINA_UNUSED) { - return pd->focus.chained_manager; + return pd->manager.manager; } EOLIAN static void @@ -6319,5 +6400,13 @@ _elm_widget_efl_ui_focus_object_geometry_get(Eo *obj, Elm_Widget_Smart_Data *pd return efl_gfx_geometry_get(obj, &rect->x , &rect->y, &rect->w, &rect->h); } +EOLIAN static void +_elm_widget_efl_ui_focus_object_focus_set(Eo *obj, Elm_Widget_Smart_Data *pd, Eina_Bool focus) +{ + pd->focused = focus; + elm_obj_widget_on_focus(obj, NULL); +} + + #include "elm_widget_item.eo.c" #include "elm_widget.eo.c" diff --git a/src/lib/elementary/elm_widget.eo b/src/lib/elementary/elm_widget.eo index 83916bc..90224a0 100644 --- a/src/lib/elementary/elm_widget.eo +++ b/src/lib/elementary/elm_widget.eo @@ -824,6 +824,13 @@ abstract Elm.Widget (Efl.Canvas.Group, Elm.Interface.Atspi_Accessible, Elm.Inter focus_reconfigure { [[@since 1.18]] } + focus_register { + params { + manager : Efl.Ui.Focus.Manager; + logical : Efl.Ui.Focus.Object; + full : bool; + } + } } implements { class.constructor; @@ -853,6 +860,7 @@ abstract Elm.Widget (Efl.Canvas.Group, Elm.Interface.Atspi_Accessible, Elm.Inter Efl.Ui.Focus.User.manager.get; Efl.Ui.Focus.User.parent.get; Efl.Ui.Focus.Object.geometry_get; + Efl.Ui.Focus.Object.focus.set; } events { moved; [[Called when widget moved]] diff --git a/src/lib/elementary/elm_widget.h b/src/lib/elementary/elm_widget.h index 561afbc..f9aa7a0 100644 --- a/src/lib/elementary/elm_widget.h +++ b/src/lib/elementary/elm_widget.h @@ -457,7 +457,6 @@ typedef struct _Elm_Widget_Smart_Data Eina_Bool on_destroy: 1; /**< This is true when the widget is on destruction(general widget destructor). */ Eina_Bool provider_lookup : 1; /**< This is true when efl_provider_find is currently walking the tree */ struct { - Efl_Ui_Focus_Manager *chained_manager; //manager which is the correct according to the chain Efl_Ui_Focus_Manager *manager; //manager which is currently regsitered in Eina_Bool logical; } focus; @@ -465,6 +464,10 @@ typedef struct _Elm_Widget_Smart_Data int child_count; Efl_Ui_Focus_Object *parent; } logical; + struct { + Efl_Ui_Focus_Manager *manager; + Efl_Ui_Focus_User *provider; + } manager; } Elm_Widget_Smart_Data; /** -- 2.7.4