Repository layout adjusted and manifest added
[platform/core/uifw/eail.git] / eail / eail.c
1 /*
2  * Copyright (c) 2013 Samsung Electronics Co., Ltd.
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 /**
21  * @file eail.c
22  * @brief EAIL initialization
23  */
24
25 #include <Elementary.h>
26
27 #include <gmodule.h>
28 #include <atk-bridge.h>
29 #include "eail.h"
30 #include "eail_app.h"
31 #include "eail_priv.h"
32 #include "eail_clipboard.h"
33
34 /** @brief Struct definition for listener info*/
35 typedef struct _EailUtilListenerInfo EailUtilListenerInfo;
36 /** @brief Struct definition for event info*/
37 typedef struct _EailKeyEventInfo EailKeyEventInfo;
38
39 /** @brief Struct definition for listener info*/
40 struct _EailUtilListenerInfo
41 {
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*/
45 };
46
47 /** @brief Struct definition for event info*/
48 struct _EailKeyEventInfo
49 {
50   AtkKeyEventStruct *key_event;/**< @brief key of event */
51   gpointer func_data;/**< @brief additional data passed to the event */
52 };
53
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;
58
59 /**
60  * @brief Domain index that will be used as the DOMAIN parameter on EINA log macros
61  *
62  * A negative value means a log occurred.
63  */
64 int _eail_log_dom = -1;
65
66 /**
67  * @brief A variable for tracking the last focused AtkObject
68  */
69 static AtkObject *eail_atk_last_focused_obj = NULL;
70
71 /**
72  * @brief Gets the name of the toolkit
73  * @return string representing the name of the toolkit
74  */
75 static const gchar * eail_get_toolkit_name(void)
76 {
77    return "elementary";
78 }
79
80 /**
81  * @brief Gets the version of the toolkit
82  *
83  * @return string representing the version of the toolkit
84  */
85 static const gchar * eail_get_toolkit_version(void)
86 {
87    return g_strdup_printf("%i.%i.%i", elm_version->major,
88                           elm_version->minor,
89                           elm_version->micro);
90 }
91
92 /**
93  * @brief Gets the accessible root container for the current application
94  *
95  * @return AtkObject representing the accessible root container
96  */
97 static AtkObject * eail_get_root(void)
98 {
99    static AtkObject *root = NULL;
100
101    if (!root)
102      {
103         root = g_object_new(EAIL_TYPE_APP, NULL);
104         atk_object_initialize(root, NULL);
105    }
106
107    return root;
108 }
109
110 /**
111  * @brief Callback to be called when an object receives focus
112  *
113  * @param current_focused_obj AtkObject instance
114  */
115 static void
116 eail_focus_listener_cb(AtkObject *current_focused_obj)
117 {
118    if (current_focused_obj == eail_atk_last_focused_obj)
119      return;
120
121    if (eail_atk_last_focused_obj)
122      {
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);
126      }
127
128    g_object_ref(current_focused_obj);
129
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;
133 }
134
135 /**
136  * @brief Initializes object focus tracking
137  */
138 static void
139 eail_app_focus_listener_init()
140 {
141    atk_add_focus_tracker(eail_focus_listener_cb);
142 }
143
144 /**
145  * @brief Creates and adds a listener for the given object type
146  *
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
152  *
153  * @returns integer representing the id of the newly added listener
154  */
155 static guint
156 add_listener (GSignalEmissionHook listener,
157               const gchar         *object_type,
158               const gchar         *signal,
159               const gchar         *hook_data)
160 {
161   GType type;
162   guint signal_id;
163   gint  rc = 0;
164
165   type = g_type_from_name (object_type);
166   if (type)
167     {
168       signal_id  = g_signal_lookup (signal, type);
169       if (signal_id > 0)
170         {
171           EailUtilListenerInfo *listener_info;
172
173           rc = listener_idx;
174
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;
182
183           g_hash_table_insert(listener_list, &(listener_info->key), listener_info);
184           listener_idx++;
185         }
186       else
187         {
188            DBG("Invalid signal type %s\n", signal);
189         }
190     }
191   else
192     {
193        DBG("Invalid object type %s\n", object_type);
194     }
195   return rc;
196 }
197
198 /**
199  * @brief Removes a listener for given object type
200  *
201  * @param remove_listener id of the listener to remove
202  */
203 static void
204 eail_remove_global_event_listener (guint remove_listener)
205 {
206   if (remove_listener > 0)
207   {
208     EailUtilListenerInfo *listener_info;
209     gint tmp_idx = remove_listener;
210
211     listener_info = (EailUtilListenerInfo *)
212                                  g_hash_table_lookup(listener_list, &tmp_idx);
213
214     if (listener_info != NULL)
215       {
216         /* Hook id of 0 and signal id of 0 are invalid */
217         if (listener_info->hook_id != 0 && listener_info->signal_id != 0)
218           {
219             /* Remove the emission hook */
220             g_signal_remove_emission_hook(listener_info->signal_id,
221                                                 listener_info->hook_id);
222
223             /* Remove the element from the hash */
224             g_hash_table_remove(listener_list, &tmp_idx);
225           }
226         else
227           {
228              DBG("Invalid listener hook_id %ld or signal_id %d\n",
229                             listener_info->hook_id, listener_info->signal_id);
230           }
231       }
232     else
233       {
234          DBG("No listener with the specified listener id %d", remove_listener);
235       }
236   }
237   else
238   {
239      DBG("Invalid listener_id %d", remove_listener);
240   }
241 }
242
243 /**
244  * @brief Initialization for global event listener
245  *
246  * @param listener GSignalEmissionHook (GObject 'signal invocation hint')
247  * @param event_type string representing the event's type
248  *
249  * @return integer representing the id of the added listener
250  */
251 static guint
252 eail_add_global_event_listener(GSignalEmissionHook listener,
253                                const gchar *event_type)
254 {
255    guint rc = 0;
256    gchar **split_string;
257
258    split_string = g_strsplit(event_type, ":", 3);
259
260    if (split_string)
261      {
262        if (!strcmp("window", split_string[0]))
263          rc = add_listener /* window event handling */
264                        (listener, "AtkWindow", split_string[1], event_type);
265        else
266          rc = add_listener /* regular event handling */
267                     (listener, split_string[1], split_string[2], event_type);
268
269        g_strfreev(split_string);
270      }
271
272    return rc;
273 }
274
275 /**
276  * @brief Destructor for listener info object
277  *
278  * @param data data to be freed
279  */
280 static void
281 eail_listener_info_destroy(gpointer data)
282 {
283    g_free(data);
284 }
285
286 /**
287  * @brief AtkUtil class initialization
288  */
289 static void atk_util_install(void)
290 {
291    AtkUtilClass *uclass;
292
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;
297
298    eail_app_focus_listener_init();
299
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;
304 }
305
306 /**
307  * @brief Function to be executed by Elementary when EAIL module is loaded
308  *
309  * @param m Elm_Module data
310  * @return 1 on success, 0 otherwise
311  */
312 int
313 elm_modapi_init(void *m)
314 {
315    static gboolean initialized = FALSE;
316    if (initialized) return 1;
317
318    _eail_log_dom = eina_log_domain_register("eail", EAIL_LOG_COLOR);
319    if (!_eail_log_dom)
320      {
321         EINA_LOG_ERR("could not register eail log domain.");
322         _eail_log_dom = EINA_LOG_DOMAIN_GLOBAL;
323      }
324
325    if (!ecore_main_loop_glib_integrate())
326      {
327         ERR("Cannot integrate with glib main loop");
328         return 0;
329      }
330
331    initialized = TRUE;
332
333    g_type_init();
334
335    listener_list = g_hash_table_new_full
336                   (g_int_hash, g_int_equal, NULL, eail_listener_info_destroy);
337
338    atk_util_install();
339
340    atk_misc_instance = g_object_new(ATK_TYPE_MISC, NULL);
341
342    atk_bridge_adaptor_init(NULL, NULL);
343
344    return 1;
345 }
346
347 /**
348  * @brief Function to be executed by Elementary when EAIL module is unloaded
349  *
350  * @param m Elm_Module data
351  * @return always 1 - notifying success
352  */
353 int
354 elm_modapi_shutdown(void *m)
355 {
356    eail_clipboard_free();
357
358    if ((_eail_log_dom > -1) && (_eail_log_dom != EINA_LOG_DOMAIN_GLOBAL))
359      {
360         eina_log_domain_unregister(_eail_log_dom);
361         _eail_log_dom = -1;
362      }
363    /*always succeed*/
364    return 1;
365 }
366