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