From 76e39954181062c6e7930c4d51541c435d6c1257 Mon Sep 17 00:00:00 2001 From: Sungho Kwak Date: Thu, 20 Jun 2013 19:47:15 +0900 Subject: [PATCH] Initialize efl-assist Change-Id: Ida7e933065bd1b2193e1ddebce23f889a65ffa8a --- src/CMakeLists.txt | 8 + src/include/CMakeLists.txt | 6 + src/include/efl_assist.h | 26 +++ src/include/efl_assist_editfield.h | 85 ++++++++ src/include/efl_assist_events.h | 146 +++++++++++++ src/include/efl_assist_private.h | 77 +++++++ src/lib/CMakeLists.txt | 35 ++++ src/lib/efl_assist.c | 123 +++++++++++ src/lib/efl_assist_editfield.c | 141 +++++++++++++ src/lib/efl_assist_events.c | 408 +++++++++++++++++++++++++++++++++++++ 10 files changed, 1055 insertions(+) create mode 100644 src/CMakeLists.txt create mode 100644 src/include/CMakeLists.txt create mode 100644 src/include/efl_assist.h create mode 100644 src/include/efl_assist_editfield.h create mode 100644 src/include/efl_assist_events.h create mode 100644 src/include/efl_assist_private.h create mode 100644 src/lib/CMakeLists.txt create mode 100644 src/lib/efl_assist.c create mode 100644 src/lib/efl_assist_editfield.c create mode 100644 src/lib/efl_assist_events.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..502ae8b --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,8 @@ +SET(LIB_NAME ${PROJECT_NAME}) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include) +LINK_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/lib) + +ADD_SUBDIRECTORY(include) +ADD_SUBDIRECTORY(lib) +#ADD_SUBDIRECTORY(examples) diff --git a/src/include/CMakeLists.txt b/src/include/CMakeLists.txt new file mode 100644 index 0000000..b9f586f --- /dev/null +++ b/src/include/CMakeLists.txt @@ -0,0 +1,6 @@ +INSTALL( + DIRECTORY ./ DESTINATION include/${LIB_NAME} + FILES_MATCHING + PATTERN "*_private.h" EXCLUDE + PATTERN "*.h" + ) diff --git a/src/include/efl_assist.h b/src/include/efl_assist.h new file mode 100644 index 0000000..f914dce --- /dev/null +++ b/src/include/efl_assist.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __EFL_ASSIST_H__ +#define __EFL_ASSIST_H__ + + +#include "efl_assist_editfield.h" +#include "efl_assist_events.h" + +#endif /* __EFL_ASSIST_H__ */ + diff --git a/src/include/efl_assist_editfield.h b/src/include/efl_assist_editfield.h new file mode 100644 index 0000000..3f99d22 --- /dev/null +++ b/src/include/efl_assist_editfield.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __EFL_ASSIST_EDITFIELD_H__ +#define __EFL_ASSIST_EDITFIELD_H__ + +#include +#include +#ifndef DESKTOP + #include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @typedef Ea_Editfield_Type + * + * Editfield Entry types. + * + * @see ea_editfield_add() + */ +typedef enum +{ + EA_EDITFIELD_SINGLELINE, + EA_EDITFIELD_MULTILINE, + EA_EDITFIELD_SCROLL_SINGLELINE, + EA_EDITFIELD_SCROLL_MULTILINE, + EA_EDITFIELD_SCROLL_SINGLELINE_PASSWORD, + EA_EDITFIELD_SEARCHBAR +} Ea_Editfield_Type; + +/** + * @brief Add an elementary entry widget with clear button and rename icon. + * + * @details Add an elementary entry widget with some special features. + * The first is clear button that will delete all characters in current entry widget. + * The second is rename icon which symbolizes the editable field in dialogue view. + * Visible state of each clear button and rename icon will be changed automatically. + * This API will return an elementary entry widget, and some elm_entry APIs can change + * the internal state of this widget. For maintaining the original states of entry widget, + * following signal emitting is needed : + * + * 1. For maintaining visible state of rename icon : + * "elm,state,rename,visible", "elm,state,rename,hidden" + * + * 2. For maintaining visible state of clear button : + * "elm,state,clear,visible", "elm,state,clear,hidden" + * + * 3. For maintaining scrollable state of entry : + * "elm,state,scroll,enabled", "elm,state,scroll,disabled" + * + * + * @param [in] parent The parent widget object + * @param [in] type Types for supporting different entry widget modes. + * + * @return elementary entry widget + * + */ +Evas_Object *ea_editfield_add(Evas_Object *parent, Ea_Editfield_Type type); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __EFL_ASSIST_EDITFIELD_H__ */ diff --git a/src/include/efl_assist_events.h b/src/include/efl_assist_events.h new file mode 100644 index 0000000..c0441d0 --- /dev/null +++ b/src/include/efl_assist_events.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __EFL_ASSIST_EVENTS_H__ +#define __EFL_ASSIST_EVENTS_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Convenient macro function that sends back key events to the popup + * to be removed. + * + * @see ea_object_event_callback_add() + */ +static inline void +ea_popup_back_cb(void *data, Evas_Object *obj, void *event_info) +{ + evas_object_del(obj); +} + +/** + * @brief Convenient macro function that sends back key events to the ctxpopup + * to be dismissed. + * + * @see ea_object_event_callback_add() + */ +static inline void +ea_ctxpopup_back_cb(void *data, Evas_Object *obj, void *event_info) +{ + elm_ctxpopup_dismiss(obj); +} + +/** + * @brief Convenient macro function that sends more key events to the naviframe + * top item. + * @see ea_object_event_callback_add() + */ +static inline void +ea_naviframe_more_cb(void *data, Evas_Object *obj, void *event_info) +{ + Elm_Object_Item *top = elm_naviframe_top_item_get(obj); + if (!top) return; + Evas_Object *more_btn = elm_object_item_part_content_get(top, "toolbar_more_btn"); + if (more_btn) + evas_object_smart_callback_call(more_btn, "clicked", NULL); +} + +/** + * @brief Convenient macro function that pop the naviframe item. + * @see ea_object_event_callback_add() + */ +static inline void +ea_naviframe_back_cb(void *data, Evas_Object *obj, void *event_info) +{ + elm_naviframe_item_pop(obj); +} + +/** + * Identifier of callbacks to be set for Ea events. + * + * @see ea_object_event_callback_add() + * @see ea_object_event_callback_del() + */ +typedef enum _Ea_Callback_Type +{ + EA_CALLBACK_BACK, + EA_CALLBACK_MORE, + EA_CALLBACK_LAST +} Ea_Callback_Type; + +/** +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef LOG_TAG +#undef LOG_TAG +#endif + +#define LOG_TAG "efl-assist" +#define __CONSTRUCTOR__ __attribute__ ((constructor)) +#define __DESTRUCTOR__ __attribute__ ((destructor)) + +/* eina magic types */ +#define EA_MAGIC_NONE 0x87657890 +#define EA_MAGIC_CUTLINK 0x78908765 + +typedef unsigned int ea_magic; +#define EA_MAGIC ea_magic __magic + +#define EA_MAGIC_SET(d, m) (d)->__magic = (m) +#define EA_MAGIC_CHECK(d, m) ((d) && ((d)->__magic == (m))) +#define EA_MAGIC_FAIL(d, m, fn) \ + _ea_magic_fail((d), (d) ? (d)->__magic : 0, (m), (fn)); + +void _ea_magic_fail(const void *d, ea_magic m, + ea_magic req_m, const char *fname); + +#define CRITICAL(...) EINA_LOG_DOM_CRIT(_ea.ea_log_dom, __VA_ARGS__) +#define ERR(...) EINA_LOG_DOM_ERR(_ea.ea_log_dom, __VA_ARGS__) +#define WRN(...) EINA_LOG_DOM_WARN(_ea.ea_log_dom, __VA_ARGS__) +#define INF(...) EINA_LOG_DOM_INFO(_ea.ea_log_dom, __VA_ARGS__) +#define DBG(...) EINA_LOG_DOM_DBG(_ea.ea_log_dom, __VA_ARGS__) + +typedef struct _Ea Ea; +typedef struct _Ea_Event_Mgr Ea_Event_Mgr; + +struct _Ea +{ + Eina_List *event_mgrs; + int ea_log_dom; +}; + +extern Ea _ea; + +void ea_event_mgr_clear(Ea_Event_Mgr *event_mgr); + +#ifdef __cplusplus +} +#endif + +#endif /* __EFL_ASSIST_PRIVATE_H__ */ diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt new file mode 100644 index 0000000..3e3656c --- /dev/null +++ b/src/lib/CMakeLists.txt @@ -0,0 +1,35 @@ +option(DESKTOP "Build for i386 linux desktop" OFF) + +if (DESKTOP) + SET(LIB_SRCS + efl_assist.c + efl_assist_editfield.c + efl_assist_events.c) +else (DESKTOP) + SET(LIB_SRCS + efl_assist.c + efl_assist_editfield.c + efl_assist_events.c) +endif (DESKTOP) + +ADD_LIBRARY(${LIB_NAME} SHARED ${LIB_SRCS}) + +if (DESKTOP) + PKG_CHECK_MODULES(LIB_PKGS REQUIRED elementary) + ADD_DEFINITIONS("-DDESKTOP=1") + ADD_DEFINITIONS("-DEXPORT_API=__attribute__((visibility(\"default\")))") +else (DESKTOP) + PKG_CHECK_MODULES(LIB_PKGS REQUIRED elementary capi-base-common capi-appfw-application) +endif (DESKTOP) + +FOREACH(flag ${LIB_PKGS_CFLAGS}) + SET(LIB_CFLAGS "${LIB_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES COMPILE_FLAGS "${LIB_CFLAGS}") +SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES VERSION ${VERSION}) +SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES SOVERSION ${VERSION_MAJOR}) +TARGET_LINK_LIBRARIES(${LIB_NAME} ${LIB_PKGS_LDFLAGS} ${LIB_TARGET_PKGS_LDFLAGS}) + +INSTALL(TARGETS ${LIB_NAME} DESTINATION lib) + diff --git a/src/lib/efl_assist.c b/src/lib/efl_assist.c new file mode 100644 index 0000000..8d92501 --- /dev/null +++ b/src/lib/efl_assist.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "efl_assist.h" +#include "efl_assist_private.h" + +/*===========================================================================* + * Local * + *===========================================================================*/ + +Ea _ea; + +static void +ea_init(void) +{ + memset(&_ea, 0x00, sizeof(_ea)); + + _ea.ea_log_dom = eina_log_domain_register("efl-assist", + EINA_COLOR_LIGHTBLUE); + if (!_ea.ea_log_dom) + { + EINA_LOG_ERR("could not register efl-assist log domain"); + _ea.ea_log_dom = EINA_LOG_DOMAIN_GLOBAL; + } +} + +static void +ea_shutdown(void) +{ + Eina_List *l; + Ea_Event_Mgr *event_mgr; + + //Remove Event Managers + EINA_LIST_FOREACH(_ea.event_mgrs, l, event_mgr) + ea_event_mgr_clear(event_mgr); + _ea.event_mgrs = eina_list_free(_ea.event_mgrs); + + if ((_ea.ea_log_dom > - 1) && (_ea.ea_log_dom != EINA_LOG_DOMAIN_GLOBAL)) + { + eina_log_domain_unregister(_ea.ea_log_dom); + _ea.ea_log_dom = -1; + } +} + +static const char * +_magic_string_get(ea_magic m) +{ + switch (m) { + case EA_MAGIC_NONE: + return "None (Freed Object)"; + + case EA_MAGIC_CUTLINK: + return "cutlink"; + + default: + return ""; + } +} + +__CONSTRUCTOR__ static void +ea_mod_init(void) +{ + if (!elm_init(0, NULL)) { + fprintf(stderr, "could not initialize elementary.\n"); + return; + } + + ea_init(); + + DBG("loaded"); +} + +__DESTRUCTOR__ static void +ea_mod_shutdown(void) +{ + DBG("unloaded"); + + ea_shutdown(); + elm_shutdown(); +} + + +/*===========================================================================* + * Global * + *===========================================================================*/ + +void +_ea_magic_fail(const void *d, ea_magic m, ea_magic req_m, const char *fname) +{ + ERR("\n*** MAGIC FAIL (%s) ***\n", fname); + + if (!d) + ERR(" Input handle pointer is NULL!"); + else if (m == EA_MAGIC_NONE) + ERR(" Input handle has already been freed!"); + else if (m != req_m) + ERR(" Input handle is wrong type\n" + " Expected: %08x - %s\n" + " Supplied: %08x - %s", + (unsigned int)req_m, _magic_string_get(req_m), + (unsigned int)m, _magic_string_get(m)); + + if (getenv("EA_ERROR_ABORT")) abort(); +} + +/*===========================================================================* + * API * + *===========================================================================*/ + diff --git a/src/lib/efl_assist_editfield.c b/src/lib/efl_assist_editfield.c new file mode 100644 index 0000000..9fe6d2c --- /dev/null +++ b/src/lib/efl_assist_editfield.c @@ -0,0 +1,141 @@ +#include "efl_assist.h" +#include "efl_assist_private.h" + +static void _editfield_changed_cb(void *data, Evas_Object *obj, void *event_info) +{ + if (elm_object_part_content_get(obj, "elm.swallow.clear")) + { + if (elm_object_focus_get(obj)) + { + if (elm_entry_is_empty(obj)) + elm_object_signal_emit(obj, "elm,state,clear,hidden", ""); + else + elm_object_signal_emit(obj, "elm,state,clear,visible", ""); + } + } +} + +static void _editfield_focused_cb(void *data, Evas_Object *obj, void *event_info) +{ + if (elm_object_part_content_get(obj, "elm.swallow.clear")) + { + if (!elm_entry_is_empty(obj)) + elm_object_signal_emit(obj, "elm,state,clear,visible", ""); + else + elm_object_signal_emit(obj, "elm,state,clear,hidden", ""); + } + elm_object_signal_emit(obj, "elm,state,focus,on", ""); +} + +static void _editfield_unfocused_cb(void *data, Evas_Object *obj, void *event_info) +{ + if (elm_object_part_content_get(obj, "elm.swallow.clear")) + elm_object_signal_emit(obj, "elm,state,clear,hidden", ""); + elm_object_signal_emit(obj, "elm,state,focus,off", ""); +} + +static void _eraser_btn_clicked_cb(void *data, Evas_Object *obj, void *event_info) +{ + elm_entry_entry_set(data, ""); +} + +static void _editfield_searchbar_changed_cb(void *data, Evas_Object *obj, void *event_info) +{ + if (elm_object_part_content_get(obj, "elm.swallow.clear")) + { + if (elm_entry_is_empty(obj)) + elm_object_signal_emit(obj, "elm,state,clear,hidden", ""); + else + elm_object_signal_emit(obj, "elm,state,clear,visible", ""); + } +} + +static void _editfield_searchbar_focused_cb(void *data, Evas_Object *obj, void *event_info) +{ + elm_object_signal_emit(obj, "elm,state,focus,on", ""); +} + +static void _editfield_searchbar_unfocused_cb(void *data, Evas_Object *obj, void *event_info) +{ + elm_object_signal_emit(obj, "elm,state,focus,off", ""); +} + +EXPORT_API Evas_Object * +ea_editfield_add(Evas_Object *parent, Ea_Editfield_Type type) +{ + Evas_Object *entry, *button; + + entry = elm_entry_add(parent); + + if (type == EA_EDITFIELD_SINGLELINE) + { + elm_object_style_set(entry, "editfield"); + elm_entry_single_line_set(entry, EINA_TRUE); + } + else if (type == EA_EDITFIELD_SCROLL_SINGLELINE) + { + elm_object_style_set(entry, "editfield"); + elm_entry_single_line_set(entry, EINA_TRUE); + elm_entry_scrollable_set(entry, EINA_TRUE); + elm_object_signal_emit(entry, "elm,state,scroll,enabled", ""); + } + else if (type == EA_EDITFIELD_SCROLL_SINGLELINE_PASSWORD) + { + elm_object_style_set(entry, "editfield"); + elm_entry_single_line_set(entry, EINA_TRUE); + elm_entry_password_set(entry, EINA_TRUE); + elm_entry_scrollable_set(entry, EINA_TRUE); + elm_object_signal_emit(entry, "elm,state,scroll,enabled", ""); + } + else if (type == EA_EDITFIELD_SCROLL_MULTILINE) + { + elm_object_style_set(entry, "editfield"); + elm_entry_scrollable_set(entry, EINA_TRUE); + elm_object_signal_emit(entry, "elm,state,scroll,enabled", ""); + } + else if (type == EA_EDITFIELD_SEARCHBAR) + { + elm_object_style_set(entry, "editfield/searchbar/default"); + elm_entry_single_line_set(entry, EINA_TRUE); + elm_entry_scrollable_set(entry, EINA_TRUE); + elm_object_signal_emit(entry, "elm,state,scroll,enabled", ""); + } + else + { + elm_object_style_set(entry, "editfield"); + } + + if (type == EA_EDITFIELD_SEARCHBAR) + { + button = elm_button_add(parent); + elm_object_style_set(button, "search_icon"); + elm_object_focus_allow_set(button, EINA_FALSE); + elm_object_part_content_set(entry, "elm.swallow.icon", button); + + button = elm_button_add(parent); + elm_object_style_set(button, "search_clear"); + elm_object_focus_allow_set(button, EINA_FALSE); + elm_object_part_content_set(entry, "elm.swallow.clear", button); + evas_object_smart_callback_add(button, "clicked", _eraser_btn_clicked_cb, entry); + + evas_object_smart_callback_add(entry, "changed", _editfield_searchbar_changed_cb, NULL); + evas_object_smart_callback_add(entry, "preedit,changed", _editfield_searchbar_changed_cb, NULL); + evas_object_smart_callback_add(entry, "focused", _editfield_searchbar_focused_cb, NULL); + evas_object_smart_callback_add(entry, "unfocused", _editfield_searchbar_unfocused_cb, NULL); + } + else + { + button = elm_button_add(parent); + elm_object_style_set(button, "editfield_clear"); + elm_object_focus_allow_set(button, EINA_FALSE); + elm_object_part_content_set(entry, "elm.swallow.clear", button); + evas_object_smart_callback_add(button, "clicked", _eraser_btn_clicked_cb, entry); + + evas_object_smart_callback_add(entry, "changed", _editfield_changed_cb, NULL); + evas_object_smart_callback_add(entry, "preedit,changed", _editfield_changed_cb, NULL); + evas_object_smart_callback_add(entry, "focused", _editfield_focused_cb, NULL); + evas_object_smart_callback_add(entry, "unfocused", _editfield_unfocused_cb, NULL); + } + + return entry; +} diff --git a/src/lib/efl_assist_events.c b/src/lib/efl_assist_events.c new file mode 100644 index 0000000..fc4a8e1 --- /dev/null +++ b/src/lib/efl_assist_events.c @@ -0,0 +1,408 @@ +#include "efl_assist.h" +#include "efl_assist_private.h" + +struct _Ea_Event_Mgr +{ + Eina_List *obj_events; + Evas *e; + Evas_Object *key_grab_rect; +}; + +typedef struct _Ea_Object_Event +{ + Evas_Object *obj; + Evas_Object *parent; + Eina_List *callbacks; +} Ea_Object_Event; + +typedef struct _Ea_Event_Callback +{ + Ea_Callback_Type type; + void (*func)(void *data, Evas_Object *obj, void *event_info); + void *data; +} Ea_Event_Callback; + +const char *EA_OBJ_KEY_EVENT_MGR = "_ea_obj_key_event_mgr"; +const char *EA_OBJ_KEY_OBJ_EVENT = "_ea_obj_key_obj_event"; +const char *EA_KEY_BACK = "XF86Stop"; +const char *EA_KEY_BACK2 = "Escape"; +const char *EA_KEY_SEND = "XF86Send"; + +static void +_ea_event_mgr_del(Ea_Event_Mgr *event_mgr) +{ + if (event_mgr->obj_events) return; + + //Redundant Event Mgr. Remove it. + evas_object_del(event_mgr->key_grab_rect); + _ea.event_mgrs = eina_list_remove(_ea.event_mgrs, event_mgr); + free(event_mgr); +} + +static void +_ea_object_del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Ea_Event_Mgr *event_mgr = evas_object_data_get(obj, EA_OBJ_KEY_EVENT_MGR); + Ea_Object_Event *obj_event = data; + Eina_List *l; + Ea_Event_Callback *callback; + + l = eina_list_data_find_list(event_mgr->obj_events, obj_event); + if (!l) return; + + event_mgr->obj_events = eina_list_remove_list(event_mgr->obj_events, l); + + EINA_LIST_FOREACH(obj_event->callbacks, l, callback) + free(callback); + obj_event->callbacks = eina_list_free(obj_event->callbacks); + + free(obj_event); + + _ea_event_mgr_del(event_mgr); +} + +static int +_ea_layer_sort_cb(const void *data1, const void *data2) +{ + const Ea_Object_Event *obj_event = data1; + const Ea_Object_Event *obj_event2 = data2; + + //1. Layer Compare + int layer1 = evas_object_layer_get(obj_event->obj); + int layer2 = evas_object_layer_get(obj_event2->obj); + + return (layer1 < layer2) ? -1 : 1; +} + +static Evas_Object * +_ea_top_parent_candidates(Eina_List **candidates, Evas *e) +{ + Evas_Object *temp; + Evas_Object *parent; + Eina_List *l, *l_next; + Ea_Object_Event *obj_event; + Eina_List *_candidates = *candidates; + Eina_Bool found = EINA_FALSE; + + //Get the top parent lists + EINA_LIST_FOREACH(_candidates, l, obj_event) + { + temp = obj_event->obj; + parent = obj_event->obj; + while (temp) + { + parent = temp; + temp = evas_object_smart_parent_get(temp); + } + obj_event->parent = parent; + } + + //Leave only parent candidates. + parent = evas_object_top_get(e); + + while (parent) + { + EINA_LIST_FOREACH(_candidates, l, obj_event) + { + if (parent == obj_event->parent) + { + found = EINA_TRUE; + obj_event->parent = NULL; + } + } + if (found) break; + parent = evas_object_below_get(parent); + } + + //Redundant parents (no candidates) + EINA_LIST_FOREACH_SAFE(_candidates, l, l_next, obj_event) + { + if (!obj_event->parent) continue; + _candidates = eina_list_remove_list(_candidates, l); + } + + *candidates = _candidates; + return parent; +} + +static Ea_Object_Event * +_ea_find_event_target(Eina_List *candidates, Evas_Object *parent) +{ + Ea_Object_Event *obj_event = NULL; + Eina_List *l; + Evas_Object *obj; + Eina_List *members = evas_object_smart_members_get(parent); + if (members) + { + EINA_LIST_REVERSE_FOREACH(members, l, obj) + { + obj_event = _ea_find_event_target(candidates, obj); + //got you! + if (obj_event) + { + eina_list_free(members); + return obj_event; + } + } + eina_list_free(members); + } + + EINA_LIST_REVERSE_FOREACH(candidates, l, obj_event) + { + //got you! + if (parent == obj_event->obj) return obj_event; + } + + return NULL; +} + +static Ea_Object_Event * +_ea_top_obj_event_find(Ea_Event_Mgr *event_mgr) +{ + Ea_Object_Event *obj_event = NULL; + Eina_List *l, *l_next; + Eina_List *candidates = NULL; + Evas_Object *parent; + int top_layer; + Eina_Bool invisible; + + //1. filter the invisible objs + EINA_LIST_FOREACH(event_mgr->obj_events, l, obj_event) + { + parent = obj_event->obj; + invisible = EINA_FALSE; + + while (parent) + { + if (!evas_object_visible_get(parent)) + { + invisible = EINA_TRUE; + break; + } + parent = evas_object_smart_parent_get(parent); + } + if (invisible) continue; + candidates = eina_list_append(candidates, obj_event); + } + if (!candidates) return NULL; //no visible objects. + if (eina_list_count(candidates) == 1) goto found; + + //2.1. sort by layer order + candidates = eina_list_sort(candidates, eina_list_count(candidates), + _ea_layer_sort_cb); + + //2.2. leave the only top layer + obj_event = eina_list_data_get(eina_list_last(candidates)); + top_layer = evas_object_layer_get(obj_event->obj); + + EINA_LIST_FOREACH_SAFE(candidates, l, l_next, obj_event) + { + if (evas_object_layer_get(obj_event->obj) < top_layer) + candidates = eina_list_remove_list(candidates, l); + } + if (eina_list_count(candidates) == 1) goto found; + + //3. find the top parent candidate. + parent = _ea_top_parent_candidates(&candidates, event_mgr->e); + if (eina_list_count(candidates) == 1) goto found; + + //4. find the target in this parent tree. + return _ea_find_event_target(candidates, parent); + +found: + obj_event = eina_list_data_get(candidates); + eina_list_free(candidates); + return obj_event; +} + +static void +_ea_key_grab_rect_key_up_cb(void *data, Evas *e, Evas_Object *obj, + void *event_info) +{ + Evas_Event_Key_Down *ev = event_info; + Ea_Event_Mgr *event_mgr = data; + Ea_Object_Event *obj_event; + Ea_Event_Callback *callback; + Ea_Callback_Type type; + Eina_List *l; + + obj_event = _ea_top_obj_event_find(event_mgr); + if (!obj_event) return; + + if (!strcmp(ev->keyname, EA_KEY_BACK) || !strcmp(ev->keyname, EA_KEY_BACK2)) + type = EA_CALLBACK_BACK; + else if (!strcmp(ev->keyname, EA_KEY_SEND)) + type = EA_CALLBACK_MORE; + + EINA_LIST_FOREACH(obj_event->callbacks, l, callback) + { + if (callback->type != type) continue; + callback->func(callback->data, obj_event->obj, (void*) type); + } +} + +static void +_ea_key_grab_obj_create(Ea_Event_Mgr *event_mgr) +{ + Evas_Object *key_grab_rect = evas_object_rectangle_add(event_mgr->e); + + evas_object_event_callback_add(key_grab_rect, EVAS_CALLBACK_KEY_UP, + _ea_key_grab_rect_key_up_cb, event_mgr); + if (!evas_object_key_grab(key_grab_rect, EA_KEY_BACK, 0, 0, EINA_FALSE)) + CRITICAL("Failed to grab END KEY\n"); + + if (!evas_object_key_grab(key_grab_rect, EA_KEY_BACK2, 0, 0, EINA_FALSE)) + CRITICAL("Failed to grab END KEY\n"); + + if (!evas_object_key_grab(key_grab_rect, EA_KEY_SEND, 0, 0, EINA_FALSE)) + CRITICAL("Failed to grab MORE KEY\n"); + event_mgr->key_grab_rect = key_grab_rect; +} + +static Ea_Event_Mgr * +_ea_event_mgr_new(Evas *e) +{ + Ea_Event_Mgr *event_mgr = calloc(1, sizeof(Ea_Event_Mgr)); + if (!event_mgr) + { + ERR("Failed to allocate event manager"); + return NULL; + } + event_mgr->e = e; + _ea_key_grab_obj_create(event_mgr); + + return event_mgr; +} + +void +ea_event_mgr_clear(Ea_Event_Mgr *event_mgr) +{ + Ea_Object_Event *obj_event; + Ea_Event_Callback *callback; + Eina_List *l, *l2; + + //Remove Object Events + EINA_LIST_FOREACH(event_mgr->obj_events, l, obj_event) + { + evas_object_event_callback_del(obj_event->obj, EVAS_CALLBACK_DEL, + _ea_object_del_cb); + //Remove Callbacks + EINA_LIST_FOREACH(obj_event->callbacks, l2, callback) + free(callback); + obj_event->callbacks = eina_list_free(obj_event->callbacks); + + free(obj_event); + } + event_mgr->obj_events = eina_list_free(event_mgr->obj_events); + + evas_object_del(event_mgr->key_grab_rect); + + free(event_mgr); +} + +EAPI void * +ea_object_event_callback_del(Evas_Object *obj, Ea_Callback_Type type, Ea_Event_Cb func) +{ + Ea_Object_Event *obj_event; + Ea_Event_Mgr *event_mgr; + Eina_List *l; + Ea_Event_Callback *callback; + void *data; + + //Check the validation + event_mgr = evas_object_data_get(obj, EA_OBJ_KEY_EVENT_MGR); + obj_event = evas_object_data_get(obj, EA_OBJ_KEY_OBJ_EVENT); + + if (!event_mgr || !obj_event) + { + WRN("This object(%p) hasn't been registered before", obj); + return NULL; + } + + evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _ea_object_del_cb); + + //Remove the callback data + EINA_LIST_REVERSE_FOREACH(obj_event->callbacks, l, callback) + { + if ((callback->func == func) && (callback->type == type)) break; + } + + data = callback->data; + obj_event->callbacks = eina_list_remove_list(obj_event->callbacks, l); + free(callback); + + //This object is not managed anymore. + if (!obj_event->callbacks) + { + evas_object_data_set(obj, EA_OBJ_KEY_OBJ_EVENT, NULL); + evas_object_data_set(obj, EA_OBJ_KEY_EVENT_MGR, NULL); + } + + _ea_event_mgr_del(event_mgr); + + return data; +} + +EAPI void +ea_object_event_callback_add(Evas_Object *obj, Ea_Callback_Type type, Ea_Event_Cb func, void *data) +{ + Ea_Event_Mgr *event_mgr; + Evas *e; + Ea_Object_Event *obj_event = NULL; + Eina_List *l; + Ea_Event_Callback *callback; + Eina_Bool new_event_mgr = EINA_TRUE; + + //Check the registered event manager for this Evas. + e = evas_object_evas_get(obj); + + EINA_LIST_FOREACH(_ea.event_mgrs, l, event_mgr) + { + if (event_mgr->e == e) + { + new_event_mgr = EINA_FALSE; + break; + } + } + + //New Evas comes. Create new event manager for this Evas. + if (new_event_mgr) + { + if (!(event_mgr = _ea_event_mgr_new(e))) return; + _ea.event_mgrs = eina_list_append(_ea.event_mgrs, event_mgr); + } + + obj_event = evas_object_data_get(obj, EA_OBJ_KEY_OBJ_EVENT); + + //New Object Event. Probably user adds ea_object_event_callback first time. + if (!obj_event) + { + obj_event = calloc(1, sizeof(Ea_Object_Event)); + if (!obj_event) + { + ERR("Failed to allocate object event"); + return; + } + evas_object_data_set(obj, EA_OBJ_KEY_OBJ_EVENT, obj_event); + evas_object_data_set(obj, EA_OBJ_KEY_EVENT_MGR, event_mgr); + evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, + _ea_object_del_cb, + obj_event); + event_mgr->obj_events = eina_list_append(event_mgr->obj_events, + obj_event); + obj_event->obj = obj; + } + + //Append this callback. + callback = calloc(1, sizeof(Ea_Event_Callback)); + if (!callback) + { + ERR("Failed to allocate event callback"); + return; + } + callback->type = type; + callback->func = func; + callback->data = data; + + obj_event->callbacks = eina_list_append(obj_event->callbacks, callback); +} -- 2.7.4