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
_is_pointer(Evas_Device_Class clas)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 *
_new_default_device_find(Evas_Public_Data * e,Evas_Device * old_dev)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
_del_cb(void * data,const Efl_Event * ev)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    devtype = efl_input_device_type_get(ev->object);
91    if ((devtype == EFL_INPUT_DEVICE_TYPE_SEAT) && (!e->default_seat))
92      {
93         Evas_Pointer_Data *pdata = _evas_pointer_data_by_device_get(e, ev->object);
94         if (pdata)
95           {
96              Evas_Pointer_Seat *pseat;
97 
98              EINA_INLIST_FOREACH(e->seats, pseat)
99                {
100                   /* store to dummy seat data for when seat reattaches */
101                   if (pseat->seat) continue;
102                   pseat->x = pdata->seat->x;
103                   pseat->y = pdata->seat->y;
104                   pseat->inside = pdata->seat->inside;
105                   break;
106                }
107           }
108      }
109 
110    if (devtype == EFL_INPUT_DEVICE_TYPE_MOUSE)
111      {
112         _evas_pointer_data_remove(e, ev->object, EINA_TRUE);
113      }
114    eina_hash_del_by_key(e->locks.masks, &ev->object);
115    eina_hash_del_by_key(e->modifiers.masks, &ev->object);
116    efl_event_callback_call(e->evas, EFL_CANVAS_SCENE_EVENT_DEVICE_REMOVED,
117                            ev->object);
118 }
119 
120 EOLIAN Efl_Input_Device *
_evas_canvas_efl_canvas_scene_device_get(Evas * eo_e EINA_UNUSED,Evas_Public_Data * e,const char * name)121 _evas_canvas_efl_canvas_scene_device_get(Evas *eo_e EINA_UNUSED, Evas_Public_Data *e, const char *name)
122 {
123    const char *dev_name;
124    Evas_Device *dev;
125    Eina_List *l;
126 
127    if (!name) return NULL;
128 
129    EINA_LIST_FOREACH(e->devices, l, dev)
130      {
131         dev_name = efl_name_get(dev);
132 
133         if (eina_streq(dev_name, name))
134           return dev;
135      }
136 
137    return NULL;
138 }
139 
140 EAPI Evas_Device *
evas_device_get(Evas * eo_e,const char * name)141 evas_device_get(Evas *eo_e, const char *name)
142 {
143    return efl_canvas_scene_device_get(eo_e, name);
144 }
145 
146 EOLIAN Efl_Input_Device *
_evas_canvas_efl_canvas_scene_seat_default_get(Evas * eo_e EINA_UNUSED,Evas_Public_Data * e)147 _evas_canvas_efl_canvas_scene_seat_default_get(Evas *eo_e EINA_UNUSED, Evas_Public_Data *e)
148 {
149    return e->default_seat;
150 }
151 
152 EOLIAN Efl_Input_Device *
_evas_canvas_efl_canvas_scene_seat_get(Evas * eo_e EINA_UNUSED,Evas_Public_Data * e,unsigned int id)153 _evas_canvas_efl_canvas_scene_seat_get(Evas *eo_e EINA_UNUSED, Evas_Public_Data *e, unsigned int id)
154 {
155    Evas_Device *dev;
156    Eina_List *l;
157 
158    EINA_LIST_FOREACH(e->devices, l, dev)
159      {
160         if (efl_input_device_type_get(dev) != EFL_INPUT_DEVICE_TYPE_SEAT)
161           continue;
162 
163         if (efl_input_device_seat_id_get(dev) == id)
164           return dev;
165      }
166 
167    return NULL;
168 }
169 
170 EAPI Evas_Device *
evas_device_get_by_seat_id(Evas * eo_e,unsigned int id)171 evas_device_get_by_seat_id(Evas *eo_e, unsigned int id)
172 {
173    return efl_canvas_scene_seat_get(eo_e, id);
174 }
175 
176 EAPI Evas_Device *
evas_device_add(Evas * eo_e)177 evas_device_add(Evas *eo_e)
178 {
179    return evas_device_add_full(eo_e, NULL, NULL, NULL, NULL,
180                                EVAS_DEVICE_CLASS_NONE,
181                                EVAS_DEVICE_SUBCLASS_NONE);
182 }
183 
184 EAPI Evas_Device *
evas_device_add_full(Evas * eo_e,const char * name,const char * desc,Evas_Device * parent_dev,Evas_Device * emulation_dev,Evas_Device_Class clas,Evas_Device_Subclass sub_clas)185 evas_device_add_full(Evas *eo_e, const char *name, const char *desc,
186                      Evas_Device *parent_dev, Evas_Device *emulation_dev,
187                      Evas_Device_Class clas, Evas_Device_Subclass sub_clas)
188 {
189    Evas_Public_Data *e;
190    Evas_Device *dev;
191 
192    SAFETY_CHECK(eo_e, EVAS_CANVAS_CLASS, NULL);
193 
194    dev = efl_add_ref(EFL_INPUT_DEVICE_CLASS, parent_dev ?: eo_e,
195                      efl_name_set(efl_added, name),
196                      efl_comment_set(efl_added, desc),
197                      efl_input_device_type_set(efl_added, (Efl_Input_Device_Type)clas),
198                      efl_input_device_source_set(efl_added, emulation_dev),
199                      efl_input_device_evas_set(efl_added, eo_e),
200                      efl_input_device_subclass_set(efl_added, sub_clas));
201 
202    e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
203 
204    /* This is the case when the user is using wayland backend,
205       since evas itself will not create the devices we must set them here. */
206    if (!e->default_seat && clas == EVAS_DEVICE_CLASS_SEAT)
207      e->default_seat = dev;
208    else if (!e->default_keyboard && clas == EVAS_DEVICE_CLASS_KEYBOARD)
209      e->default_keyboard = dev;
210    else if (_is_pointer(clas))
211      {
212         Evas_Pointer_Data *pdata = _evas_pointer_data_add(e, dev);
213         if (!pdata)
214           {
215              efl_del(dev);
216              return NULL;
217           }
218 
219         if (e->default_mouse)
220           {
221              if ((clas == EVAS_DEVICE_CLASS_MOUSE) &&
222                  (parent_dev == e->default_seat) &&
223                  (evas_device_class_get(e->default_mouse) != EVAS_DEVICE_CLASS_MOUSE))
224                {
225                   Eina_Bool inside = pdata->seat->inside;
226 
227                   if (inside)
228                     evas_event_feed_mouse_out(eo_e, 0, NULL);
229                   e->default_mouse = dev;
230                   if (inside)
231                     evas_event_feed_mouse_in(eo_e, 0, NULL);
232                }
233           }
234         else
235           {
236              Evas_Pointer_Seat *pseat;
237 
238              EINA_INLIST_FOREACH(e->seats, pseat)
239                if (!pseat->pointers) break;
240              e->default_mouse = dev;
241              if (pseat)
242                {
243                   if (pseat->inside)
244                     evas_event_feed_mouse_in(eo_e, 0, NULL);
245                   evas_event_feed_mouse_move(eo_e, pseat->x, pseat->y, 0, NULL);
246                }
247           }
248      }
249 
250    e->devices = eina_list_append(e->devices, dev);
251    efl_event_callback_add(dev, EFL_EVENT_DEL, _del_cb, e);
252 
253    efl_event_callback_call(eo_e, EFL_CANVAS_SCENE_EVENT_DEVICE_ADDED, dev);
254    // Keeping this event to do not break things...
255    evas_event_callback_call(eo_e, EVAS_CALLBACK_DEVICE_CHANGED, dev);
256    if (e->pending_default_focus_obj && (e->default_seat == dev))
257      {
258         Eo *eo_obj = e->pending_default_focus_obj;
259         e->pending_default_focus_obj = NULL;
260         evas_object_focus_set(eo_obj, 1);
261      }
262 
263    return dev;
264 }
265 
266 EAPI void
evas_device_del(Evas_Device * dev)267 evas_device_del(Evas_Device *dev)
268 {
269    if (!efl_invalidated_get(dev))
270      efl_del(dev);
271    efl_unref(dev);
272 }
273 
274 EAPI void
evas_device_push(Evas * eo_e,Evas_Device * dev)275 evas_device_push(Evas *eo_e, Evas_Device *dev)
276 {
277    Evas_Public_Data *e = efl_data_scope_safe_get(eo_e, EVAS_CANVAS_CLASS);
278    if (!e) return;
279    if (!e->cur_device)
280      {
281         e->cur_device = eina_array_new(4);
282         if (!e->cur_device) return;
283      }
284    efl_ref(dev);
285    eina_array_push(e->cur_device, dev);
286 }
287 
288 EAPI void
evas_device_pop(Evas * eo_e)289 evas_device_pop(Evas *eo_e)
290 {
291    Evas_Device *dev;
292 
293    Evas_Public_Data *e = efl_data_scope_safe_get(eo_e, EVAS_CANVAS_CLASS);
294    if (!e) return ;
295    dev = eina_array_pop(e->cur_device);
296    if (dev) efl_unref(dev);
297 }
298 
299 EAPI const Eina_List *
evas_device_list(Evas * eo_e,const Evas_Device * dev)300 evas_device_list(Evas *eo_e, const Evas_Device *dev)
301 {
302    if (dev) return efl_input_device_children_get(dev);
303 
304    Evas_Public_Data *e = efl_data_scope_safe_get(eo_e, EVAS_CANVAS_CLASS);
305    return e ? e->devices : NULL;
306 }
307 
308 EAPI void
evas_device_name_set(Evas_Device * dev,const char * name)309 evas_device_name_set(Evas_Device *dev, const char *name)
310 {
311    efl_name_set(dev, name);
312    evas_event_callback_call(efl_input_device_evas_get(dev), EVAS_CALLBACK_DEVICE_CHANGED, dev);
313 }
314 
315 EAPI const char *
evas_device_name_get(const Evas_Device * dev)316 evas_device_name_get(const Evas_Device *dev)
317 {
318    return efl_name_get(dev);
319 }
320 
321 EAPI void
evas_device_description_set(Evas_Device * dev,const char * desc)322 evas_device_description_set(Evas_Device *dev, const char *desc)
323 {
324    efl_comment_set(dev, desc);
325    evas_event_callback_call(efl_input_device_evas_get(dev), EVAS_CALLBACK_DEVICE_CHANGED, dev);
326 }
327 
328 EAPI const char *
evas_device_description_get(const Evas_Device * dev)329 evas_device_description_get(const Evas_Device *dev)
330 {
331    return efl_comment_get(dev);
332 }
333 
334 EAPI void
evas_device_parent_set(Evas_Device * dev EINA_UNUSED,Evas_Device * parent EINA_UNUSED)335 evas_device_parent_set(Evas_Device *dev EINA_UNUSED, Evas_Device *parent EINA_UNUSED)
336 {
337    // Note: This function should be deprecated. parent_set doesn't make sense
338    // unless the parent is a seat device. Parent shouldn't be changed after
339    // creation.
340    ERR("It is not advised and possible anymore to changed the parent of an Evas_Device.");
341 }
342 
343 EAPI const Evas_Device *
evas_device_parent_get(const Evas_Device * dev)344 evas_device_parent_get(const Evas_Device *dev)
345 {
346    Eo *parent = efl_parent_get(dev);
347 
348    if (!efl_isa(parent, EFL_INPUT_DEVICE_CLASS))
349      return NULL;
350 
351    return parent;
352 }
353 
354 EAPI void
evas_device_class_set(Evas_Device * dev,Evas_Device_Class clas)355 evas_device_class_set(Evas_Device *dev, Evas_Device_Class clas)
356 {
357    EINA_SAFETY_ON_TRUE_RETURN(efl_finalized_get(dev));
358 
359    Evas_Public_Data *edata = efl_data_scope_safe_get(efl_input_device_evas_get(dev), EVAS_CANVAS_CLASS);
360    Efl_Input_Device_Type klass = efl_input_device_type_get(dev);
361 
362    if (!edata) return;
363 
364    if ((Evas_Device_Class)klass == clas)
365      return;
366 
367    if (_is_pointer((Evas_Device_Class)klass))
368      _evas_pointer_data_remove(edata, dev, EINA_FALSE);
369 
370    efl_input_device_type_set(dev, (Efl_Input_Device_Type)clas);
371 
372    if (_is_pointer(clas))
373      _evas_pointer_data_add(edata, dev);
374 
375    evas_event_callback_call(efl_input_device_evas_get(dev), EVAS_CALLBACK_DEVICE_CHANGED, dev);
376 }
377 
378 EAPI Evas_Device_Class
evas_device_class_get(const Evas_Device * dev)379 evas_device_class_get(const Evas_Device *dev)
380 {
381    return (Evas_Device_Class)efl_input_device_type_get(dev);
382 }
383 
384 EAPI void
evas_device_subclass_set(Evas_Device * dev,Evas_Device_Subclass clas)385 evas_device_subclass_set(Evas_Device *dev, Evas_Device_Subclass clas)
386 {
387    efl_input_device_subclass_set(dev, clas);
388    evas_event_callback_call(efl_input_device_evas_get(dev), EVAS_CALLBACK_DEVICE_CHANGED, dev);
389 }
390 
391 EAPI Evas_Device_Subclass
evas_device_subclass_get(const Evas_Device * dev)392 evas_device_subclass_get(const Evas_Device *dev)
393 {
394    return efl_input_device_subclass_get(dev);
395 }
396 
397 EAPI void
evas_device_emulation_source_set(Evas_Device * dev,Evas_Device * src)398 evas_device_emulation_source_set(Evas_Device *dev, Evas_Device *src)
399 {
400    efl_input_device_source_set(dev, src);
401    evas_event_callback_call(efl_input_device_evas_get(dev), EVAS_CALLBACK_DEVICE_CHANGED, dev);
402 }
403 
404 EAPI const Evas_Device *
evas_device_emulation_source_get(const Evas_Device * dev)405 evas_device_emulation_source_get(const Evas_Device *dev)
406 {
407    return efl_input_device_source_get(dev);
408 }
409 
410 EAPI void
evas_device_seat_id_set(Evas_Device * dev,unsigned int id)411 evas_device_seat_id_set(Evas_Device *dev, unsigned int id)
412 {
413    efl_input_device_seat_id_set(dev, id);
414 }
415 
416 EAPI unsigned int
evas_device_seat_id_get(const Evas_Device * dev)417 evas_device_seat_id_get(const Evas_Device *dev)
418 {
419    return efl_input_device_seat_id_get(dev);
420 }
421 
422 void
_evas_device_cleanup(Evas * eo_e)423 _evas_device_cleanup(Evas *eo_e)
424 {
425    Eina_List *cpy, *deleted = NULL;
426    Evas_Device *dev;
427    Evas_Public_Data *e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
428 
429    if (e->cur_device)
430      {
431         while ((dev = eina_array_pop(e->cur_device)))
432           efl_unref(dev);
433         eina_array_free(e->cur_device);
434         e->cur_device = NULL;
435      }
436 
437    /* If the device is deleted, _del_cb will remove the device
438     * from the devices list. Ensure we delete them only once, and only if this
439     * Evas is the owner, otherwise we would kill external references (eg.
440     * from efl_duplicate()). */
441 again:
442    e->devices_modified = EINA_FALSE;
443    cpy = eina_list_clone(e->devices);
444    EINA_LIST_FREE(cpy, dev)
445      {
446         if (!eina_list_data_find(deleted, dev) && (efl_parent_get(dev) == eo_e))
447           {
448              evas_device_del(dev);
449              deleted = eina_list_append(deleted, dev);
450              if (e->devices_modified)
451                {
452                   eina_list_free(cpy);
453                   goto again;
454                }
455           }
456      }
457    eina_list_free(deleted);
458 
459    /* Not all devices were deleted. The user probably will unref them later.
460       Since Evas will be deleted, remove the del callback from them and
461       tell the user that the device was removed.
462    */
463    EINA_LIST_FREE(e->devices, dev)
464      {
465         efl_event_callback_call(e->evas, EFL_CANVAS_SCENE_EVENT_DEVICE_REMOVED, dev);
466         efl_event_callback_del(dev, EFL_EVENT_DEL, _del_cb, e);
467      }
468 }
469 
470 Evas_Device *
_evas_device_top_get(const Evas * eo_e)471 _evas_device_top_get(const Evas *eo_e)
472 {
473    int num;
474 
475    Evas_Public_Data *e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
476    if (!e->cur_device) return NULL;
477    num = eina_array_count(e->cur_device);
478    if (num < 1) return NULL;
479    return eina_array_data_get(e->cur_device, num - 1);
480 }
481 
482 EOLIAN Eina_Bool
_evas_canvas_efl_canvas_scene_pointer_position_get(const Eo * eo_e,Evas_Public_Data * e,Efl_Input_Device * seat,Eina_Position2D * pos)483 _evas_canvas_efl_canvas_scene_pointer_position_get(const Eo *eo_e, Evas_Public_Data *e, Efl_Input_Device *seat, Eina_Position2D *pos)
484 {
485    Eina_Iterator *it;
486    Eo *child;
487 
488    if (!pos) return EINA_FALSE;
489 
490    *pos = EINA_POSITION2D(0, 0);
491    if (!e->default_seat) return EINA_FALSE;
492    if (!seat)
493      {
494         evas_pointer_canvas_xy_get(eo_e, &pos->x, &pos->y);
495         return EINA_TRUE;
496      }
497    it = efl_input_device_children_iterate(seat);
498    EINA_SAFETY_ON_NULL_RETURN_VAL(it, EINA_FALSE);
499 
500    EINA_ITERATOR_FOREACH(it, child)
501      if (_is_pointer((Evas_Device_Class)efl_input_device_type_get(child)))
502        break;
503    if (child)
504      *pos = efl_input_pointer_position_get(child);
505 
506    eina_iterator_free(it);
507    return !!child;
508 }
509