bu5hm4n pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=c51f35d42a148b34a9cf74714ecc16609984eecb

commit c51f35d42a148b34a9cf74714ecc16609984eecb
Author: Marcel Hollerbach <marcel-hollerb...@t-online.de>
Date:   Sat Sep 2 19:08:18 2017 +0200

    elm_widget: move the complete regsiter/unregister logic
    
    We had here a little problem, state focus_state_eval function handled
    the unregisteration and consideration of the focus flags and then only
    called a helper function (which was a widget function), that then did
    the registeration in logical or regular mode.
    
    Elm scroller for example took that function overwrote it and did onyl
    permit logical registrations. Then again a evaluation of the focus state
    and flags took place, and the function considered elm_scroller should be
    registered as regular object, but found it to be logical. This lead to
    the problem that we permantently unregistered Elm.Scroller and
    registered it again as logical just to unregister it again. This was on
    the one side a performance downside. But also a bug since all items from
    within the Elm_Scrollers sub manager are getting reparent onto the
    parent, which means not the root of the scroller (the scroller itself)
    is the logical entrypoint to the widget but rather this reparented
    widget, which led to unexpected focus  warps like described in T5923.
    
    tldr: this fixes T5923
---
 src/lib/elementary/elc_fileselector.c  |   4 +-
 src/lib/elementary/elm_box.c           |   7 ++-
 src/lib/elementary/elm_box.eo          |   2 +-
 src/lib/elementary/elm_fileselector.eo |   2 +-
 src/lib/elementary/elm_scroller.c      |   6 +-
 src/lib/elementary/elm_scroller.eo     |   2 +-
 src/lib/elementary/elm_table.c         |   7 ++-
 src/lib/elementary/elm_table.eo        |   2 +-
 src/lib/elementary/elm_toolbar.c       |   6 +-
 src/lib/elementary/elm_toolbar.eo      |   2 +-
 src/lib/elementary/elm_widget.c        | 107 +++++++++++++++++++++------------
 src/lib/elementary/elm_widget.eo       |  27 ++++++---
 src/lib/elementary/elm_widget.h        |   6 +-
 13 files changed, 112 insertions(+), 68 deletions(-)

diff --git a/src/lib/elementary/elc_fileselector.c 
b/src/lib/elementary/elc_fileselector.c
index a3536c4b33..3308aef974 100644
--- a/src/lib/elementary/elc_fileselector.c
+++ b/src/lib/elementary/elc_fileselector.c
@@ -3104,9 +3104,9 @@ 
_elm_fileselector_elm_widget_focus_direction_manager_is(Eo *obj EINA_UNUSED, Elm
 }
 
 EOLIAN static Eina_Bool
-_elm_fileselector_elm_widget_focus_register(Eo *obj, Elm_Fileselector_Data 
*pd, Efl_Ui_Focus_Manager *manager, Efl_Ui_Focus_Object *logical, Eina_Bool 
*logical_flag)
+_elm_fileselector_elm_widget_focus_state_apply(Eo *obj, Elm_Fileselector_Data 
*pd, Elm_Widget_Focus_State current_state, Elm_Widget_Focus_State 
*configured_state, Elm_Widget *redirect)
 {
-   Eina_Bool ret = elm_obj_widget_focus_register(efl_super(obj, MY_CLASS), 
manager, logical, logical_flag);
+   Eina_Bool ret = elm_obj_widget_focus_state_apply(efl_super(obj, MY_CLASS), 
current_state, configured_state, redirect);
 
    _focus_chain_update(obj, pd);
 
diff --git a/src/lib/elementary/elm_box.c b/src/lib/elementary/elm_box.c
index 04420be35f..224075d310 100644
--- a/src/lib/elementary/elm_box.c
+++ b/src/lib/elementary/elm_box.c
@@ -720,12 +720,13 @@ _elm_box_class_constructor(Efl_Class *klass)
    evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
 }
 EOLIAN Eina_Bool
-_elm_box_elm_widget_focus_register(Eo *obj, Elm_Box_Data *pd, 
Efl_Ui_Focus_Manager *manager, Efl_Ui_Focus_Object *logical, Eina_Bool 
*logical_flag)
+_elm_box_elm_widget_focus_state_apply(Eo *obj, Elm_Box_Data *pd, 
Elm_Widget_Focus_State current_state, Elm_Widget_Focus_State *configured_state, 
Elm_Widget *redirect)
 {
-   Eina_Bool result = elm_obj_widget_focus_register(efl_super(obj, MY_CLASS), 
manager, logical, logical_flag);
+   Eina_Bool result = elm_obj_widget_focus_state_apply(efl_super(obj, 
MY_CLASS), current_state, configured_state, redirect);
 
    //later registering children are automatically set into the order of the 
internal table
-   _focus_order_flush(obj, pd);
+   if (configured_state->manager)
+     _focus_order_flush(obj, pd);
 
    return result;
 }
diff --git a/src/lib/elementary/elm_box.eo b/src/lib/elementary/elm_box.eo
index efdb2e3838..0269d84945 100644
--- a/src/lib/elementary/elm_box.eo
+++ b/src/lib/elementary/elm_box.eo
@@ -255,7 +255,7 @@ class Elm.Box (Elm.Widget)
       Elm.Widget.focus_next;
       Elm.Widget.theme_apply;
       Elm.Widget.widget_sub_object_del;
-      Elm.Widget.focus_register;
+      Elm.Widget.focus_state_apply;
    }
    events {
       child,added; [[Called when child was added]]
diff --git a/src/lib/elementary/elm_fileselector.eo 
b/src/lib/elementary/elm_fileselector.eo
index 3ac04a40db..ee33eb5ee5 100644
--- a/src/lib/elementary/elm_fileselector.eo
+++ b/src/lib/elementary/elm_fileselector.eo
@@ -41,7 +41,7 @@ class Elm.Fileselector (Efl.Ui.Layout, 
Elm.Interface.Fileselector,
       Elm.Widget.widget_event;
       Elm.Widget.theme_apply;
       Elm.Widget.focus_next_manager_is;
-      Elm.Widget.focus_register;
+      Elm.Widget.focus_state_apply;
       Elm.Interface.Fileselector.selected_models { get; }
       Elm.Interface.Fileselector.selected_model_get;
       Elm.Interface.Fileselector.selected_model_set;
diff --git a/src/lib/elementary/elm_scroller.c 
b/src/lib/elementary/elm_scroller.c
index f764988c91..2c06b1aefa 100644
--- a/src/lib/elementary/elm_scroller.c
+++ b/src/lib/elementary/elm_scroller.c
@@ -1446,11 +1446,11 @@ _elm_scroller_class_constructor(Efl_Class *klass)
 }
 
 EOLIAN static Eina_Bool
-_elm_scroller_elm_widget_focus_register(Eo *obj, Elm_Scroller_Data *pd 
EINA_UNUSED, Efl_Ui_Focus_Manager *manager, Efl_Ui_Focus_Object *logical, 
Eina_Bool *logical_flag)
+_elm_scroller_elm_widget_focus_state_apply(Eo *obj, Elm_Scroller_Data *pd 
EINA_UNUSED, Elm_Widget_Focus_State current_state, Elm_Widget_Focus_State 
*configured_state, Elm_Widget *redirect EINA_UNUSED)
 {
    //undepended from logical or not we always reigster as full with ourself as 
redirect
-   *logical_flag = EINA_TRUE;
-   return efl_ui_focus_manager_calc_register_logical(manager, obj, logical, 
obj);
+   configured_state->logical = EINA_TRUE;
+   return elm_obj_widget_focus_state_apply(efl_super(obj, MY_CLASS), 
current_state, configured_state, obj);
 }
 
 
diff --git a/src/lib/elementary/elm_scroller.eo 
b/src/lib/elementary/elm_scroller.eo
index 48f3f74754..94a1159916 100644
--- a/src/lib/elementary/elm_scroller.eo
+++ b/src/lib/elementary/elm_scroller.eo
@@ -60,7 +60,7 @@ class Elm.Scroller (Efl.Ui.Layout, Elm.Interface_Scrollable,
       Elm.Interface_Scrollable.single_direction { get; set; }
       Elm.Interface.Atspi_Widget_Action.elm_actions { get; }
       Efl.Part.part;
-      Elm.Widget.focus_register;
+      Elm.Widget.focus_state_apply;
    }
    events {
       scroll,page,changed; [[Called when scroll page changed]]
diff --git a/src/lib/elementary/elm_table.c b/src/lib/elementary/elm_table.c
index d90bdc7d8d..dd40369ddb 100644
--- a/src/lib/elementary/elm_table.c
+++ b/src/lib/elementary/elm_table.c
@@ -419,12 +419,13 @@ _elm_table_efl_canvas_group_group_calculate(Eo *obj, void 
*pd EINA_UNUSED)
 }
 
 EOLIAN Eina_Bool
-_elm_table_elm_widget_focus_register(Eo *obj, void *pd EINA_UNUSED, 
Efl_Ui_Focus_Manager *manager, Efl_Ui_Focus_Object *logical, Eina_Bool 
*logical_flag)
+_elm_table_elm_widget_focus_state_apply(Eo *obj, void *pd EINA_UNUSED, 
Elm_Widget_Focus_State current_state, Elm_Widget_Focus_State *configured_state, 
Elm_Widget *redirect)
 {
-   Eina_Bool result = elm_obj_widget_focus_register(efl_super(obj, MY_CLASS), 
manager, logical, logical_flag);
+   Eina_Bool result = elm_obj_widget_focus_state_apply(efl_super(obj, 
MY_CLASS), current_state, configured_state, redirect);
 
    //later registering children are automatically set into the order of the 
internal table
-   _focus_order_flush(obj);
+   if (configured_state->manager)
+     _focus_order_flush(obj);
 
    return result;
 }
diff --git a/src/lib/elementary/elm_table.eo b/src/lib/elementary/elm_table.eo
index 9354068630..0c0536b18b 100644
--- a/src/lib/elementary/elm_table.eo
+++ b/src/lib/elementary/elm_table.eo
@@ -127,6 +127,6 @@ class Elm.Table (Elm.Widget)
       Elm.Widget.focus_direction_manager_is;
       Elm.Widget.theme_apply;
       Elm.Widget.widget_sub_object_del;
-      Elm.Widget.focus_register;
+      Elm.Widget.focus_state_apply;
    }
 }
diff --git a/src/lib/elementary/elm_toolbar.c b/src/lib/elementary/elm_toolbar.c
index 066d675efd..b947e86116 100644
--- a/src/lib/elementary/elm_toolbar.c
+++ b/src/lib/elementary/elm_toolbar.c
@@ -3074,10 +3074,10 @@ elm_toolbar_add(Evas_Object *parent)
 }
 
 EOLIAN static Eina_Bool
-_elm_toolbar_elm_widget_focus_register(Eo *obj, Elm_Toolbar_Data *pd 
EINA_UNUSED, Efl_Ui_Focus_Manager *manager, Efl_Ui_Focus_Object *logical, 
Eina_Bool *logical_flag)
+_elm_toolbar_elm_widget_focus_state_apply(Eo *obj, Elm_Toolbar_Data *pd 
EINA_UNUSED, Elm_Widget_Focus_State current_state, Elm_Widget_Focus_State 
*configured_state, Elm_Widget *redirect)
 {
-   *logical_flag = EINA_TRUE;
-   return efl_ui_focus_manager_calc_register_logical(manager, obj, logical, 
NULL);
+   configured_state->logical = EINA_TRUE;
+   return elm_obj_widget_focus_state_apply(efl_super(obj, MY_CLASS), 
current_state, configured_state, redirect);
 }
 
 EOLIAN static Eo *
diff --git a/src/lib/elementary/elm_toolbar.eo 
b/src/lib/elementary/elm_toolbar.eo
index c9ddc53a12..8864fabbc7 100644
--- a/src/lib/elementary/elm_toolbar.eo
+++ b/src/lib/elementary/elm_toolbar.eo
@@ -330,7 +330,7 @@ class Elm.Toolbar (Elm.Widget, Elm.Interface_Scrollable, 
Efl.Ui.Direction,
       Elm.Widget.focus_highlight_geometry { get; }
       Elm.Widget.focused_item { get; }
       Efl.Ui.Direction.direction { get; set; [[Only supports $vertical and 
$horizontal. Default is $horizontal.]] }
-      Elm.Widget.focus_register;
+      Elm.Widget.focus_state_apply;
       Elm.Interface.Atspi_Widget_Action.elm_actions { get; }
       Elm.Interface.Atspi_Accessible.children { get; }
       Elm.Interface.Atspi_Accessible.state_set { get; }
diff --git a/src/lib/elementary/elm_widget.c b/src/lib/elementary/elm_widget.c
index 92e7e21a09..523a34eb2e 100644
--- a/src/lib/elementary/elm_widget.c
+++ b/src/lib/elementary/elm_widget.c
@@ -332,24 +332,63 @@ _focus_manager_eval(Eo *obj, Elm_Widget_Smart_Data *pd)
 }
 
 EOLIAN static Eina_Bool
-_elm_widget_focus_register(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED,
-  Efl_Ui_Focus_Manager *manager,
-  Efl_Ui_Focus_Object *logical, Eina_Bool *logical_flag)
+_elm_widget_focus_state_apply(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED, 
Elm_Widget_Focus_State current_state, Elm_Widget_Focus_State *configured_state, 
Elm_Widget *redirect)
 {
+   Eina_Bool registered = EINA_TRUE;
 
-   if (!*logical_flag)
-     return efl_ui_focus_manager_calc_register(manager, obj, logical, NULL);
-   else
-     return efl_ui_focus_manager_calc_register_logical(manager, obj, logical, 
NULL);
-}
+   //shortcut for having the same configurations
+   if (current_state.manager == configured_state->manager && 
!current_state.manager)
+     return !!current_state.manager;
+
+   if (configured_state->logical == current_state.logical &&
+       configured_state->manager == current_state.manager &&
+       configured_state->parent == current_state.parent)
+     return !!current_state.manager;
+
+   //this thing doesnt want to be registered, but it is ...
+   if (!configured_state->manager && current_state.manager)
+     {
+        efl_ui_focus_manager_calc_unregister(current_state.manager, obj);
+        return EINA_FALSE;
+     }
+   //by that point we have always a configured manager
+
+   if (!current_state.manager) registered = EINA_FALSE;
+
+   if (//check if we have changed the manager
+       (current_state.manager != configured_state->manager) ||
+       //check if we are already registered but in a different state
+       (current_state.logical != configured_state->logical))
+     {
+        //we need to unregister here
+        efl_ui_focus_manager_calc_unregister(current_state.manager, obj);
+        registered = EINA_FALSE;
+     }
 
+   if (!registered)
+     {
+        if (configured_state->logical)
+          return 
efl_ui_focus_manager_calc_register_logical(configured_state->manager, obj, 
configured_state->parent, redirect);
+        else
+          return efl_ui_focus_manager_calc_register(configured_state->manager, 
obj, configured_state->parent, redirect);
+     }
+   ERR("Uncaught focus state consider this as unregistered (%d) \n (%p,%p,%d) 
\n (%p,%p,%d) ", registered,
+     configured_state->manager, configured_state->parent, 
configured_state->logical,
+     current_state.manager, current_state.parent, current_state.logical
+   );
+   abort();
+   return EINA_FALSE;
+}
 
 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 = pd->manager.manager;
+   Elm_Widget_Focus_State configuration;
+
+   //this would mean we are registering again the root, we dont want that
+   if (pd->manager.manager == obj) return;
 
    //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)
@@ -379,44 +418,38 @@ _focus_state_eval(Eo *obj, Elm_Widget_Smart_Data *pd)
 
         if (_tree_disabled(obj))
           should = EINA_FALSE;
+
+        if (!evas_object_visible_get(obj))
+          should = EINA_FALSE;
      }
 
-   if ( //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)
-      )
+   if (should)
      {
-        efl_ui_focus_manager_calc_unregister(pd->focus.manager, obj);
-        pd->focus.manager = NULL;
-        pd->focus.parent = NULL;
+        configuration.parent = pd->logical.parent;
+        configuration.manager = pd->manager.manager;
+        configuration.logical = !want_full;
      }
-
-   //now register in the manager
-   if (should && !pd->focus.manager)
+   else
      {
-        if (manager && manager != obj)
-          {
-             if (!pd->logical.parent) return;
-
-             pd->focus.manager = manager;
-             pd->focus.logical = !want_full;
-             pd->focus.parent = pd->logical.parent;
-
-             if (!elm_obj_widget_focus_register(obj, pd->focus.manager,
-                  pd->focus.parent, &pd->focus.logical))
-               {
-                  pd->focus.manager = NULL;
-                  pd->focus.parent = NULL;
-               }
-          }
+        configuration.parent = NULL;
+        configuration.manager = NULL;
+        configuration.logical = EINA_FALSE;
      }
-   else if (!should && pd->focus.manager)
+
+   if (!elm_obj_widget_focus_state_apply(obj, pd->focus, &configuration, NULL))
      {
-        efl_ui_focus_manager_calc_unregister(pd->focus.manager, obj);
+        //things went wrong or this thing is unregistered. Purge the current 
configuration.
         pd->focus.manager = NULL;
         pd->focus.parent = NULL;
+        pd->focus.logical = EINA_FALSE;
      }
+   else
+     {
+        pd->focus.parent = configuration.parent;
+        pd->focus.manager = configuration.manager;
+        pd->focus.logical = configuration.logical;
+     }
+
 }
 
 static Efl_Ui_Focus_Object*
diff --git a/src/lib/elementary/elm_widget.eo b/src/lib/elementary/elm_widget.eo
index ebeea3dc14..89d622f159 100644
--- a/src/lib/elementary/elm_widget.eo
+++ b/src/lib/elementary/elm_widget.eo
@@ -10,6 +10,13 @@ function Efl.Ui.Scrollable_On_Show_Region {
 
 struct @extern Elm.Theme; [[Elementary theme]]
 
+struct Elm.Widget.Focus_State {
+   [[All relevant fields needed for the current state of focus registeration]]
+   manager : Efl.Ui.Focus.Manager; [[The manager where the widget is 
registered in]]
+   parent : Efl.Ui.Focus.User; [[The parent the widget is using as logical 
parent]]
+   logical : bool; [[$true if this is registered as logical currently]]
+}
+
 abstract Elm.Widget (Efl.Canvas.Group, Elm.Interface.Atspi_Accessible,
                      Elm.Interface.Atspi_Component, Efl.Ui.Focus.User,
                      Efl.Ui.Focus.Object, Efl.Ui.Base, Efl.Ui.Cursor)
@@ -794,15 +801,21 @@ abstract Elm.Widget (Efl.Canvas.Group, 
Elm.Interface.Atspi_Accessible,
       }
 
       /* Focus Manager API */
-      focus_register @protected {
-         [[Register focus with the given focus manager.]]
+      focus_state_apply @protected {
+         [[Register focus with the given configuration.
+
+           The implementation can feel free to change the logical flag as it 
wants, but other than that it should strictly keep the configuration.
+
+           The implementation in elm.widget updates the current state into 
what is passed as configured state, respecting manager changes, registeration 
and unregistration based on if it should be registered or unregistered.
+
+           A manager field that is $null means that the widget should not or 
was not registered.
+         ]]
          params {
-            @in manager: Efl.Ui.Focus.Manager; [[The focus manager to register 
with.]]
-            @in logical: Efl.Ui.Focus.Object; [[The logical parent to use.]]
-            /* FIXME: The below doc needs fixing! */
-            @inout logical_flag: bool; [[reference to the flag indicating if 
the should be logical or not change this flag to the value you have it 
registered]]
+            @in current_state : Elm.Widget.Focus_State; [[The focus manager to 
register with.]]
+            @inout configured_state : Elm.Widget.Focus_State; [[The evalulated 
Focus state that should be used]]
+            @in redirect : Elm.Widget; [[A redirect that will be set by the 
elm.widget implementation]]
          }
-         return: bool; [[return $true or $false if the registration was 
successfull or not]]
+         return: bool; [[return $true or $false if the widget is registered or 
false if it is not]]
       }
       focus_manager_factory @protected {
          [[If the widget needs a focus manager, this function will be called.
diff --git a/src/lib/elementary/elm_widget.h b/src/lib/elementary/elm_widget.h
index 3bd9b02521..8f3eae2ee0 100644
--- a/src/lib/elementary/elm_widget.h
+++ b/src/lib/elementary/elm_widget.h
@@ -430,11 +430,7 @@ typedef struct _Elm_Widget_Smart_Data
    Elm_Focus_Move_Policy         focus_move_policy;
    Elm_Focus_Region_Show_Mode    focus_region_show_mode;
 
-   struct {
-     Efl_Ui_Focus_Manager *manager; //manager which is currently regsitered in
-     Efl_Ui_Focus_Object *parent; //the parent where it is currently registered
-     Eina_Bool logical;
-   } focus;
+   Elm_Widget_Focus_State focus;
    struct {
       int child_count;
       Efl_Ui_Focus_Object *parent;

-- 


Reply via email to