evas_device: fix memory leak.
[platform/upstream/efl.git] / src / lib / evas / canvas / evas_device.c
1 #include "evas_common_private.h"
2 #include "evas_private.h"
3
4 /* WARNING: This API is not used across EFL, hard to test! */
5
6 #ifdef DEBUG_UNTESTED_
7 // booh
8 #define SAFETY_CHECK(obj, klass, ...) \
9    do { MAGIC_CHECK(dev, Evas_Device, 1); \
10         return __VA_ARGS__; \
11         MAGIC_CHECK_END(); \
12    } while (0)
13
14 #else
15 #define SAFETY_CHECK(obj, klass, ...) \
16    do { if (!obj) return __VA_ARGS__; } while (0)
17 #endif
18
19 /* FIXME: Ideally no work besides calling the Efl_Input_Device API
20  * should be done here. But unfortunately, some knowledge of Evas is required
21  * here (callbacks and canvas private data).
22  */
23
24 static Eina_Bool
25 _is_pointer(Evas_Device_Class clas)
26 {
27    if (clas == EVAS_DEVICE_CLASS_MOUSE ||
28        clas == EVAS_DEVICE_CLASS_TOUCH ||
29        clas == EVAS_DEVICE_CLASS_PEN ||
30        clas == EVAS_DEVICE_CLASS_POINTER ||
31        clas == EVAS_DEVICE_CLASS_WAND)
32      return EINA_TRUE;
33    return EINA_FALSE;
34 }
35
36 static Evas_Device *
37 _new_default_device_find(Evas_Public_Data *e, Evas_Device *old_dev)
38 {
39    Eina_List *l;
40    Evas_Device *dev, *def, *old_parent;
41    Efl_Input_Device_Type old_class;
42
43    if (e->cleanup) return NULL;
44    old_class = efl_input_device_type_get(old_dev);
45    old_parent = efl_parent_get(old_dev);
46    def = NULL;
47
48    EINA_LIST_FOREACH(e->devices, l, dev)
49      {
50         if (efl_input_device_type_get(dev) != old_class)
51           continue;
52
53         def = dev;
54         //Prefer devices with the same parent.
55         if (efl_parent_get(dev) == old_parent)
56           break;
57      }
58
59    if (!def)
60      {
61         const char *class_str;
62         if (old_class == EFL_INPUT_DEVICE_TYPE_SEAT)
63           class_str = "seat";
64         else if (old_class == EFL_INPUT_DEVICE_TYPE_KEYBOARD)
65           class_str = "keyboard";
66         else
67           class_str = "mouse";
68         WRN("Could not find a default %s device.", class_str);
69      }
70    return def;
71 }
72
73 static void
74 _del_cb(void *data, const Efl_Event *ev)
75 {
76    Efl_Input_Device_Type devtype;
77    Evas_Public_Data *e = data;
78
79    e->devices_modified = EINA_TRUE;
80    // can not be done in std destructor
81    e->devices = eina_list_remove(e->devices, ev->object);
82
83    if (e->default_seat == ev->object)
84      e->default_seat = _new_default_device_find(e, ev->object);
85    else if (e->default_mouse == ev->object)
86      e->default_mouse = _new_default_device_find(e, ev->object);
87    else if (e->default_keyboard == ev->object)
88      e->default_keyboard = _new_default_device_find(e, ev->object);
89
90    //TIZEN_ONLY(20180530): add storing last mouse device.
91    if (e->last_mouse == ev->object)
92      e->last_mouse = NULL;
93    //
94
95    devtype = efl_input_device_type_get(ev->object);
96    if ((devtype == EFL_INPUT_DEVICE_TYPE_SEAT) && (!e->default_seat))
97      {
98         Evas_Pointer_Data *pdata = _evas_pointer_data_by_device_get(e, ev->object);
99         if (pdata)
100           {
101              Evas_Pointer_Seat *pseat;
102
103              EINA_INLIST_FOREACH(e->seats, pseat)
104                {
105                   /* store to dummy seat data for when seat reattaches */
106                   if (pseat->seat) continue;
107                   pseat->x = pdata->seat->x;
108                   pseat->y = pdata->seat->y;
109                   pseat->inside = pdata->seat->inside;
110                   break;
111                }
112           }
113      }
114
115    if (_is_pointer(devtype))
116      _evas_pointer_data_remove(e, ev->object);
117    eina_hash_del_by_key(e->locks.masks, &ev->object);
118    eina_hash_del_by_key(e->modifiers.masks, &ev->object);
119    efl_event_callback_call(e->evas, EFL_CANVAS_SCENE_EVENT_DEVICE_REMOVED,
120                            ev->object);
121 }
122
123 EOLIAN Efl_Input_Device *
124 _evas_canvas_efl_canvas_scene_device_get(Evas *eo_e EINA_UNUSED, Evas_Public_Data *e, const char *name)
125 {
126    const char *dev_name;
127    Evas_Device *dev;
128    Eina_List *l;
129
130    if (!name) return NULL;
131
132    EINA_LIST_FOREACH(e->devices, l, dev)
133      {
134         dev_name = efl_name_get(dev);
135
136         if (eina_streq(dev_name, name))
137           return dev;
138      }
139
140    return NULL;
141 }
142
143 EAPI Evas_Device *
144 evas_device_get(Evas *eo_e, const char *name)
145 {
146    return efl_canvas_scene_device_get(eo_e, name);
147 }
148
149 EOLIAN Efl_Input_Device *
150 _evas_canvas_efl_canvas_scene_seat_default_get(Evas *eo_e EINA_UNUSED, Evas_Public_Data *e)
151 {
152    return e->default_seat;
153 }
154
155 EOLIAN Efl_Input_Device *
156 _evas_canvas_efl_canvas_scene_seat_get(Evas *eo_e EINA_UNUSED, Evas_Public_Data *e, unsigned int id)
157 {
158    Evas_Device *dev;
159    Eina_List *l;
160
161    EINA_LIST_FOREACH(e->devices, l, dev)
162      {
163         if (efl_input_device_type_get(dev) != EFL_INPUT_DEVICE_TYPE_SEAT)
164           continue;
165
166         if (efl_input_device_seat_id_get(dev) == id)
167           return dev;
168      }
169
170    return NULL;
171 }
172
173 EAPI Evas_Device *
174 evas_device_get_by_seat_id(Evas *eo_e, unsigned int id)
175 {
176    return efl_canvas_scene_seat_get(eo_e, id);
177 }
178
179 EAPI Evas_Device *
180 evas_device_add(Evas *eo_e)
181 {
182    return evas_device_add_full(eo_e, NULL, NULL, NULL, NULL,
183                                EVAS_DEVICE_CLASS_NONE,
184                                EVAS_DEVICE_SUBCLASS_NONE);
185 }
186
187 EAPI Evas_Device *
188 evas_device_add_full(Evas *eo_e, const char *name, const char *desc,
189                      Evas_Device *parent_dev, Evas_Device *emulation_dev,
190                      Evas_Device_Class clas, Evas_Device_Subclass sub_clas)
191 {
192    Evas_Public_Data *e;
193    Evas_Device *dev;
194
195    SAFETY_CHECK(eo_e, EVAS_CANVAS_CLASS, NULL);
196
197    dev = efl_add_ref(EFL_INPUT_DEVICE_CLASS, parent_dev ?: eo_e,
198                      efl_name_set(efl_added, name),
199                      efl_comment_set(efl_added, desc),
200                      efl_input_device_type_set(efl_added, (Efl_Input_Device_Type)clas),
201                      efl_input_device_source_set(efl_added, emulation_dev),
202                      efl_input_device_evas_set(efl_added, eo_e),
203                      efl_input_device_subclass_set(efl_added, sub_clas));
204
205    e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
206
207    /* This is the case when the user is using wayland backend,
208       since evas itself will not create the devices we must set them here. */
209    if (!e->default_seat && clas == EVAS_DEVICE_CLASS_SEAT)
210      e->default_seat = dev;
211    else if (!e->default_keyboard && clas == EVAS_DEVICE_CLASS_KEYBOARD)
212      e->default_keyboard = dev;
213    else if (_is_pointer(clas))
214      {
215         Evas_Pointer_Data *pdata = _evas_pointer_data_add(e, dev);
216         if (!pdata)
217           {
218              efl_del(dev);
219              return NULL;
220           }
221
222         if (e->default_mouse)
223           {
224              if ((clas == EVAS_DEVICE_CLASS_MOUSE) &&
225                  (parent_dev == e->default_seat) &&
226                  (evas_device_class_get(e->default_mouse) != EVAS_DEVICE_CLASS_MOUSE))
227                {
228                   Eina_Bool inside = pdata->seat->inside;
229
230                   if (inside)
231                     evas_event_feed_mouse_out(eo_e, 0, NULL);
232                   e->default_mouse = dev;
233                   if (inside)
234                     evas_event_feed_mouse_in(eo_e, 0, NULL);
235                }
236           }
237         else
238           {
239              Evas_Pointer_Seat *pseat;
240
241              EINA_INLIST_FOREACH(e->seats, pseat)
242                if (!pseat->pointers) break;
243              e->default_mouse = dev;
244              if (pseat)
245                {
246                   if (pseat->inside)
247                     evas_event_feed_mouse_in(eo_e, 0, NULL);
248                   evas_event_feed_mouse_move(eo_e, pseat->x, pseat->y, 0, NULL);
249                }
250           }
251      }
252
253    e->devices = eina_list_append(e->devices, dev);
254    efl_event_callback_add(dev, EFL_EVENT_DEL, _del_cb, e);
255
256    efl_event_callback_call(eo_e, EFL_CANVAS_SCENE_EVENT_DEVICE_ADDED, dev);
257    // Keeping this event to do not break things...
258    evas_event_callback_call(eo_e, EVAS_CALLBACK_DEVICE_CHANGED, dev);
259    if (e->pending_default_focus_obj && (e->default_seat == dev))
260      {
261         Eo *eo_obj = e->pending_default_focus_obj;
262         e->pending_default_focus_obj = NULL;
263         evas_object_focus_set(eo_obj, 1);
264      }
265
266    return dev;
267 }
268
269 EAPI void
270 evas_device_del(Evas_Device *dev)
271 {
272    if (!efl_invalidated_get(dev))
273      efl_del(dev);
274    efl_unref(dev);
275 }
276
277 EAPI void
278 evas_device_push(Evas *eo_e, Evas_Device *dev)
279 {
280    Evas_Public_Data *e = efl_data_scope_safe_get(eo_e, EVAS_CANVAS_CLASS);
281    if (!e) return;
282    if (!e->cur_device)
283      {
284         e->cur_device = eina_array_new(4);
285         if (!e->cur_device) return;
286      }
287    efl_ref(dev);
288    eina_array_push(e->cur_device, dev);
289 }
290
291 EAPI void
292 evas_device_pop(Evas *eo_e)
293 {
294    Evas_Device *dev;
295
296    Evas_Public_Data *e = efl_data_scope_safe_get(eo_e, EVAS_CANVAS_CLASS);
297    if (!e) return ;
298    dev = eina_array_pop(e->cur_device);
299    if (dev) efl_unref(dev);
300 }
301
302 EAPI const Eina_List *
303 evas_device_list(Evas *eo_e, const Evas_Device *dev)
304 {
305    if (dev) return efl_input_device_children_get(dev);
306
307    Evas_Public_Data *e = efl_data_scope_safe_get(eo_e, EVAS_CANVAS_CLASS);
308    return e ? e->devices : NULL;
309 }
310
311 EAPI void
312 evas_device_name_set(Evas_Device *dev, const char *name)
313 {
314    efl_name_set(dev, name);
315    evas_event_callback_call(efl_input_device_evas_get(dev), EVAS_CALLBACK_DEVICE_CHANGED, dev);
316 }
317
318 EAPI const char *
319 evas_device_name_get(const Evas_Device *dev)
320 {
321    return efl_name_get(dev);
322 }
323
324 EAPI void
325 evas_device_description_set(Evas_Device *dev, const char *desc)
326 {
327    efl_comment_set(dev, desc);
328    evas_event_callback_call(efl_input_device_evas_get(dev), EVAS_CALLBACK_DEVICE_CHANGED, dev);
329 }
330
331 EAPI const char *
332 evas_device_description_get(const Evas_Device *dev)
333 {
334    return efl_comment_get(dev);
335 }
336
337 EAPI void
338 evas_device_parent_set(Evas_Device *dev EINA_UNUSED, Evas_Device *parent EINA_UNUSED)
339 {
340    // Note: This function should be deprecated. parent_set doesn't make sense
341    // unless the parent is a seat device. Parent shouldn't be changed after
342    // creation.
343    ERR("It is not advised and possible anymore to changed the parent of an Evas_Device.");
344 }
345
346 EAPI const Evas_Device *
347 evas_device_parent_get(const Evas_Device *dev)
348 {
349    Eo *parent = efl_parent_get(dev);
350
351    if (!efl_isa(parent, EFL_INPUT_DEVICE_CLASS))
352      return NULL;
353
354    return parent;
355 }
356
357 EAPI void
358 evas_device_class_set(Evas_Device *dev, Evas_Device_Class clas)
359 {
360    EINA_SAFETY_ON_TRUE_RETURN(efl_finalized_get(dev));
361
362    Evas_Public_Data *edata = efl_data_scope_safe_get(efl_input_device_evas_get(dev), EVAS_CANVAS_CLASS);
363    Efl_Input_Device_Type klass = efl_input_device_type_get(dev);
364
365    if (!edata) return;
366
367    if ((Evas_Device_Class)klass == clas)
368      return;
369
370    if (_is_pointer((Evas_Device_Class)klass))
371      _evas_pointer_data_remove(edata, dev);
372
373    efl_input_device_type_set(dev, (Efl_Input_Device_Type)clas);
374
375    if (_is_pointer(clas))
376      _evas_pointer_data_add(edata, dev);
377
378    evas_event_callback_call(efl_input_device_evas_get(dev), EVAS_CALLBACK_DEVICE_CHANGED, dev);
379 }
380
381 EAPI Evas_Device_Class
382 evas_device_class_get(const Evas_Device *dev)
383 {
384    return (Evas_Device_Class)efl_input_device_type_get(dev);
385 }
386
387 EAPI void
388 evas_device_subclass_set(Evas_Device *dev, Evas_Device_Subclass clas)
389 {
390    efl_input_device_subclass_set(dev, clas);
391    evas_event_callback_call(efl_input_device_evas_get(dev), EVAS_CALLBACK_DEVICE_CHANGED, dev);
392 }
393
394 EAPI Evas_Device_Subclass
395 evas_device_subclass_get(const Evas_Device *dev)
396 {
397    return efl_input_device_subclass_get(dev);
398 }
399
400 EAPI void
401 evas_device_emulation_source_set(Evas_Device *dev, Evas_Device *src)
402 {
403    efl_input_device_source_set(dev, src);
404    evas_event_callback_call(efl_input_device_evas_get(dev), EVAS_CALLBACK_DEVICE_CHANGED, dev);
405 }
406
407 EAPI const Evas_Device *
408 evas_device_emulation_source_get(const Evas_Device *dev)
409 {
410    return efl_input_device_source_get(dev);
411 }
412
413 EAPI void
414 evas_device_seat_id_set(Evas_Device *dev, unsigned int id)
415 {
416    efl_input_device_seat_id_set(dev, id);
417 }
418
419 EAPI unsigned int
420 evas_device_seat_id_get(const Evas_Device *dev)
421 {
422    return efl_input_device_seat_id_get(dev);
423 }
424
425 void
426 _evas_device_cleanup(Evas *eo_e)
427 {
428    Eina_List *cpy, *deleted = NULL;
429    Evas_Device *dev;
430    Evas_Public_Data *e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
431
432    if (e->cur_device)
433      {
434         while ((dev = eina_array_pop(e->cur_device)))
435           efl_unref(dev);
436         eina_array_free(e->cur_device);
437         e->cur_device = NULL;
438      }
439
440    /* If the device is deleted, _del_cb will remove the device
441     * from the devices list. Ensure we delete them only once, and only if this
442     * Evas is the owner, otherwise we would kill external references (eg.
443     * from efl_duplicate()). */
444 again:
445    e->devices_modified = EINA_FALSE;
446    cpy = eina_list_clone(e->devices);
447    EINA_LIST_FREE(cpy, dev)
448      {
449         if (!eina_list_data_find(deleted, dev))
450           {
451              evas_device_del(dev);
452              deleted = eina_list_append(deleted, dev);
453              if (e->devices_modified)
454                {
455                   eina_list_free(cpy);
456                   goto again;
457                }
458           }
459      }
460    eina_list_free(deleted);
461
462    /* Not all devices were deleted. The user probably will unref them later.
463       Since Evas will be deleted, remove the del callback from them and
464       tell the user that the device was removed.
465    */
466    EINA_LIST_FREE(e->devices, dev)
467      {
468         efl_event_callback_call(e->evas, EFL_CANVAS_SCENE_EVENT_DEVICE_REMOVED, dev);
469         efl_event_callback_del(dev, EFL_EVENT_DEL, _del_cb, e);
470      }
471 }
472
473 Evas_Device *
474 _evas_device_top_get(const Evas *eo_e)
475 {
476    int num;
477
478    Evas_Public_Data *e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
479    if (!e->cur_device) return NULL;
480    num = eina_array_count(e->cur_device);
481    if (num < 1) return NULL;
482    return eina_array_data_get(e->cur_device, num - 1);
483 }
484
485 EOLIAN Eina_Bool
486 _evas_canvas_efl_canvas_scene_pointer_position_get(const Eo *eo_e, Evas_Public_Data *e, Efl_Input_Device *seat, Eina_Position2D *pos)
487 {
488    Eina_Iterator *it;
489    Eo *child;
490
491    if (!pos) return EINA_FALSE;
492
493    *pos = EINA_POSITION2D(0, 0);
494    if (!e->default_seat) return EINA_FALSE;
495    if (!seat)
496      {
497         evas_pointer_canvas_xy_get(eo_e, &pos->x, &pos->y);
498         return EINA_TRUE;
499      }
500    it = efl_input_device_children_iterate(seat);
501    EINA_SAFETY_ON_NULL_RETURN_VAL(it, EINA_FALSE);
502
503    EINA_ITERATOR_FOREACH(it, child)
504      if (_is_pointer((Evas_Device_Class)efl_input_device_type_get(child)))
505        break;
506    if (child)
507      *pos = efl_input_pointer_position_get(child);
508
509    eina_iterator_free(it);
510    return !!child;
511 }
512
513 //TIZEN_ONLY(20171220): send a hw device for pointer events
514 EAPI Evas_Device *
515 evas_device_top_get(const Evas *eo_e)
516 {
517    return _evas_device_top_get(eo_e);
518 }
519 //
520
521 //TIZEN_ONLY
522 EAPI Evas_Device *
523 evas_device_default_get(const Evas *eo_e, Evas_Device_Class clas)
524 {
525    Evas_Public_Data *e;
526
527    SAFETY_CHECK(eo_e, EVAS_CANVAS_CLASS, NULL);
528
529    e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
530
531    if (clas == EVAS_DEVICE_CLASS_SEAT)
532      {
533         return e->default_seat;
534      }
535    else if (clas == EVAS_DEVICE_CLASS_KEYBOARD)
536      {
537         return e->default_keyboard;
538      }
539    else if (clas == EVAS_DEVICE_CLASS_MOUSE ||
540             clas == EVAS_DEVICE_CLASS_TOUCH)
541      {
542         return e->default_mouse;
543      }
544
545    return NULL;
546 }
547 //
548