8c9017bb41b16b1a56eee9572343db9b6ac0790c
[platform/upstream/enlightenment.git] / src / bin / e_pointer.c
1 #include "e_pointer_intern.h"
2 #include "e_input_intern.h"
3 #include "e_client_intern.h"
4
5 /* local variables */
6 static Eina_List *_ptrs = NULL;
7 static Eina_Bool _initted = EINA_FALSE;
8
9 static int _e_pointer_hooks_delete = 0;
10 static int _e_pointer_hooks_walking = 0;
11 static Eina_Inlist *_e_pointer_hooks[] =
12 {
13    [E_POINTER_HOOK_TOUCH_MOVE] = NULL,
14    [E_POINTER_HOOK_MOUSE_MOVE] = NULL,
15    [E_POINTER_HOOK_SHOW] = NULL,
16    [E_POINTER_HOOK_HIDE] = NULL,
17 };
18
19 static void
20 _e_pointer_configured_output_resolution_ratio_get(E_Client *ec, double *ratio)
21 {
22    E_Output *output;
23    E_Zone *zone;
24    double cal_ratio_w, cal_ratio_h, cal_ratio;
25
26    if (!ratio) return;
27
28    *ratio = 1.0;
29
30    if (!e_config->cursor_configured_output_resolution.use) return;
31    if (e_config->cursor_configured_output_resolution.w == 0) return;
32    if (e_config->cursor_configured_output_resolution.h == 0) return;
33
34    if (!ec) return;
35
36    zone = e_comp_zone_find_by_ec(ec);
37    if (!zone) return;
38
39    output = e_output_find(zone->output_id);
40    if (!output) return;
41    if (output->config.geom.w == 0) return;
42    if (output->config.geom.h == 0) return;
43
44    cal_ratio_w = (double)output->config.geom.w /
45                  (double)e_config->cursor_configured_output_resolution.w;
46
47    cal_ratio_h = (double)output->config.geom.h /
48                  (double)e_config->cursor_configured_output_resolution.h;
49
50    cal_ratio = MIN(cal_ratio_w, cal_ratio_h);
51
52    *ratio = cal_ratio;
53 }
54
55 /* move the cursor image with the calcaultion of the hot spot */
56 static void
57 _e_pointer_position_update(E_Pointer *ptr)
58 {
59    int nx, ny;
60    int rotation;
61    int cursor_w, cursor_h;
62    E_Client *ec;
63    double ratio = 1.0;
64    int hot_x = 0, hot_y = 0;
65
66    if (!ptr->o_ptr) return;
67
68    ec = e_comp_object_client_get(ptr->o_ptr);
69    EINA_SAFETY_ON_NULL_RETURN(ec);
70
71    rotation = ptr->rotation;
72
73    evas_object_geometry_get(ec->frame, NULL, NULL, &cursor_w, &cursor_h);
74    _e_pointer_configured_output_resolution_ratio_get(ec, &ratio);
75
76    if (ratio != 1.0)
77      {
78         hot_x = (int)((double)ptr->hot.x * ratio);
79         hot_y = (int)((double)ptr->hot.y * ratio);
80      }
81    else
82      {
83         hot_x = ptr->hot.x;
84         hot_y = ptr->hot.y;
85      }
86
87    switch (rotation)
88      {
89       case 0:
90         nx = ptr->x - hot_x;
91         ny = ptr->y - hot_y;
92         break;
93       case 90:
94         nx = ptr->x - hot_y;
95         ny = ptr->y + hot_x;
96         break;
97       case 180:
98         nx = ptr->x + hot_x;
99         ny = ptr->y + hot_y;
100         break;
101       case 270:
102         nx = ptr->x + hot_y;
103         ny = ptr->y - hot_x;
104         break;
105       default:
106         nx = ptr->x - hot_x;
107         ny = ptr->y - hot_y;
108         break;
109      }
110
111    evas_object_move(ptr->o_ptr, nx, ny);
112 }
113
114 static void
115 _e_pointer_map_apply(E_Pointer *ptr)
116 {
117    E_Map *map;
118    int x, y, w, h;
119    E_Client *ec;
120    int rotation = 0;
121    double ratio = 1.0;
122
123    EINA_SAFETY_ON_NULL_RETURN(ptr);
124    if (!ptr->o_ptr) return;
125
126    ec = e_comp_object_client_get(ptr->o_ptr);
127    EINA_SAFETY_ON_NULL_RETURN(ec);
128
129    _e_pointer_configured_output_resolution_ratio_get(ec, &ratio);
130    rotation = ptr->rotation;
131
132    if ((ratio == 1.0) &&
133        ((rotation == 0) || (rotation % 90 != 0) || (rotation / 90 > 3)))
134      {
135         e_client_map_enable_set(ec, EINA_FALSE);
136         e_client_map_set(ec, NULL);
137         return;
138      }
139
140    evas_object_geometry_get(ec->frame, &x, &y, &w, &h);
141
142    map = e_map_new();
143    EINA_SAFETY_ON_NULL_RETURN(map);
144
145    e_map_util_points_populate_from_object_full(map, ec->frame, 0);
146
147    if (ratio != 1.0)
148      {
149         e_map_point_coord_set(map, 1, x + (int)((double)w * ratio), y, 0);
150         e_map_point_coord_set(map, 2, x + (int)((double)w * ratio),
151                              y + (int)((double)h * ratio), 0);
152         e_map_point_coord_set(map, 3, x, y + (int)((double)h * ratio), 0);
153      }
154
155    if (rotation)
156      {
157         if (rotation == 90)
158           rotation = 270;
159         else if (rotation == 270)
160           rotation = 90;
161
162         e_map_util_rotate(map, rotation, x, y);
163      }
164
165    e_map_util_points_color_set(map, 255, 255, 255, 255);
166    e_map_util_object_move_sync_set(map, EINA_TRUE);
167
168    e_client_map_set(ec, map);
169    e_client_map_enable_set(ec, EINA_TRUE);
170
171    e_map_free(map);
172 }
173
174 static void
175 _e_pointer_cb_object_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
176 {
177    E_Pointer *ptr = (E_Pointer *)data;
178
179    ptr->o_ptr = NULL;
180    ptr->device = E_POINTER_NONE;
181    ptr->hot.x = 0;
182    ptr->hot.y = 0;
183 }
184
185 static void
186 _e_pointer_object_set(E_Pointer *ptr, Evas_Object *obj)
187 {
188    if (ptr->o_ptr == obj) return;
189
190    if (ptr->o_ptr)
191      {
192          evas_object_event_callback_del_full(ptr->o_ptr, EVAS_CALLBACK_DEL, _e_pointer_cb_object_del, ptr);
193          ptr->o_ptr = NULL;
194      }
195
196    if (obj)
197      {
198         evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _e_pointer_cb_object_del, ptr);
199         ptr->o_ptr = obj;
200      }
201 }
202
203 static void
204 _e_pointer_cb_free(E_Pointer *ptr)
205 {
206    _e_pointer_object_set(ptr, NULL);
207
208    _ptrs = eina_list_remove(_ptrs, ptr);
209
210    free(ptr);
211 }
212
213 static void
214 _e_pointer_hooks_clean(void)
215 {
216    Eina_Inlist *l;
217    E_Pointer_Hook *ph;
218    unsigned int x;
219
220    for (x = 0; x < E_POINTER_HOOK_LAST; x++)
221      EINA_INLIST_FOREACH_SAFE(_e_pointer_hooks[x], l, ph)
222        {
223           if (!ph->delete_me) continue;
224           _e_pointer_hooks[x] = eina_inlist_remove(_e_pointer_hooks[x], EINA_INLIST_GET(ph));
225           free(ph);
226        }
227
228    _e_pointer_hooks_delete = 0;
229 }
230
231 static Eina_Bool
232 _e_pointer_hook_call(E_Pointer_Hook_Point hookpoint, E_Pointer *ptr)
233 {
234    E_Pointer_Hook *ph;
235
236    e_object_ref(E_OBJECT(ptr));
237    _e_pointer_hooks_walking++;
238    EINA_INLIST_FOREACH(_e_pointer_hooks[hookpoint], ph)
239      {
240         if (ph->delete_me) continue;
241         ph->func(ph->data, ptr);
242         if (e_object_is_del(E_OBJECT(ptr)))
243           break;
244      }
245    _e_pointer_hooks_walking--;
246    if ((_e_pointer_hooks_walking == 0) && (_e_pointer_hooks_delete > 0))
247      _e_pointer_hooks_clean();
248    return !!e_object_unref(E_OBJECT(ptr));
249 }
250
251 EINTERN int
252 e_pointer_init(void)
253 {
254    _initted = EINA_TRUE;
255    return 1;
256 }
257
258 EINTERN int
259 e_pointer_shutdown(void)
260 {
261    _initted = EINA_FALSE;
262    return 1;
263 }
264
265 EINTERN E_Pointer *
266 e_pointer_canvas_new(Ecore_Evas *ee, Eina_Bool filled)
267 {
268    E_Pointer *ptr = NULL;
269    E_Output *output = NULL;
270
271    EINA_SAFETY_ON_FALSE_RETURN_VAL(ee, NULL);
272    if (!_initted) return NULL;
273
274    /* allocate space for new pointer */
275    if (!(ptr = E_OBJECT_ALLOC(E_Pointer, E_POINTER_TYPE, _e_pointer_cb_free)))
276      return NULL;
277
278    /* set default pointer properties */
279    ptr->canvas = EINA_TRUE;
280    ptr->w = ptr->h = e_config->cursor_size;
281    ptr->e_cursor = e_config->use_e_cursor;
282    output = e_output_find_by_index(0);
283    if (output)
284      {
285         ptr->x = output->config.mode.w / 2;
286         ptr->y = output->config.mode.h / 2;
287      }
288
289    ptr->ee = ee;
290    ptr->evas = ecore_evas_get(ee);
291
292    /* append this pointer to the list */
293    _ptrs = eina_list_append(_ptrs, ptr);
294
295    return ptr;
296 }
297
298 static Eina_Bool
299 _e_pointer_object_hide(E_Pointer *ptr, Evas_Object *obj)
300 {
301    E_Client *ec;
302    Eina_Bool res = EINA_FALSE;
303
304    ec = e_comp_object_client_get(obj);
305    if ((ec) && (!e_object_is_del(E_OBJECT(ec))))
306      {
307         ec->hidden = 1;
308         ec->visible = EINA_FALSE;
309         ec->visibility.obscured = E_VISIBILITY_FULLY_OBSCURED;
310         ec->comp_data->mapped = EINA_FALSE;
311         ec->override = 1; /* ignore the previous cursor_ec */
312      }
313
314    /* hide cursor object */
315    if (evas_object_visible_get(obj))
316      {
317         res = EINA_TRUE;
318         evas_object_hide(obj);
319         evas_damage_rectangle_add(e_comp->evas, 0, 0, e_comp->w, e_comp->h);
320      }
321
322    _e_pointer_object_set(ptr, NULL);
323    ptr->device = E_POINTER_NONE;
324
325    return res;
326 }
327
328 static Eina_Bool
329 _e_pointer_object_show(E_Pointer *ptr, Evas_Object *obj)
330 {
331    E_Client *ec;
332    Eina_Bool res = EINA_FALSE;
333
334    ec = e_comp_object_client_get(obj);
335    if (ec && e_pixmap_usable_get(ec->pixmap))
336      {
337         ec->hidden = 0;
338         ec->visible = EINA_TRUE;
339         ec->visibility.obscured = E_VISIBILITY_UNOBSCURED;
340         evas_object_geometry_set(ec->frame, ec->x, ec->y, ec->w, ec->h);
341         ec->comp_data->mapped = EINA_TRUE;
342         ec->override = 0; /* do not ignore the cursor_ec to set the image object */
343      }
344
345    /* show cursor object */
346    if (!evas_object_visible_get(obj))
347      {
348         res = EINA_TRUE;
349         evas_object_show(obj);
350      }
351
352    _e_pointer_object_set(ptr, obj);
353
354    return res;
355 }
356
357 EINTERN void
358 e_pointer_object_set(E_Pointer *ptr, Evas_Object *obj, int x, int y)
359 {
360    Eina_Bool need_call_hide = EINA_FALSE;
361
362    EINA_SAFETY_ON_NULL_RETURN(ptr);
363
364    /* don't show cursor if in hidden mode */
365    if ((!e_config->show_cursor) || (!e_comp_wl->ptr.enabled))
366      {
367         if (ptr->o_ptr && _e_pointer_object_hide(ptr, ptr->o_ptr))
368           _e_pointer_hook_call(E_POINTER_HOOK_HIDE, ptr);
369
370         return;
371      }
372
373    /* hide and unset the existed ptr->o_ptr */
374    if (ptr->o_ptr && (ptr->o_ptr != obj))
375      {
376         if (_e_pointer_object_hide(ptr, ptr->o_ptr))
377           need_call_hide = EINA_TRUE;
378      }
379
380    /* update the hot spot of the cursor */
381    ptr->hot.x = x;
382    ptr->hot.y = y;
383
384    /* if obj is not null, set the obj to ptr->o_ptr */
385    if (obj && (ptr->o_ptr != obj))
386      {
387         if (_e_pointer_object_show(ptr, obj))
388           {
389              need_call_hide = EINA_FALSE;
390              _e_pointer_hook_call(E_POINTER_HOOK_SHOW, ptr);
391           }
392
393         /* apply the cursor obj map */
394         _e_pointer_map_apply(ptr);
395
396         /* move the pointer to the current position */
397         _e_pointer_position_update(ptr);
398      }
399
400    if (need_call_hide)
401      _e_pointer_hook_call(E_POINTER_HOOK_HIDE, ptr);
402 }
403
404 EINTERN void
405 e_pointer_touch_move(E_Pointer *ptr, int x, int y)
406 {
407    EINA_SAFETY_ON_NULL_RETURN(ptr);
408
409    if (!e_config->show_cursor) return;
410
411    /* save the current position */
412    ptr->x = x;
413    ptr->y = y;
414
415    if (ptr->device != E_POINTER_TOUCH) ptr->device = E_POINTER_TOUCH;
416
417    _e_pointer_position_update(ptr);
418
419    _e_pointer_hook_call(E_POINTER_HOOK_TOUCH_MOVE, ptr);
420 }
421
422 E_API void
423 e_pointer_mouse_move(E_Pointer *ptr, int x, int y)
424 {
425    EINA_SAFETY_ON_NULL_RETURN(ptr);
426
427    if (!e_config->show_cursor) return;
428
429    /* save the current position */
430    ptr->x = x;
431    ptr->y = y;
432
433    if (ptr->device != E_POINTER_MOUSE) ptr->device = E_POINTER_MOUSE;
434
435    _e_pointer_position_update(ptr);
436
437    _e_pointer_hook_call(E_POINTER_HOOK_MOUSE_MOVE, ptr);
438 }
439
440 EINTERN void
441 e_pointer_hide(E_Pointer *ptr)
442 {
443    EINA_SAFETY_ON_NULL_RETURN(ptr);
444    if (!ptr->o_ptr) return;
445    if (!evas_object_visible_get(ptr->o_ptr)) return;
446
447    evas_object_hide(ptr->o_ptr);
448 }
449
450 E_API Eina_Bool
451 e_pointer_is_hidden(E_Pointer *ptr)
452 {
453    EINA_SAFETY_ON_NULL_RETURN_VAL(ptr, EINA_TRUE);
454
455    if (!e_config->show_cursor) return EINA_TRUE;
456    if (ptr->o_ptr && evas_object_visible_get(ptr->o_ptr)) return EINA_FALSE;
457
458    return EINA_TRUE;
459 }
460
461 E_API void
462 e_pointer_rotation_set(E_Pointer *ptr, int rotation)
463 {
464    const Eina_List *l;
465    E_Input_Device *dev;
466
467    EINA_SAFETY_ON_NULL_RETURN(ptr);
468    if (ptr->rotation == rotation) return;
469
470    ptr->rotation = rotation;
471
472    _e_pointer_map_apply(ptr);
473    _e_pointer_position_update(ptr);
474
475    EINA_LIST_FOREACH(e_input_devices_get(), l, dev)
476      e_input_device_pointer_rotation_set(dev, rotation);
477 }
478
479 EINTERN void
480 e_pointer_position_get(E_Pointer *ptr, int *x, int *y)
481 {
482    EINA_SAFETY_ON_NULL_RETURN(ptr);
483
484    if (!e_config->show_cursor) return;
485    if (!ptr->o_ptr) return;
486    if (!evas_object_visible_get(ptr->o_ptr)) return;
487
488    *x = ptr->x;
489    *y = ptr->y;
490 }
491
492 EINTERN E_Pointer *
493 e_pointer_get(E_Client *ec)
494 {
495    const Eina_List *l;
496    E_Pointer *ptr;
497    E_Client *ptr_ec = NULL;
498
499    if ((!ec) || (e_object_is_del(E_OBJECT(ec)))) return NULL;
500
501    EINA_LIST_FOREACH(_ptrs, l, ptr)
502      {
503         if (ptr->o_ptr)
504           {
505              ptr_ec = e_comp_object_client_get(ptr->o_ptr);
506              if (ptr_ec == ec)
507                 return ptr;
508           }
509      }
510
511   return NULL;
512 }
513
514 E_API E_Pointer_Hook *
515 e_pointer_hook_add(E_Pointer_Hook_Point hookpoint, E_Pointer_Hook_Cb func, const void *data)
516 {
517    E_Pointer_Hook *ph;
518
519    EINA_SAFETY_ON_TRUE_RETURN_VAL(hookpoint >= E_POINTER_HOOK_LAST, NULL);
520    ph = E_NEW(E_Pointer_Hook, 1);
521    if (!ph) return NULL;
522    ph->hookpoint = hookpoint;
523    ph->func = func;
524    ph->data = (void*)data;
525    _e_pointer_hooks[hookpoint] = eina_inlist_append(_e_pointer_hooks[hookpoint], EINA_INLIST_GET(ph));
526    return ph;
527 }
528
529 E_API void
530 e_pointer_hook_del(E_Pointer_Hook *ph)
531 {
532    ph->delete_me = 1;
533    if (_e_pointer_hooks_walking == 0)
534      {
535         _e_pointer_hooks[ph->hookpoint] = eina_inlist_remove(_e_pointer_hooks[ph->hookpoint], EINA_INLIST_GET(ph));
536         free(ph);
537      }
538    else
539      _e_pointer_hooks_delete++;
540 }