e_pointer: add safety checks in e_pointer_is_hidden()
[platform/upstream/enlightenment.git] / src / bin / e_pointer.c
1 #include "e.h"
2
3 typedef struct _E_Pointer_Stack E_Pointer_Stack;
4 struct _E_Pointer_Stack
5 {
6    void *obj;
7    const char *type;
8 };
9
10 /* local variables */
11 static Eina_List *_hdlrs = NULL;
12 static Eina_List *_ptrs = NULL;
13 static Eina_Bool _initted = EINA_FALSE;
14
15 static inline void
16 _e_pointer_theme_buf(E_Pointer *ptr, char cursor[1024])
17 {
18    if (ptr->color)
19      snprintf(cursor, 1024, "e/pointer/enlightenment/%s/color", ptr->type);
20    else
21      snprintf(cursor, 1024, "e/pointer/enlightenment/%s/mono", ptr->type);
22 }
23
24 static inline void 
25 _e_pointer_hot_update(E_Pointer *ptr, int x, int y)
26 {
27    if ((ptr->hot.x != x) || (ptr->hot.y != y))
28      {
29         ptr->hot.x = x;
30         ptr->hot.y = y;
31         ptr->hot.update = EINA_TRUE;
32      }
33 }
34
35 static void 
36 _e_pointer_active(E_Pointer *ptr)
37 {
38    if (!ptr->idle) return;
39    if (ptr->o_ptr)
40      edje_object_signal_emit(ptr->o_ptr, "e,state,mouse,active", "e");
41    ptr->idle = EINA_FALSE;
42 }
43
44 static void 
45 _e_pointer_idle(E_Pointer *ptr)
46 {
47    if (ptr->idle) return;
48    if (ptr->o_ptr)
49      edje_object_signal_emit(ptr->o_ptr, "e,state,mouse,idle", "e");
50    ptr->idle = EINA_TRUE;
51 }
52
53 static Eina_Bool 
54 _e_pointer_cb_idle_poller(void *data)
55 {
56    E_Pointer *ptr;
57    int x = 0, y = 0;
58
59    if (!(ptr = data)) return ECORE_CALLBACK_RENEW;
60
61    if ((e_powersave_mode_get() >= E_POWERSAVE_MODE_MEDIUM) || 
62        (!e_config->idle_cursor))
63      {
64         ptr->idle_poll = NULL;
65         return ECORE_CALLBACK_CANCEL;
66      }
67
68    if (ptr->canvas)
69      ecore_evas_pointer_xy_get(ptr->ee, &x, &y);
70 #ifndef HAVE_WAYLAND_ONLY
71    else
72      ecore_x_pointer_xy_get(ptr->win, &x, &y);
73 #endif
74
75    if ((ptr->x != x) || (ptr->y != y))
76      {
77         ptr->x = x;
78         ptr->y = y;
79         if (ptr->idle) _e_pointer_active(ptr);
80         return ECORE_CALLBACK_RENEW;
81      }
82
83    if (!ptr->idle) _e_pointer_idle(ptr);
84
85    return ECORE_CALLBACK_RENEW;
86 }
87
88 static Eina_Bool 
89 _e_pointer_cb_idle_wait(void *data)
90 {
91    E_Pointer *ptr;
92
93    if (!(ptr = data)) return ECORE_CALLBACK_RENEW;
94    ptr->idle_tmr = NULL;
95    if ((e_powersave_mode_get() >= E_POWERSAVE_MODE_MEDIUM) || 
96        (!e_config->idle_cursor))
97      {
98         E_FREE_FUNC(ptr->idle_poll, ecore_poller_del);
99         return ECORE_CALLBACK_CANCEL;
100      }
101
102    if (!ptr->idle_poll)
103      ptr->idle_poll = ecore_poller_add(ECORE_POLLER_CORE, 64, 
104                                        _e_pointer_cb_idle_poller, ptr);
105
106    return ECORE_CALLBACK_CANCEL;
107 }
108
109 static Eina_Bool 
110 _e_pointer_cb_idle_pre(void *data)
111 {
112    E_Pointer *ptr;
113
114    if (!(ptr = data)) return ECORE_CALLBACK_RENEW;
115
116    if (ptr->canvas)
117      ecore_evas_pointer_xy_get(ptr->ee, &ptr->x, &ptr->y);
118 #ifndef HAVE_WAYLAND_ONLY
119    else
120      ecore_x_pointer_xy_get(ptr->win, &ptr->x, &ptr->y);
121 #endif
122
123    ptr->idle_tmr = ecore_timer_loop_add(4.0, _e_pointer_cb_idle_wait, ptr);
124
125    return ECORE_CALLBACK_CANCEL;
126 }
127
128 static void 
129 _e_pointer_active_handle(E_Pointer *ptr)
130 {
131    _e_pointer_active(ptr);
132    if (ptr->idle_tmr)
133      ecore_timer_reset(ptr->idle_tmr);
134    else
135      {
136         E_FREE_FUNC(ptr->idle_poll, ecore_poller_del);
137         if (e_powersave_mode_get() >= E_POWERSAVE_MODE_MEDIUM) return;
138         if (!e_config->idle_cursor) return;
139         ptr->idle_tmr = ecore_timer_loop_add(1.0, _e_pointer_cb_idle_pre, ptr);
140      }
141 }
142
143 static Eina_Bool 
144 _e_pointer_cb_mouse_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
145 {
146    Eina_List *l;
147    E_Pointer *ptr;
148
149    EINA_LIST_FOREACH(_ptrs, l, ptr)
150      {
151         _e_pointer_active_handle(ptr);
152         if (e_powersave_mode_get() < E_POWERSAVE_MODE_EXTREME)
153           {
154              if (ptr->o_ptr)
155                edje_object_signal_emit(ptr->o_ptr, "e,action,mouse,down", "e");
156           }
157      }
158
159    return ECORE_CALLBACK_PASS_ON;
160 }
161
162 static Eina_Bool 
163 _e_pointer_cb_mouse_up(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
164 {
165    Eina_List *l;
166    E_Pointer *ptr;
167
168    EINA_LIST_FOREACH(_ptrs, l, ptr)
169      {
170         _e_pointer_active_handle(ptr);
171         if (e_powersave_mode_get() < E_POWERSAVE_MODE_EXTREME)
172           {
173              if (ptr->o_ptr)
174                edje_object_signal_emit(ptr->o_ptr, "e,action,mouse,up", "e");
175           }
176      }
177
178    return ECORE_CALLBACK_PASS_ON;
179 }
180
181 static Eina_Bool 
182 _e_pointer_cb_mouse_move(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
183 {
184    Eina_List *l;
185    E_Pointer *ptr;
186
187    EINA_LIST_FOREACH(_ptrs, l, ptr)
188      {
189         _e_pointer_active_handle(ptr);
190         if (e_powersave_mode_get() < E_POWERSAVE_MODE_HIGH)
191           {
192              if (ptr->o_ptr)
193                edje_object_signal_emit(ptr->o_ptr, "e,action,mouse,move", "e");
194           }
195      }
196
197    return ECORE_CALLBACK_PASS_ON;
198 }
199
200 static Eina_Bool 
201 _e_pointer_cb_mouse_wheel(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
202 {
203    Eina_List *l;
204    E_Pointer *ptr;
205
206    EINA_LIST_FOREACH(_ptrs, l, ptr)
207      {
208         _e_pointer_active_handle(ptr);
209         if (e_powersave_mode_get() < E_POWERSAVE_MODE_EXTREME)
210           {
211              if (ptr->o_ptr)
212                edje_object_signal_emit(ptr->o_ptr, "e,action,mouse,wheel", "e");
213           }
214      }
215
216    return ECORE_CALLBACK_PASS_ON;
217 }
218
219 static void 
220 _e_pointer_cb_hot_move(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
221 {
222    E_Pointer *ptr = data;
223    int x = 0, y = 0;
224
225    if (!ptr->e_cursor) return;
226    if (!evas_object_visible_get(ptr->o_ptr)) return;
227    edje_object_part_geometry_get(ptr->o_ptr, "e.swallow.hotspot", 
228                                  &x, &y, NULL, NULL);
229    _e_pointer_hot_update(ptr, x, y);
230 }
231
232 static void 
233 _e_pointer_cb_hot_show(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
234 {
235    E_Pointer *ptr = data;
236    int x = 0, y = 0;
237
238    if (!ptr->e_cursor) return;
239    edje_object_part_geometry_get(ptr->o_ptr, "e.swallow.hotspot", 
240                                  &x, &y, NULL, NULL);
241    _e_pointer_hot_update(ptr, x, y);
242 }
243
244 static void
245 _e_pointer_pointer_canvas_init(E_Pointer *ptr, Evas *e, Evas_Object **o_ptr, Evas_Object **o_hot)
246 {
247    /* create pointer object */
248    *o_ptr = edje_object_add(e);
249
250    /* create hotspot object */
251    *o_hot = evas_object_rectangle_add(e);
252    evas_object_color_set(*o_hot, 0, 0, 0, 0);
253
254    evas_object_event_callback_add(*o_hot, EVAS_CALLBACK_MOVE,
255                                   _e_pointer_cb_hot_move, ptr);
256    evas_object_event_callback_add(*o_hot, EVAS_CALLBACK_SHOW,
257                                   _e_pointer_cb_hot_show, ptr);
258
259    evas_object_move(*o_ptr, 0, 0);
260    evas_object_resize(*o_ptr, ptr->w, ptr->h);
261 }
262
263 static void 
264 _e_pointer_canvas_del(E_Pointer *ptr)
265 {
266    E_FREE_FUNC(ptr->buffer_o_hot, evas_object_del);
267    E_FREE_FUNC(ptr->buffer_o_ptr, evas_object_del);
268    E_FREE_FUNC(ptr->buffer_evas, evas_free);
269    E_FREE(ptr->pixels);
270 }
271
272 static void 
273 _e_pointer_canvas_add(E_Pointer *ptr)
274 {
275    Evas_Engine_Info_Buffer *einfo;
276    int method = 0;
277
278    /* try to create new canvas */
279    if (!(ptr->buffer_evas = evas_new())) goto err;
280
281    method = evas_render_method_lookup("buffer");
282    evas_output_method_set(ptr->buffer_evas, method);
283    evas_output_size_set(ptr->buffer_evas, ptr->w, ptr->h);
284    evas_output_viewport_set(ptr->buffer_evas, 0, 0, ptr->w, ptr->h);
285
286    /* try to allocate space for pixels */
287    if (!(ptr->pixels = malloc(ptr->w * ptr->h * sizeof(int))))
288      goto err;
289
290    /* try to get the buffer engine info */
291    einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ptr->buffer_evas);
292    if (!einfo) goto err;
293
294    /* fill in buffer engine info */
295    einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32;
296    einfo->info.dest_buffer = ptr->pixels;
297    einfo->info.dest_buffer_row_bytes = (ptr->w * sizeof(int));
298    einfo->info.use_color_key = 0;
299    einfo->info.alpha_threshold = 0;
300    einfo->info.func.new_update_region = NULL;
301    einfo->info.func.free_update_region = NULL;
302
303    /* set buffer engine info */
304    evas_engine_info_set(ptr->buffer_evas, (Evas_Engine_Info *)einfo);
305
306    _e_pointer_pointer_canvas_init(ptr, ptr->buffer_evas, &ptr->buffer_o_ptr, &ptr->buffer_o_hot);
307    if (!ptr->evas)
308      {
309         ptr->evas = ptr->buffer_evas;
310         ptr->o_ptr = ptr->buffer_o_ptr;
311         ptr->o_hot = ptr->buffer_o_hot;
312      }
313    return;
314
315 err:
316    _e_pointer_canvas_del(ptr);
317 }
318
319 static void 
320 _e_pointer_canvas_resize(E_Pointer *ptr, int w, int h)
321 {
322    Evas_Engine_Info_Buffer *einfo;
323
324    if ((ptr->w == w) && (ptr->h == h)) return;
325    ptr->w = w;
326    ptr->h = h;
327    evas_output_size_set(ptr->buffer_evas, w, h);
328    evas_output_viewport_set(ptr->buffer_evas, 0, 0, w, h);
329
330    ptr->pixels = realloc(ptr->pixels, (ptr->w * ptr->h * sizeof(int)));
331
332    einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ptr->buffer_evas);
333    EINA_SAFETY_ON_NULL_RETURN(einfo);
334
335    einfo->info.dest_buffer = ptr->pixels;
336    einfo->info.dest_buffer_row_bytes = (ptr->w * sizeof(int));
337    evas_engine_info_set(ptr->buffer_evas, (Evas_Engine_Info *)einfo);
338
339    evas_object_move(ptr->buffer_o_ptr, 0, 0);
340    evas_object_resize(ptr->buffer_o_ptr, ptr->w, ptr->h);
341 }
342
343 static void 
344 _e_pointer_stack_free(E_Pointer_Stack *stack)
345 {
346    if (stack->type) eina_stringshare_del(stack->type);
347    free(stack);
348 }
349
350 static void 
351 _e_pointer_cb_free(E_Pointer *ptr)
352 {
353    _ptrs = eina_list_remove(_ptrs, ptr);
354
355    E_FREE_LIST(ptr->stack, _e_pointer_stack_free);
356
357    eina_stringshare_del(ptr->type);
358
359    E_FREE_FUNC(ptr->idle_tmr, ecore_timer_del);
360    E_FREE_FUNC(ptr->idle_poll, ecore_poller_del);
361
362    if (ptr->buffer_evas) _e_pointer_canvas_del(ptr);
363
364    free(ptr);
365 }
366
367 static void
368 _e_pointer_x11_setup(E_Pointer *ptr, const char *cursor)
369 {
370    if (ptr->e_cursor)
371      {
372         /* create a pointer canvas if we need to */
373         if ((!ptr->buffer_evas) && ptr->win) _e_pointer_canvas_add(ptr);
374         if (ptr->buffer_o_ptr && (ptr->buffer_o_ptr != ptr->o_ptr))
375           {
376              e_theme_edje_object_set(ptr->buffer_o_ptr, "base/theme/pointer", cursor);
377              edje_object_part_swallow(ptr->buffer_o_ptr, "e.swallow.hotspot", ptr->buffer_o_hot);
378           }
379         return;
380      }
381    if (ptr->buffer_evas) _e_pointer_canvas_del(ptr);
382 #ifndef HAVE_WAYLAND_ONLY
383    if (!e_comp_util_has_x()) return;
384    Ecore_X_Cursor curs = 0;
385
386    if (!strcmp(ptr->type, "move"))
387      curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_FLEUR);
388 # if 0
389    else if (!strcmp(ptr->type, "resize"))
390      curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_SIZING);
391 # endif
392    else if (!strcmp(ptr->type, "resize_tl"))
393      curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_TOP_LEFT_CORNER);
394    else if (!strcmp(ptr->type, "resize_t"))
395      curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_TOP_SIDE);
396    else if (!strcmp(ptr->type, "resize_tr"))
397      curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_TOP_RIGHT_CORNER);
398    else if (!strcmp(ptr->type, "resize_r"))
399      curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_RIGHT_SIDE);
400    else if (!strcmp(ptr->type, "resize_br"))
401      curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_BOTTOM_RIGHT_CORNER);
402    else if (!strcmp(ptr->type, "resize_b"))
403      curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_BOTTOM_SIDE);
404    else if (!strcmp(ptr->type, "resize_bl"))
405      curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_BOTTOM_LEFT_CORNER);
406    else if (!strcmp(ptr->type, "resize_l"))
407      curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_LEFT_SIDE);
408    else if (!strcmp(ptr->type, "entry"))
409      curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_XTERM);
410    else if (!strcmp(ptr->type, "default"))
411      curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_LEFT_PTR);
412    else if (!strcmp(ptr->type, "plus"))
413      curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_PLUS);
414    else if (!strcmp(ptr->type, "hand"))
415      curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_HAND1);
416    else if (!strcmp(ptr->type, "rotate"))
417      curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_EXCHANGE);
418    else
419      {
420         WRN("Unknown pointer ptr->type: %s\n", ptr->type);
421         curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_ARROW);
422      }
423    if (!curs) WRN("X Cursor for %s is missing\n", ptr->type);
424    ecore_x_window_cursor_set(ptr->win, curs);
425    if (curs) ecore_x_cursor_free(curs);
426 #endif
427 }
428
429 static void 
430 _e_pointer_type_set(E_Pointer *ptr, const char *type)
431 {
432    /* check if pointer type is already set */
433    if (!e_util_strcmp(ptr->type, type)) return;
434
435    eina_stringshare_replace(&ptr->type, type);
436
437    /* don't show cursor if in hidden mode */
438    if (!e_config->show_cursor)
439      {
440         e_pointer_hide(ptr);
441         return;
442      }
443
444    if (ptr->e_cursor)
445      {
446         char cursor[1024];
447         int x = 0, y = 0;
448
449         if ((!ptr->buffer_evas) && ptr->win) _e_pointer_canvas_add(ptr);
450         _e_pointer_theme_buf(ptr, cursor);
451
452         /* try to set the edje object theme */
453         if (!e_theme_edje_object_set(ptr->o_ptr, "base/theme/pointer", cursor))
454           cursor[0] = 0;
455         _e_pointer_x11_setup(ptr, cursor);
456         if (!cursor[0]) return;
457
458         edje_object_part_geometry_get(ptr->o_ptr, "e.swallow.hotspot", 
459                                       &x, &y, NULL, NULL);
460         _e_pointer_hot_update(ptr, x, y);
461
462         if (ptr->canvas)
463           e_pointer_object_set(ptr, NULL, 0, 0);
464         else
465           evas_object_show(ptr->o_ptr);
466
467      }
468    else
469      _e_pointer_x11_setup(ptr, NULL);
470 }
471
472 EINTERN int 
473 e_pointer_init(void)
474 {
475    E_LIST_HANDLER_APPEND(_hdlrs, ECORE_EVENT_MOUSE_BUTTON_DOWN, 
476                          _e_pointer_cb_mouse_down, NULL);
477    E_LIST_HANDLER_APPEND(_hdlrs, ECORE_EVENT_MOUSE_BUTTON_UP, 
478                          _e_pointer_cb_mouse_up, NULL);
479    E_LIST_HANDLER_APPEND(_hdlrs, ECORE_EVENT_MOUSE_MOVE, 
480                          _e_pointer_cb_mouse_move, NULL);
481    E_LIST_HANDLER_APPEND(_hdlrs, ECORE_EVENT_MOUSE_WHEEL, 
482                          _e_pointer_cb_mouse_wheel, NULL);
483    _initted = EINA_TRUE;
484    return 1;
485 }
486
487 EINTERN int 
488 e_pointer_shutdown(void)
489 {
490    _initted = EINA_FALSE;
491    E_FREE_LIST(_hdlrs, ecore_event_handler_del);
492    return 1;
493 }
494
495 E_API E_Pointer *
496 e_pointer_window_new(Ecore_Window win, Eina_Bool filled)
497 {
498    E_Pointer *ptr = NULL;
499
500    EINA_SAFETY_ON_FALSE_RETURN_VAL(win, NULL);
501    if (!_initted) return NULL;
502
503    /* allocate space for new pointer */
504    if (!(ptr = E_OBJECT_ALLOC(E_Pointer, E_POINTER_TYPE, _e_pointer_cb_free)))
505      return NULL;
506
507    /* set default pointer properties */
508    ptr->w = ptr->h = e_config->cursor_size;
509    ptr->e_cursor = e_config->use_e_cursor;
510    ptr->win = win;
511    ptr->color = EINA_FALSE;
512    if (e_comp->pointer)
513      ptr->color = e_comp->pointer->color;
514
515    /* set pointer default type */
516    if (filled) e_pointer_type_push(ptr, ptr, "default");
517
518    /* append this pointer to the list */
519    _ptrs = eina_list_append(_ptrs, ptr);
520
521    return ptr;
522 }
523
524 E_API E_Pointer *
525 e_pointer_canvas_new(Ecore_Evas *ee, Eina_Bool filled)
526 {
527    E_Pointer *ptr = NULL;
528
529    EINA_SAFETY_ON_FALSE_RETURN_VAL(ee, NULL);
530    if (!_initted) return NULL;
531
532    /* allocate space for new pointer */
533    if (!(ptr = E_OBJECT_ALLOC(E_Pointer, E_POINTER_TYPE, _e_pointer_cb_free)))
534      return NULL;
535
536    /* set default pointer properties */
537    ptr->color = EINA_TRUE;
538    ptr->canvas = EINA_TRUE;
539    ptr->w = ptr->h = e_config->cursor_size;
540    ptr->e_cursor = e_config->use_e_cursor;
541
542    ptr->ee = ee;
543    ptr->evas = ecore_evas_get(ee);
544    _e_pointer_pointer_canvas_init(ptr, ptr->evas, &ptr->o_ptr, &ptr->o_hot);
545
546    /* set pointer default type */
547    if (filled) e_pointer_type_push(ptr, ptr, "default");
548
549      /* append this pointer to the list */
550    _ptrs = eina_list_append(_ptrs, ptr);
551
552    _e_pointer_active_handle(ptr);
553
554    return ptr;
555 }
556
557 E_API void 
558 e_pointers_size_set(int size)
559 {
560    Eina_List *l;
561    E_Pointer *ptr;
562
563    if (!e_config->show_cursor) return;
564
565    EINA_LIST_FOREACH(_ptrs, l, ptr)
566      {
567         if ((ptr->w == size) && (ptr->h == size)) continue;
568         if (ptr->buffer_evas)
569           _e_pointer_canvas_resize(ptr, size, size);
570         if (ptr->canvas)
571           {
572              ptr->w = size;
573              ptr->h = size;
574              evas_object_resize(ptr->o_ptr, size, size);
575           }
576      }
577 #ifndef HAVE_WAYLAND_ONLY
578    if (e_comp_util_has_x())
579      ecore_x_cursor_size_set(e_config->cursor_size * 3 / 4);
580 #endif
581 }
582
583 E_API void 
584 e_pointer_hide(E_Pointer *ptr)
585 {
586    EINA_SAFETY_ON_NULL_RETURN(ptr);
587
588    if (ptr->buffer_evas)
589      _e_pointer_canvas_del(ptr);
590    if (ptr->canvas)
591      evas_object_hide(ptr->o_ptr);
592 #ifndef HAVE_WAYLAND_ONLY
593    if (ptr->win)
594      ecore_x_window_cursor_set(ptr->win, 0);
595 #endif
596 }
597
598 E_API void 
599 e_pointer_type_push(E_Pointer *ptr, void *obj, const char *type)
600 {
601    E_Pointer_Stack *stack;
602
603    EINA_SAFETY_ON_NULL_RETURN(ptr);
604
605    _e_pointer_type_set(ptr, type);
606
607    if (!(stack = E_NEW(E_Pointer_Stack, 1))) return;
608    stack->type = eina_stringshare_ref(ptr->type);
609    stack->obj = obj;
610    ptr->stack = eina_list_prepend(ptr->stack, stack);
611 }
612
613 E_API void 
614 e_pointer_type_pop(E_Pointer *ptr, void *obj, const char *type)
615 {
616    Eina_List *l, *ll;
617    E_Pointer_Stack *stack;
618
619    EINA_SAFETY_ON_NULL_RETURN(ptr);
620
621    EINA_LIST_FOREACH_SAFE(ptr->stack, l, ll, stack)
622      {
623         if ((stack->obj == obj) && 
624             ((!type) || (!e_util_strcmp(stack->type, type))))
625           {
626              _e_pointer_stack_free(stack);
627              ptr->stack = eina_list_remove_list(ptr->stack, l);
628              if (type) break;
629           }
630      }
631
632    if (!ptr->stack)
633      {
634         e_pointer_hide(ptr);
635         eina_stringshare_replace(&ptr->type, NULL);
636         return;
637      }
638
639    if (!(stack = eina_list_data_get(ptr->stack))) return;
640
641    _e_pointer_type_set(ptr, stack->type);
642
643    eina_stringshare_refplace(&ptr->type, stack->type);
644 }
645
646 E_API void 
647 e_pointer_mode_push(void *obj, E_Pointer_Mode mode)
648 {
649    E_Client *ec;
650    Evas_Object *o;
651
652    EINA_SAFETY_ON_NULL_RETURN(e_comp->pointer);
653
654    ecore_evas_cursor_get(e_comp->pointer->ee, &o, NULL, NULL, NULL);
655    if ((o != e_comp->pointer->o_ptr) && (ec = e_comp_object_client_get(o)))
656      return;
657
658    switch (mode)
659      {
660       case E_POINTER_RESIZE_TL:
661         e_pointer_type_push(e_comp->pointer, obj, "resize_tl");
662         break;
663
664       case E_POINTER_RESIZE_T:
665         e_pointer_type_push(e_comp->pointer, obj, "resize_t");
666         break;
667
668       case E_POINTER_RESIZE_TR:
669         e_pointer_type_push(e_comp->pointer, obj, "resize_tr");
670         break;
671
672       case E_POINTER_RESIZE_R:
673         e_pointer_type_push(e_comp->pointer, obj, "resize_r");
674         break;
675
676       case E_POINTER_RESIZE_BR:
677         e_pointer_type_push(e_comp->pointer, obj, "resize_br");
678         break;
679
680       case E_POINTER_RESIZE_B:
681         e_pointer_type_push(e_comp->pointer, obj, "resize_b");
682         break;
683
684       case E_POINTER_RESIZE_BL:
685         e_pointer_type_push(e_comp->pointer, obj, "resize_bl");
686         break;
687
688       case E_POINTER_RESIZE_L:
689         e_pointer_type_push(e_comp->pointer, obj, "resize_l");
690         break;
691
692       case E_POINTER_MOVE:
693         e_pointer_type_push(e_comp->pointer, obj, "move");
694         break;
695
696       default: break;
697      }
698 }
699
700 E_API void 
701 e_pointer_mode_pop(void *obj, E_Pointer_Mode mode)
702 {
703    switch (mode)
704      {
705       case E_POINTER_RESIZE_TL:
706         e_pointer_type_pop(e_comp->pointer, obj, "resize_tl");
707         break;
708
709       case E_POINTER_RESIZE_T:
710         e_pointer_type_pop(e_comp->pointer, obj, "resize_t");
711         break;
712
713       case E_POINTER_RESIZE_TR:
714         e_pointer_type_pop(e_comp->pointer, obj, "resize_tr");
715         break;
716
717       case E_POINTER_RESIZE_R:
718         e_pointer_type_pop(e_comp->pointer, obj, "resize_r");
719         break;
720
721       case E_POINTER_RESIZE_BR:
722         e_pointer_type_pop(e_comp->pointer, obj, "resize_br");
723         break;
724
725       case E_POINTER_RESIZE_B:
726         e_pointer_type_pop(e_comp->pointer, obj, "resize_b");
727         break;
728
729       case E_POINTER_RESIZE_BL:
730         e_pointer_type_pop(e_comp->pointer, obj, "resize_bl");
731         break;
732
733       case E_POINTER_RESIZE_L:
734         e_pointer_type_pop(e_comp->pointer, obj, "resize_l");
735         break;
736
737       case E_POINTER_MOVE:
738         e_pointer_type_pop(e_comp->pointer, obj, "move");
739         break;
740
741       default: break;
742      }
743 }
744
745 E_API void 
746 e_pointer_idler_before(void)
747 {
748    Eina_List *l;
749    E_Pointer *ptr;
750
751    if (!e_config->show_cursor) return;
752
753    EINA_LIST_FOREACH(_ptrs, l, ptr)
754      {
755         if ((!ptr->e_cursor) || (!ptr->buffer_evas)) continue;
756
757         if (ptr->hot.update)
758           _e_pointer_type_set(ptr, ptr->type);
759  
760         if (ptr->buffer_evas)
761           {
762              Eina_List *updates;
763
764              if ((updates = evas_render_updates(ptr->buffer_evas)))
765                {
766 #ifndef HAVE_WAYLAND_ONLY
767                   Ecore_X_Cursor cur;
768
769                   cur = ecore_x_cursor_new(ptr->win, ptr->pixels, ptr->w, 
770                                            ptr->h, ptr->hot.x, ptr->hot.y);
771                   ecore_x_window_cursor_set(ptr->win, cur);
772                   ecore_x_cursor_free(cur);
773 #endif
774                   evas_render_updates_free(updates);
775                }
776           }
777
778         ptr->hot.update = EINA_FALSE;
779      }
780 }
781
782 E_API void
783 e_pointer_object_set(E_Pointer *ptr, Evas_Object *obj, int x, int y)
784 {
785    Evas_Object *o;
786    E_Client *ec;
787
788    EINA_SAFETY_ON_NULL_RETURN(ptr);
789
790    /* don't show cursor if in hidden mode */
791    if (!e_config->show_cursor)
792      {
793         if (obj) evas_object_hide(obj);
794         return;
795      }
796
797    ecore_evas_cursor_get(ptr->ee, &o, NULL, NULL, NULL);
798    if (o)
799      {
800         if (o == obj)
801           {
802              ecore_evas_object_cursor_set(ptr->ee, obj, E_LAYER_MAX - 1, x, y);
803              return;
804           }
805         ec = e_comp_object_client_get(o);
806         if (ec)
807           ec->hidden = 1;
808      }
809    ecore_evas_cursor_unset(ptr->ee);
810
811    if (obj)
812      {
813         ec = e_comp_object_client_get(obj);
814         if (ec)
815           ec->hidden = 1;
816         ecore_evas_object_cursor_set(ptr->ee, obj, E_LAYER_MAX - 1, x, y);
817      }
818    else if (ptr->o_ptr)
819      ecore_evas_object_cursor_set(ptr->ee, ptr->o_ptr, E_LAYER_MAX - 1, ptr->hot.x, ptr->hot.y);
820 }
821
822 E_API void
823 e_pointer_window_add(E_Pointer *ptr, Ecore_Window win)
824 {
825    char buf[1024];
826
827    ptr->win = win;
828    _e_pointer_theme_buf(ptr, buf);
829    _e_pointer_x11_setup(ptr, buf);
830 }
831
832 E_API Eina_Bool
833 e_pointer_is_hidden(E_Pointer *ptr)
834 {
835    Evas_Object *o;
836
837    EINA_SAFETY_ON_NULL_RETURN(ptr);
838
839    if (!e_config->show_cursor)
840      return EINA_TRUE;
841
842    ecore_evas_cursor_get(ptr->ee, &o, NULL, NULL, NULL);
843    if (o)
844      return EINA_FALSE;
845    else
846      {
847         if (ptr->o_ptr && (evas_object_visible_get(ptr->o_ptr)))
848           return EINA_FALSE;
849      }
850    return EINA_TRUE;
851 }