--- /dev/null
+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)
--- /dev/null
+INSTALL(
+ DIRECTORY ./ DESTINATION include/${LIB_NAME}
+ FILES_MATCHING
+ PATTERN "*_private.h" EXCLUDE
+ PATTERN "*.h"
+ )
--- /dev/null
+/*
+ * 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__ */
+
--- /dev/null
+/*
+ * 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 <Elementary.h>
+#include <stdbool.h>
+#ifndef DESKTOP
+ #include <tizen.h>
+#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__ */
--- /dev/null
+/*
+ * 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 <Elementary.h>
+
+#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;
+
+/** <Ea event callback function signature */
+typedef void (*Ea_Event_Cb)(void *data, Evas_Object *obj, void *event_info);
+
+/**
+ * Delete a callback function from an object.
+ *
+ * @param[in] obj Object to remove a callback from.
+ * @param[in] type The type of event that was triggering the callback.
+ * @param[in] func The function that was to be called when the event was
+ * triggered
+ * @return data The data pointer that was to be passed to the callback.
+ *
+ * @brief This function removes the most recently added callback from the
+ * object @p obj which was triggered by the type @p type and
+ * was calling the function @p func when triggered. If the removal is
+ * successful it will also return the data pointer that was passed to
+ * ea_object_event_callback_add() when the callback was added to
+ * the object. If not successful @c NULl will be returned.
+ *
+ * @see ea_object_event_callback_add()
+ */
+
+EAPI void *ea_object_event_callback_del(Evas_Object *obj, Ea_Callback_Type type, Ea_Event_Cb);
+
+/**
+ * Add (register) a callback function to a given evas object.
+ *
+ * @param[in] obj evas object.
+ * @param[in] type The type of event that will trigger the callback.
+ * @param[in] func The function to be called when the key event is triggered.
+ * @param[in] data The data pointer to be passed to @p func.
+ *
+ * @brief This function adds a function callback to an object when the key event
+ * occurs on object @p obj. The key event on the object is only triggered
+ * when the object is the most top in objects stack and visible. This
+ * means, like the naviframe widget, if your application needs to have
+ * the events based on the view but not focus, you can use this callback.
+ *
+ * A callback function must have the Ea_Event_Cb prototype definition.
+ * The first parameter (@p data) in this definition will have the same
+ * value passed to ea_object_event_callback_add() as the @p data
+ * parameter, at runtime. The second parameter @p obj is the evas object
+ * on which event occurred. Finally, the third parameter @p event_info is
+ * a pointer to a data structure that may or may not be passed to the
+ * callback, depending on the event type that triggered the callback.
+ * This is so because some events don't carry extra context with them,
+ * but others do.
+ *
+ * @see ea_object_event_callback_del()
+ */
+
+EAPI void ea_object_event_callback_add(Evas_Object *obj, Ea_Callback_Type type, Ea_Event_Cb func, void *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __EFL_ASSIST_EVENTS_H__ */
--- /dev/null
+/*
+ * 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_PRIVATE_H__
+#define __EFL_ASSIST_PRIVATE_H__
+
+#include <syslog.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+#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__ */
--- /dev/null
+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)
+
--- /dev/null
+/*
+ * 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 "<UNKNOWN>";
+ }
+}
+
+__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 *
+ *===========================================================================*/
+
--- /dev/null
+#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;
+}
--- /dev/null
+#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);
+}