efl/src/lib/elementary/efl_ui_focus_composition.c

316 lines
9.7 KiB
C

#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#define EFL_UI_FOCUS_COMPOSITION_PROTECTED
#define EFL_UI_FOCUS_OBJECT_PROTECTED
#include <Elementary.h>
#include "elm_priv.h"
#include "efl_ui_focus_composition_adapter.eo.h"
#define MY_CLASS EFL_UI_FOCUS_COMPOSITION_MIXIN
typedef struct {
Eina_List *order, *targets_ordered;
Eina_List *register_target, *registered_targets;
Efl_Ui_Focus_Manager *registered, *old_manager;
Eina_Bool dirty;
Eina_Bool logical;
} Efl_Ui_Focus_Composition_Data;
static void
_state_apply(Eo *obj, Efl_Ui_Focus_Composition_Data *pd)
{
Efl_Ui_Focus_Manager *manager;
//Legacy code compatibility, only update the custom chain of elements if legacy was NOT messing with it.
if (elm_widget_is_legacy(obj) && elm_object_focus_custom_chain_get(obj)) return;
manager = pd->registered;
if (manager)
{
Eina_List *n;
Eina_List *safed = NULL;
Efl_Ui_Focus_Object *o;
pd->old_manager = manager;
//remove all of them
EINA_LIST_FREE(pd->registered_targets, o)
{
if (!!eina_list_data_find(pd->register_target, o))
safed = eina_list_append(safed, o);
else
efl_ui_focus_manager_calc_unregister(manager, o);
if (efl_isa(o, EFL_UI_FOCUS_COMPOSITION_ADAPTER_CLASS))
{
efl_ui_focus_composition_adapter_focus_manager_parent_set(o, NULL);
efl_ui_focus_composition_adapter_focus_manager_object_set(o, NULL);
}
}
pd->registered_targets = safed;
EINA_LIST_FOREACH(pd->register_target, n, o)
{
if (!!eina_list_data_find(pd->registered_targets, o)) continue;
if (!pd->logical)
efl_ui_focus_manager_calc_register(manager, o, obj, NULL);
else
efl_ui_focus_manager_calc_register_logical(manager, o, obj, NULL);
if (efl_isa(o, EFL_UI_FOCUS_COMPOSITION_ADAPTER_CLASS))
{
efl_ui_focus_composition_adapter_focus_manager_parent_set(o, obj);
efl_ui_focus_composition_adapter_focus_manager_object_set(o, manager);
}
pd->registered_targets = eina_list_append(pd->registered_targets, o);
}
efl_ui_focus_manager_calc_update_order(manager, obj, eina_list_clone(pd->targets_ordered));
}
else
{
Efl_Ui_Focus_Object *o;
EINA_LIST_FREE(pd->registered_targets, o)
{
efl_ui_focus_manager_calc_unregister(pd->old_manager, o);
if (efl_isa(o, EFL_UI_FOCUS_COMPOSITION_ADAPTER_CLASS))
{
efl_ui_focus_composition_adapter_focus_manager_parent_set(o, NULL);
efl_ui_focus_composition_adapter_focus_manager_object_set(o, NULL);
}
}
}
}
static void
_invalidate(void *data, const Efl_Event *ev)
{
Efl_Ui_Focus_Composition_Data *pd = efl_data_scope_get(data, EFL_UI_FOCUS_COMPOSITION_MIXIN);
pd->register_target = eina_list_remove(pd->register_target, ev->object);
pd->registered_targets = eina_list_remove(pd->registered_targets, ev->object);
}
EOLIAN static void
_efl_ui_focus_composition_composition_elements_set(Eo *obj, Efl_Ui_Focus_Composition_Data *pd, Eina_List *logical_order)
{
Evas_Object *elem;
Eina_List *n;
pd->targets_ordered = eina_list_free(pd->targets_ordered);
EINA_LIST_FREE(pd->register_target, elem)
{
efl_event_callback_del(elem, EFL_EVENT_INVALIDATE, _invalidate, obj);
}
pd->order = eina_list_free(pd->order);
pd->order = logical_order;
//now build a composition_elements list
EINA_LIST_FOREACH(logical_order, n, elem)
{
Efl_Ui_Focus_Object *o = elem;
EINA_SAFETY_ON_NULL_GOTO(elem, cont);
if (!efl_isa(elem, EFL_UI_WIDGET_CLASS))
{
if (efl_isa(elem, EFL_UI_FOCUS_OBJECT_MIXIN))
{
pd->register_target = eina_list_append(pd->register_target , o);
efl_event_callback_add(o, EFL_EVENT_INVALIDATE, _invalidate, obj);
}
else
{
EINA_SAFETY_ERROR("List contains element that is not EFL_UI_FOCUS_OBJECT_MIXIN or EFL_GFX_ENTITY_INTERFACE or EFL_UI_WIDGET_CLASS");
continue;
}
}
pd->targets_ordered = eina_list_append(pd->targets_ordered, o);
cont:
continue;
}
_state_apply(obj, pd);
}
EOLIAN static Eina_List*
_efl_ui_focus_composition_composition_elements_get(const Eo *obj EINA_UNUSED, Efl_Ui_Focus_Composition_Data *pd)
{
return eina_list_clone(pd->order);
}
EOLIAN static Eina_Bool
_efl_ui_focus_composition_efl_ui_widget_focus_state_apply(Eo *obj, Efl_Ui_Focus_Composition_Data *pd, Efl_Ui_Widget_Focus_State current_state, Efl_Ui_Widget_Focus_State *configured_state, Efl_Ui_Widget *redirect)
{
Eina_Bool registered;
configured_state->logical = EINA_TRUE;
//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;
registered = efl_ui_widget_focus_state_apply(efl_super(obj, MY_CLASS), current_state, configured_state, redirect);
if (registered)
{
if (efl_isa(obj, EFL_UI_FOCUS_MANAGER_INTERFACE))
pd->registered = obj;
else
pd->registered = configured_state->manager;
}
else
pd->registered = NULL;
_state_apply(obj, pd);
return registered;
}
EOLIAN static void
_efl_ui_focus_composition_dirty(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Composition_Data *pd)
{
pd->dirty = EINA_TRUE;
}
EOLIAN static void
_efl_ui_focus_composition_efl_ui_focus_object_setup_order_non_recursive(Eo *obj, Efl_Ui_Focus_Composition_Data *pd EINA_UNUSED)
{
if (pd->dirty)
{
efl_ui_focus_composition_prepare(obj);
pd->dirty = EINA_FALSE;
}
efl_ui_focus_object_setup_order_non_recursive(efl_super(obj, MY_CLASS));
}
EOLIAN static void
_efl_ui_focus_composition_logical_mode_set(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Composition_Data *pd, Eina_Bool logical_mode)
{
pd->logical = logical_mode;
}
EOLIAN static Eina_Bool
_efl_ui_focus_composition_logical_mode_get(const Eo *obj EINA_UNUSED, Efl_Ui_Focus_Composition_Data *pd)
{
return pd->logical;
}
EOLIAN static void
_efl_ui_focus_composition_efl_object_invalidate(Eo *obj, Efl_Ui_Focus_Composition_Data *pd EINA_UNUSED)
{
efl_invalidate(efl_super(obj, MY_CLASS));
efl_ui_focus_composition_elements_set(obj, NULL);
}
#include "efl_ui_focus_composition.eo.c"
typedef struct {
Evas_Object *object;
Efl_Ui_Focus_Manager *manager;
Efl_Ui_Focus_Object *parent;
} Efl_Ui_Focus_Composition_Adapter_Data;
static void
_canvas_object_deleted(void *data, const Efl_Event *ev EINA_UNUSED)
{
efl_ui_focus_composition_adapter_canvas_object_set(data, NULL);
}
static void
_new_geom(void *data, const Efl_Event *event EINA_UNUSED)
{
Eina_Rect rect = efl_ui_focus_object_focus_geometry_get(data);
efl_event_callback_call(data, EFL_UI_FOCUS_OBJECT_EVENT_FOCUS_GEOMETRY_CHANGED, &rect);
}
EFL_CALLBACKS_ARRAY_DEFINE(canvas_obj,
{EFL_GFX_ENTITY_EVENT_SIZE_CHANGED, _new_geom},
{EFL_GFX_ENTITY_EVENT_POSITION_CHANGED, _new_geom},
{EFL_EVENT_DEL, _canvas_object_deleted},
);
EOLIAN static void
_efl_ui_focus_composition_adapter_canvas_object_set(Eo *obj, Efl_Ui_Focus_Composition_Adapter_Data *pd, Efl_Canvas_Object *v)
{
if (pd->object)
{
efl_event_callback_array_del(pd->object, canvas_obj(), obj);
}
pd->object = v;
if (v)
{
efl_event_callback_array_add(pd->object, canvas_obj(), obj);
}
}
EOLIAN static Efl_Canvas_Object*
_efl_ui_focus_composition_adapter_canvas_object_get(const Eo *obj EINA_UNUSED, Efl_Ui_Focus_Composition_Adapter_Data *pd)
{
return pd->object;
}
EOLIAN static Eina_Rect
_efl_ui_focus_composition_adapter_efl_ui_focus_object_focus_geometry_get(const Eo *obj EINA_UNUSED, Efl_Ui_Focus_Composition_Adapter_Data *pd EINA_UNUSED)
{
return efl_gfx_entity_geometry_get(pd->object);
}
EOLIAN static void
_efl_ui_focus_composition_adapter_efl_ui_focus_object_focus_set(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Composition_Adapter_Data *pd, Eina_Bool focus)
{
efl_ui_focus_object_focus_set(efl_super(obj, EFL_UI_FOCUS_COMPOSITION_ADAPTER_CLASS), focus);
evas_object_focus_set(pd->object, efl_ui_focus_object_focus_get(obj));
}
EOLIAN static void
_efl_ui_focus_composition_adapter_efl_object_destructor(Eo *obj, Efl_Ui_Focus_Composition_Adapter_Data *pd EINA_UNUSED)
{
efl_ui_focus_composition_adapter_canvas_object_set(obj, NULL);
efl_destructor(efl_super(obj, EFL_UI_FOCUS_COMPOSITION_ADAPTER_CLASS));
}
EOLIAN static void
_efl_ui_focus_composition_adapter_focus_manager_object_set(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Composition_Adapter_Data *pd, Efl_Ui_Focus_Manager *v)
{
pd->manager = v;
}
EOLIAN static void
_efl_ui_focus_composition_adapter_focus_manager_parent_set(Eo *obj EINA_UNUSED, Efl_Ui_Focus_Composition_Adapter_Data *pd, Efl_Ui_Focus_Object *parent)
{
pd->parent = parent;
}
EOLIAN static Efl_Ui_Focus_Object*
_efl_ui_focus_composition_adapter_efl_ui_focus_object_focus_parent_get(const Eo *obj EINA_UNUSED, Efl_Ui_Focus_Composition_Adapter_Data *pd)
{
return pd->parent;
}
EOLIAN static Efl_Ui_Focus_Manager*
_efl_ui_focus_composition_adapter_efl_ui_focus_object_focus_manager_get(const Eo *obj EINA_UNUSED, Efl_Ui_Focus_Composition_Adapter_Data *pd)
{
return pd->manager;
}
#include "efl_ui_focus_composition_adapter.eo.c"