Add description of apache license to source files
[platform/core/uifw/efl-assist.git] / src / lib / efl_assist_events.c
1 /*
2  * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  *
16  */
17
18
19 #include "efl_assist.h"
20 #include "efl_assist_private.h"
21
22 typedef struct _Ea_Event_Mgr Ea_Event_Mgr;
23
24 struct _Ea_Event_Mgr
25 {
26    Eina_List *obj_events;
27    Evas *e;
28    Evas_Object *key_grab_rect;
29 };
30
31 typedef struct _Ea_Object_Event
32 {
33    Evas_Object *obj;
34    Evas_Object *parent;
35    Eina_List *callbacks;
36    Eina_Bool delete_me : 1;
37    Eina_Bool on_callback : 1;
38 } Ea_Object_Event;
39
40 typedef struct _Ea_Event_Callback
41 {
42    Ea_Callback_Type type;
43    void (*func)(void *data, Evas_Object *obj, void *event_info);
44    void *data;
45 } Ea_Event_Callback;
46
47 const char *EA_OBJ_KEY_EVENT_MGR = "_ea_obj_key_event_mgr";
48 const char *EA_OBJ_KEY_OBJ_EVENT = "_ea_obj_key_obj_event";
49 const char *EA_KEY_STOP = "XF86Stop";
50 const char *EA_KEY_STOP2 = "Escape";
51 const char *EA_KEY_SEND = "XF86Send";
52 const char *EA_KEY_SEND2 = "Menu";
53
54
55 static Eina_List *event_mgrs = NULL;
56
57 static void
58 _ea_event_mgr_del(Ea_Event_Mgr *event_mgr)
59 {
60    if (event_mgr->obj_events) return;
61
62    //Redundant Event Mgr. Remove it.
63    evas_object_del(event_mgr->key_grab_rect);
64    event_mgrs = eina_list_remove(event_mgrs, event_mgr);
65    free(event_mgr);
66 }
67
68 static void
69 _ea_object_del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
70 {
71    Ea_Event_Mgr *event_mgr = evas_object_data_get(obj, EA_OBJ_KEY_EVENT_MGR);
72    Ea_Object_Event *obj_event = data;
73    Eina_List *l;
74    Ea_Event_Callback *callback;
75
76    l = eina_list_data_find_list(event_mgr->obj_events, obj_event);
77    if (!l) return;
78
79    event_mgr->obj_events = eina_list_remove_list(event_mgr->obj_events, l);
80
81    EINA_LIST_FOREACH(obj_event->callbacks, l, callback)
82       free(callback);
83    obj_event->callbacks = eina_list_free(obj_event->callbacks);
84
85    if (obj_event->on_callback) obj_event->delete_me = EINA_TRUE;
86    else free(obj_event);
87
88    _ea_event_mgr_del(event_mgr);
89 }
90
91 static int
92 _ea_layer_sort_cb(const void *data1, const void *data2)
93 {
94    const Ea_Object_Event *obj_event = data1;
95    const Ea_Object_Event *obj_event2 = data2;
96
97    //1. Layer Compare
98    int layer1 = evas_object_layer_get(obj_event->obj);
99    int layer2 = evas_object_layer_get(obj_event2->obj);
100
101    return (layer1 < layer2) ? -1 : 1;
102 }
103
104 static Evas_Object *
105 _ea_top_parent_candidates(Eina_List **candidates, Evas *e)
106 {
107    Evas_Object *temp;
108    Evas_Object *parent;
109    Eina_List *l, *l_next;
110    Ea_Object_Event *obj_event;
111    Eina_List *_candidates = *candidates;
112    Eina_Bool found = EINA_FALSE;
113
114    //Get the top parent lists
115    EINA_LIST_FOREACH(_candidates, l, obj_event)
116      {
117         temp = obj_event->obj;
118         parent = obj_event->obj;
119         while (temp)
120           {
121              parent = temp;
122              temp = evas_object_smart_parent_get(temp);
123           }
124         obj_event->parent = parent;
125      }
126
127    //Leave only parent candidates.
128    parent = evas_object_top_get(e);
129
130    while (parent)
131      {
132         EINA_LIST_FOREACH(_candidates, l, obj_event)
133           {
134              if (parent == obj_event->parent)
135                {
136                   found = EINA_TRUE;
137                   obj_event->parent = NULL;
138                }
139           }
140         if (found) break;
141         parent = evas_object_below_get(parent);
142      }
143
144    //Redundant parents (no candidates)
145    EINA_LIST_FOREACH_SAFE(_candidates, l, l_next, obj_event)
146      {
147         if (!obj_event->parent) continue;
148         _candidates = eina_list_remove_list(_candidates, l);
149      }
150
151    *candidates = _candidates;
152    return parent;
153 }
154
155 static Ea_Object_Event *
156 _ea_find_event_target(Eina_List *candidates, Evas_Object *parent)
157 {
158    Ea_Object_Event *obj_event = NULL;
159    Eina_List *l;
160    Evas_Object *obj;
161    Eina_List *members = evas_object_smart_members_get(parent);
162    if (members)
163      {
164         EINA_LIST_REVERSE_FOREACH(members, l, obj)
165           {
166              obj_event = _ea_find_event_target(candidates, obj);
167              //got you!
168              if (obj_event)
169                {
170                   eina_list_free(members);
171                   return obj_event;
172                }
173           }
174         eina_list_free(members);
175      }
176
177    EINA_LIST_REVERSE_FOREACH(candidates, l, obj_event)
178      {
179         //got you!
180         if (parent == obj_event->obj) return obj_event;
181      }
182
183    return NULL;
184 }
185
186 static Ea_Object_Event *
187 _ea_top_obj_event_find(Ea_Event_Mgr *event_mgr)
188 {
189    Ea_Object_Event *obj_event = NULL;
190    Eina_List *l, *l_next;
191    Eina_List *candidates = NULL;
192    Evas_Object *parent;
193    int top_layer;
194    Eina_Bool invisible;
195
196    //1. filter the invisible objs
197    EINA_LIST_FOREACH(event_mgr->obj_events, l, obj_event)
198      {
199         parent = obj_event->obj;
200         invisible = EINA_FALSE;
201
202         while (parent)
203           {
204              if (!evas_object_visible_get(parent))
205                {
206                   invisible = EINA_TRUE;
207                   break;
208                }
209              parent = evas_object_smart_parent_get(parent);
210           }
211         if (invisible) continue;
212         candidates = eina_list_append(candidates, obj_event);
213      }
214    if (!candidates) return NULL;   //no visible objects.
215    if (eina_list_count(candidates) == 1) goto found;
216
217    //2.1. sort by layer order
218    candidates = eina_list_sort(candidates, eina_list_count(candidates),
219                                _ea_layer_sort_cb);
220
221    //2.2. leave the only top layer
222    obj_event = eina_list_data_get(eina_list_last(candidates));
223    top_layer = evas_object_layer_get(obj_event->obj);
224
225    EINA_LIST_FOREACH_SAFE(candidates, l, l_next, obj_event)
226      {
227         if (evas_object_layer_get(obj_event->obj) < top_layer)
228           candidates = eina_list_remove_list(candidates, l);
229      }
230    if (eina_list_count(candidates) == 1) goto found;
231
232    //3. find the top parent candidate.
233    parent = _ea_top_parent_candidates(&candidates, event_mgr->e);
234    if (eina_list_count(candidates) == 1) goto found;
235
236    //4. find the target in this parent tree.
237    return _ea_find_event_target(candidates, parent);
238
239 found:
240    obj_event = eina_list_data_get(candidates);
241    eina_list_free(candidates);
242    return obj_event;
243 }
244
245 static void
246 _ea_key_grab_rect_key_up_cb(void *data, Evas *e, Evas_Object *obj,
247                             void *event_info)
248 {
249    Evas_Event_Key_Down *ev = event_info;
250    Ea_Event_Mgr *event_mgr = data;
251    Ea_Object_Event *obj_event;
252    Ea_Event_Callback *callback;
253    Ea_Callback_Type type;
254    Eina_List *l;
255
256    obj_event = _ea_top_obj_event_find(event_mgr);
257    if (!obj_event) return;
258
259    if (!strcmp(ev->keyname, EA_KEY_STOP) || !strcmp(ev->keyname, EA_KEY_STOP2))
260      type = EA_CALLBACK_BACK;
261    else if (!strcmp(ev->keyname, EA_KEY_SEND) ||
262             !strcmp(ev->keyname, EA_KEY_SEND2))
263      type = EA_CALLBACK_MORE;
264    else return;
265
266    obj_event->on_callback = EINA_TRUE;
267    EINA_LIST_FOREACH(obj_event->callbacks, l, callback)
268      {
269         if (obj_event->delete_me) break;
270         if (callback->type != type) continue;
271         callback->func(callback->data, obj_event->obj, (void*) type);
272      }
273    if (obj_event->delete_me) free(obj_event);
274    else obj_event->on_callback = EINA_FALSE;
275 }
276
277 static void
278 _ea_key_grab_obj_create(Ea_Event_Mgr *event_mgr)
279 {
280    Evas_Object *key_grab_rect = evas_object_rectangle_add(event_mgr->e);
281
282    evas_object_event_callback_add(key_grab_rect, EVAS_CALLBACK_KEY_UP,
283                                   _ea_key_grab_rect_key_up_cb, event_mgr);
284    if (!evas_object_key_grab(key_grab_rect, EA_KEY_STOP, 0, 0, EINA_FALSE))
285      LOGE("Failed to grab END KEY\n");
286
287    if (!evas_object_key_grab(key_grab_rect, EA_KEY_STOP2, 0, 0, EINA_FALSE))
288      LOGE("Failed to grab END KEY\n");
289
290    if (!evas_object_key_grab(key_grab_rect, EA_KEY_SEND, 0, 0, EINA_FALSE))
291      LOGE("Failed to grab MORE KEY\n");
292
293    if (!evas_object_key_grab(key_grab_rect, EA_KEY_SEND2, 0, 0, EINA_FALSE))
294      LOGE("Failed to grab MORE KEY\n");
295
296    event_mgr->key_grab_rect = key_grab_rect;
297 }
298
299 static Ea_Event_Mgr *
300 _ea_event_mgr_new(Evas *e)
301 {
302    Ea_Event_Mgr *event_mgr = calloc(1, sizeof(Ea_Event_Mgr));
303    if (!event_mgr)
304      {
305         LOGE("Failed to allocate event manager");
306         return NULL;
307      }
308    event_mgr->e = e;
309    _ea_key_grab_obj_create(event_mgr);
310
311    return event_mgr;
312 }
313
314 EAPI void *
315 ea_object_event_callback_del(Evas_Object *obj, Ea_Callback_Type type, Ea_Event_Cb func)
316 {
317    Ea_Object_Event *obj_event;
318    Ea_Event_Mgr *event_mgr;
319    Eina_List *l;
320    Ea_Event_Callback *callback;
321    void *data;
322
323    //Check the validation
324    event_mgr = evas_object_data_get(obj, EA_OBJ_KEY_EVENT_MGR);
325    obj_event = evas_object_data_get(obj, EA_OBJ_KEY_OBJ_EVENT);
326
327    if (!event_mgr || !obj_event)
328      {
329         LOGW("This object(%p) hasn't been registered before", obj);
330         return NULL;
331      }
332
333    evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _ea_object_del_cb);
334
335    //Remove the callback data
336    EINA_LIST_REVERSE_FOREACH(obj_event->callbacks, l, callback)
337      {
338         if ((callback->func == func) && (callback->type == type)) break;
339      }
340
341    data = callback->data;
342    obj_event->callbacks = eina_list_remove_list(obj_event->callbacks, l);
343    free(callback);
344
345    //This object is not managed anymore.
346    if (!obj_event->callbacks)
347      {
348         evas_object_data_set(obj, EA_OBJ_KEY_OBJ_EVENT, NULL);
349         evas_object_data_set(obj, EA_OBJ_KEY_EVENT_MGR, NULL);
350         Eina_List *l = eina_list_data_find_list(event_mgr->obj_events,
351                                                 obj_event);
352         if (l)
353           event_mgr->obj_events = eina_list_remove_list(event_mgr->obj_events,
354                                                         l);
355         if (obj_event->on_callback) obj_event->delete_me = EINA_TRUE;
356         else free(obj_event);
357      }
358
359    _ea_event_mgr_del(event_mgr);
360
361    return data;
362 }
363
364 EAPI void
365 ea_object_event_callback_add(Evas_Object *obj, Ea_Callback_Type type, Ea_Event_Cb func, void *data)
366 {
367    Ea_Event_Mgr *event_mgr;
368    Evas *e;
369    Ea_Object_Event *obj_event = NULL;
370    Eina_List *l;
371    Ea_Event_Callback *callback;
372    Eina_Bool new_event_mgr = EINA_TRUE;
373
374    //Check the registered event manager for this Evas.
375    e = evas_object_evas_get(obj);
376
377    EINA_LIST_FOREACH(event_mgrs, l, event_mgr)
378      {
379         if (event_mgr->e == e)
380           {
381              new_event_mgr = EINA_FALSE;
382              break;
383           }
384      }
385
386    //New Evas comes. Create new event manager for this Evas.
387    if (new_event_mgr)
388      {
389         if (!(event_mgr = _ea_event_mgr_new(e))) return;
390         event_mgrs = eina_list_append(event_mgrs, event_mgr);
391      }
392
393    obj_event = evas_object_data_get(obj, EA_OBJ_KEY_OBJ_EVENT);
394
395    //New Object Event. Probably user adds ea_object_event_callback first time.
396    if (!obj_event)
397      {
398         obj_event = calloc(1, sizeof(Ea_Object_Event));
399         if (!obj_event)
400           {
401              LOGE("Failed to allocate object event");
402              return;
403           }
404         evas_object_data_set(obj, EA_OBJ_KEY_OBJ_EVENT, obj_event);
405         evas_object_data_set(obj, EA_OBJ_KEY_EVENT_MGR, event_mgr);
406         evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
407                                        _ea_object_del_cb,
408                                        obj_event);
409         event_mgr->obj_events = eina_list_append(event_mgr->obj_events,
410                                                  obj_event);
411         obj_event->obj = obj;
412      }
413
414    //Append this callback.
415    callback = calloc(1, sizeof(Ea_Event_Callback));
416    if (!callback)
417      {
418         LOGE("Failed to allocate event callback");
419         return;
420      }
421    callback->type = type;
422    callback->func = func;
423    callback->data = data;
424
425    obj_event->callbacks = eina_list_append(obj_event->callbacks, callback);
426 }