2 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
22 * @brief EAIL initialization
25 #include <Elementary.h>
28 #include <atk-bridge.h>
31 #include "eail_priv.h"
32 #include "eail_clipboard.h"
34 /** @brief Struct definition for listener info*/
35 typedef struct _EailUtilListenerInfo EailUtilListenerInfo;
36 /** @brief Struct definition for event info*/
37 typedef struct _EailKeyEventInfo EailKeyEventInfo;
39 /** @brief Struct definition for listener info*/
40 struct _EailUtilListenerInfo
42 gint key; /**< @brief key of entry */
43 guint signal_id;/**< @brief id of the signal */
44 gulong hook_id;/**< @brief emit hook value returned on signal registration*/
47 /** @brief Struct definition for event info*/
48 struct _EailKeyEventInfo
50 AtkKeyEventStruct *key_event;/**< @brief key of event */
51 gpointer func_data;/**< @brief additional data passed to the event */
54 /** @brief Cache of objects used for listening and propagating signals */
55 static GHashTable *listener_list = NULL;
56 /** @brief Last added id of a listener */
57 static gint listener_idx = 1;
60 * @brief Domain index that will be used as the DOMAIN parameter on EINA log macros
62 * A negative value means a log occurred.
64 int _eail_log_dom = -1;
67 * @brief A variable for tracking the last focused AtkObject
69 static AtkObject *eail_atk_last_focused_obj = NULL;
72 * @brief Gets the name of the toolkit
73 * @return string representing the name of the toolkit
75 static const gchar * eail_get_toolkit_name(void)
81 * @brief Gets the version of the toolkit
83 * @return string representing the version of the toolkit
85 static const gchar * eail_get_toolkit_version(void)
87 return g_strdup_printf("%i.%i.%i", elm_version->major,
93 * @brief Gets the accessible root container for the current application
95 * @return AtkObject representing the accessible root container
97 static AtkObject * eail_get_root(void)
99 static AtkObject *root = NULL;
103 root = g_object_new(EAIL_TYPE_APP, NULL);
104 atk_object_initialize(root, NULL);
111 * @brief Callback to be called when an object receives focus
113 * @param current_focused_obj AtkObject instance
116 eail_focus_listener_cb(AtkObject *current_focused_obj)
118 if (current_focused_obj == eail_atk_last_focused_obj)
121 if (eail_atk_last_focused_obj)
123 atk_object_notify_state_change
124 (eail_atk_last_focused_obj, ATK_STATE_FOCUSED, FALSE);
125 g_object_unref(eail_atk_last_focused_obj);
128 g_object_ref(current_focused_obj);
130 /* already notifying about focus in widget implementation so do not need
131 * to notify here for new focus*/
132 eail_atk_last_focused_obj = current_focused_obj;
136 * @brief Initializes object focus tracking
139 eail_app_focus_listener_init()
141 atk_add_focus_tracker(eail_focus_listener_cb);
145 * @brief Creates and adds a listener for the given object type
147 * @param listener GObject Emission Hook (a simple function pointer to get
148 * invoked when the signal is emitted)
149 * @param object_type name string representing object's type
150 * @param signal name string representing the signal to listen
151 * @param hook_data GObject 'hook' info
153 * @returns integer representing the id of the newly added listener
156 add_listener (GSignalEmissionHook listener,
157 const gchar *object_type,
159 const gchar *hook_data)
165 type = g_type_from_name (object_type);
168 signal_id = g_signal_lookup (signal, type);
171 EailUtilListenerInfo *listener_info;
175 listener_info = g_malloc(sizeof(EailUtilListenerInfo));
176 listener_info->key = listener_idx;
177 listener_info->hook_id =
178 g_signal_add_emission_hook (signal_id, 0, listener,
179 g_strdup (hook_data),
180 (GDestroyNotify) g_free);
181 listener_info->signal_id = signal_id;
183 g_hash_table_insert(listener_list, &(listener_info->key), listener_info);
188 DBG("Invalid signal type %s\n", signal);
193 DBG("Invalid object type %s\n", object_type);
199 * @brief Removes a listener for given object type
201 * @param remove_listener id of the listener to remove
204 eail_remove_global_event_listener (guint remove_listener)
206 if (remove_listener > 0)
208 EailUtilListenerInfo *listener_info;
209 gint tmp_idx = remove_listener;
211 listener_info = (EailUtilListenerInfo *)
212 g_hash_table_lookup(listener_list, &tmp_idx);
214 if (listener_info != NULL)
216 /* Hook id of 0 and signal id of 0 are invalid */
217 if (listener_info->hook_id != 0 && listener_info->signal_id != 0)
219 /* Remove the emission hook */
220 g_signal_remove_emission_hook(listener_info->signal_id,
221 listener_info->hook_id);
223 /* Remove the element from the hash */
224 g_hash_table_remove(listener_list, &tmp_idx);
228 DBG("Invalid listener hook_id %ld or signal_id %d\n",
229 listener_info->hook_id, listener_info->signal_id);
234 DBG("No listener with the specified listener id %d", remove_listener);
239 DBG("Invalid listener_id %d", remove_listener);
244 * @brief Initialization for global event listener
246 * @param listener GSignalEmissionHook (GObject 'signal invocation hint')
247 * @param event_type string representing the event's type
249 * @return integer representing the id of the added listener
252 eail_add_global_event_listener(GSignalEmissionHook listener,
253 const gchar *event_type)
256 gchar **split_string;
258 split_string = g_strsplit(event_type, ":", 3);
262 if (!strcmp("window", split_string[0]))
263 rc = add_listener /* window event handling */
264 (listener, "AtkWindow", split_string[1], event_type);
266 rc = add_listener /* regular event handling */
267 (listener, split_string[1], split_string[2], event_type);
269 g_strfreev(split_string);
276 * @brief Destructor for listener info object
278 * @param data data to be freed
281 eail_listener_info_destroy(gpointer data)
287 * @brief AtkUtil class initialization
289 static void atk_util_install(void)
291 AtkUtilClass *uclass;
293 uclass = ATK_UTIL_CLASS(g_type_class_ref(ATK_TYPE_UTIL));
294 uclass->get_toolkit_name = eail_get_toolkit_name;
295 uclass->get_toolkit_version = eail_get_toolkit_version;
296 uclass->get_root = eail_get_root;
298 eail_app_focus_listener_init();
300 uclass->add_global_event_listener = eail_add_global_event_listener;
301 uclass->remove_global_event_listener = eail_remove_global_event_listener;
302 uclass->add_key_event_listener = NULL;
303 uclass->remove_key_event_listener = NULL;
307 * @brief Function to be executed by Elementary when EAIL module is loaded
309 * @param m Elm_Module data
310 * @return 1 on success, 0 otherwise
313 elm_modapi_init(void *m)
315 static gboolean initialized = FALSE;
316 if (initialized) return 1;
318 _eail_log_dom = eina_log_domain_register("eail", EAIL_LOG_COLOR);
321 EINA_LOG_ERR("could not register eail log domain.");
322 _eail_log_dom = EINA_LOG_DOMAIN_GLOBAL;
325 if (!ecore_main_loop_glib_integrate())
327 ERR("Cannot integrate with glib main loop");
335 listener_list = g_hash_table_new_full
336 (g_int_hash, g_int_equal, NULL, eail_listener_info_destroy);
340 atk_misc_instance = g_object_new(ATK_TYPE_MISC, NULL);
342 atk_bridge_adaptor_init(NULL, NULL);
348 * @brief Function to be executed by Elementary when EAIL module is unloaded
350 * @param m Elm_Module data
351 * @return always 1 - notifying success
354 elm_modapi_shutdown(void *m)
356 eail_clipboard_free();
358 if ((_eail_log_dom > -1) && (_eail_log_dom != EINA_LOG_DOMAIN_GLOBAL))
360 eina_log_domain_unregister(_eail_log_dom);