create rotation job and EAPI e_border_rotation_set
[platform/core/uifw/e17.git] / src / bin / e_pointer.c
1 #include "e.h"
2
3 /*
4  * TODO
5  * - Make fallback user controlable.
6  * - Define the allowed signals?
7  */
8
9 typedef struct _E_Pointer_Stack E_Pointer_Stack;
10
11 struct _E_Pointer_Stack
12 {
13    void       *obj;
14    const char *type;
15 };
16
17 static Eina_List *_e_pointers = NULL;
18 static Eina_List *handlers = NULL;
19
20 static void _e_pointer_canvas_add(E_Pointer *p);
21 static void _e_pointer_canvas_del(E_Pointer *p);
22 static void _e_pointer_cb_move(void        *data,
23                                Evas        *e __UNUSED__,
24                                Evas_Object *obj __UNUSED__,
25                                void        *event_info);
26 static void      _e_pointer_free(E_Pointer *p);
27 static void      _e_pointer_stack_free(E_Pointer_Stack *elem);
28 static void      _e_pointer_type_set(E_Pointer  *p,
29                                      const char *type);
30 static void      _e_pointer_active_handle(E_Pointer *p);
31
32 static Eina_Bool _e_pointer_cb_mouse_down(void *data,
33                                           int   type,
34                                           void *event);
35 static Eina_Bool _e_pointer_cb_mouse_up(void *data,
36                                         int   type,
37                                         void *event);
38 static Eina_Bool _e_pointer_cb_mouse_move(void *data,
39                                           int   type,
40                                           void *event);
41 static Eina_Bool _e_pointer_cb_mouse_wheel(void *data,
42                                            int   type,
43                                            void *event);
44 static Eina_Bool _e_pointer_cb_idle_timer_pre(void *data);
45 static Eina_Bool _e_pointer_cb_idle_timer_wait(void *data);
46 static Eina_Bool _e_pointer_cb_idle_poller(void *data);
47
48 /* externally accessible functions */
49 EINTERN int
50 e_pointer_init(void)
51 {
52    handlers =
53      eina_list_append(handlers,
54                       ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN,
55                                               _e_pointer_cb_mouse_down, NULL));
56    handlers =
57      eina_list_append(handlers,
58                       ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP,
59                                               _e_pointer_cb_mouse_up, NULL));
60    handlers =
61      eina_list_append(handlers,
62                       ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE,
63                                               _e_pointer_cb_mouse_move, NULL));
64    handlers =
65      eina_list_append(handlers,
66                       ecore_event_handler_add(ECORE_EVENT_MOUSE_WHEEL,
67                                               _e_pointer_cb_mouse_wheel, NULL));
68    return 1;
69 }
70
71 EINTERN int
72 e_pointer_shutdown(void)
73 {
74    E_FREE_LIST(handlers, ecore_event_handler_del);
75    return 1;
76 }
77
78 EAPI E_Pointer *
79 e_pointer_window_new(Ecore_X_Window win,
80                      int            filled)
81 {
82    E_Pointer *p = NULL;
83
84    p = E_OBJECT_ALLOC(E_Pointer, E_POINTER_TYPE, _e_pointer_free);
85    if (!p) return NULL;
86
87    p->e_cursor = e_config->use_e_cursor;
88    p->win = win;
89    p->color = 0;
90    if (e_config->use_e_cursor)
91      if (ecore_x_cursor_color_supported_get()) p->color = 1;
92
93    ecore_x_cursor_size_set(e_config->cursor_size * 3 / 4);
94    if (filled) e_pointer_type_push(p, p, "default");
95    _e_pointers = eina_list_append(_e_pointers, p);
96    return p;
97 }
98
99 EAPI void
100 e_pointers_size_set(int size)
101 {
102    Eina_List *l;
103    E_Pointer *p;
104
105    if (!e_config->show_cursor) return;
106    EINA_LIST_FOREACH(_e_pointers, l, p)
107      {
108         Evas_Engine_Info_Buffer *einfo;
109
110         if (p->evas)
111           {
112              p->w = p->h = size;
113              evas_output_size_set(p->evas, p->w, p->h);
114              evas_output_viewport_set(p->evas, 0, 0, p->w, p->h);
115
116              p->pixels = realloc(p->pixels, p->w * p->h * sizeof(int));
117
118              einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(p->evas);
119              if (einfo)
120                {
121                   einfo->info.dest_buffer = p->pixels;
122                   einfo->info.dest_buffer_row_bytes = p->w * sizeof(int);
123                   evas_engine_info_set(p->evas, (Evas_Engine_Info *)einfo);
124                }
125
126              evas_object_move(p->pointer_object, 0, 0);
127              evas_object_resize(p->pointer_object, p->w, p->h);
128           }
129         else
130           {
131              const char *type;
132
133              ecore_x_cursor_size_set(e_config->cursor_size * 3 / 4);
134              type = p->type;
135              if (type)
136                {
137                   p->type = NULL;
138                   _e_pointer_type_set(p, type);
139                   eina_stringshare_del(type);
140                }
141           }
142      }
143 }
144
145 EAPI void
146 e_pointer_hide(E_Pointer *p)
147 {
148    if (!p) return;
149    if (p->win) ecore_x_window_cursor_set(p->win, 0);
150    if (p->evas) _e_pointer_canvas_del(p);
151 }
152
153 EAPI void
154 e_pointer_type_push(E_Pointer  *p,
155                     void       *obj,
156                     const char *type)
157 {
158    E_Pointer_Stack *stack;
159
160    if (!p) return;
161    p->e_cursor = e_config->use_e_cursor;
162
163    _e_pointer_type_set(p, type);
164
165    p->obj = obj;
166
167    stack = E_NEW(E_Pointer_Stack, 1);
168    if (stack)
169      {
170         stack->type = eina_stringshare_add(p->type);
171         stack->obj = p->obj;
172         p->stack = eina_list_prepend(p->stack, stack);
173      }
174 }
175
176 EAPI void
177 e_pointer_type_pop(E_Pointer  *p,
178                    void       *obj,
179                    const char *type)
180 {
181    Eina_List *l;
182    E_Pointer_Stack *stack;
183
184    if (!p) return;
185    EINA_LIST_FOREACH(p->stack, l, stack)
186      {
187         if ((stack->obj == obj) && ((!type) || (!strcmp(stack->type, type))))
188           {
189              _e_pointer_stack_free(stack);
190              p->stack = eina_list_remove_list(p->stack, l);
191              if (type) break;
192           }
193      }
194
195    if (!p->stack)
196      {
197         if (p->evas) _e_pointer_canvas_del(p);
198         ecore_x_window_cursor_set(p->win, 0);
199         if (p->type) eina_stringshare_del(p->type);
200         p->type = NULL;
201         return;
202      }
203
204    stack = eina_list_data_get(p->stack);
205    _e_pointer_type_set(p, stack->type);
206
207    if (p->type) eina_stringshare_del(p->type);
208    p->type = eina_stringshare_add(stack->type);
209    p->obj = stack->obj;
210
211    /* try the default cursor next time */
212    p->e_cursor = e_config->use_e_cursor;
213 }
214
215 EAPI void
216 e_pointer_idler_before(void)
217 {
218    Eina_List *l;
219    E_Pointer *p;
220
221    if (!e_config->show_cursor) return;
222    EINA_LIST_FOREACH(_e_pointers, l, p)
223      {
224         Eina_List *updates;
225
226         if (!p->e_cursor) continue;
227         if (!p->evas) continue;
228
229         updates = evas_render_updates(p->evas);
230         if ((updates) || (p->hot.update))
231           {
232              Ecore_X_Cursor cur;
233
234              cur = ecore_x_cursor_new(p->win, p->pixels, p->w, p->h,
235                                       p->hot.x, p->hot.y);
236              ecore_x_window_cursor_set(p->win, cur);
237              ecore_x_cursor_free(cur);
238              evas_render_updates_free(updates);
239              p->hot.update = 0;
240           }
241      }
242 }
243
244 /* local subsystem functions */
245 static void
246 _e_pointer_canvas_add(E_Pointer *p)
247 {
248    Evas_Engine_Info_Buffer *einfo;
249    Evas_Object *o;
250    int rmethod;
251
252    if (!p) return;
253    p->w = e_config->cursor_size;
254    p->h = e_config->cursor_size;
255
256    /* create evas */
257    p->evas = evas_new();
258    if (!p->evas)
259      {
260         e_object_del(E_OBJECT(p));
261         return;
262      }
263    rmethod = evas_render_method_lookup("buffer");
264    evas_output_method_set(p->evas, rmethod);
265    evas_output_size_set(p->evas, p->w, p->h);
266    evas_output_viewport_set(p->evas, 0, 0, p->w, p->h);
267
268    p->pixels = malloc(p->w * p->h * sizeof(int));
269    if (!p->pixels)
270      {
271         _e_pointer_canvas_del(p);
272         return;
273      }
274    einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(p->evas);
275    if (!einfo)
276      {
277         _e_pointer_canvas_del(p);
278         return;
279      }
280    einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32;
281    einfo->info.dest_buffer = p->pixels;
282    einfo->info.dest_buffer_row_bytes = p->w * sizeof(int);
283    einfo->info.use_color_key = 0;
284    einfo->info.alpha_threshold = 0;
285    einfo->info.func.new_update_region = NULL;
286    einfo->info.func.free_update_region = NULL;
287    evas_engine_info_set(p->evas, (Evas_Engine_Info *)einfo);
288
289    /* set the pointer edje */
290    o = edje_object_add(p->evas);
291    p->pointer_object = o;
292    /* Create the hotspot object */
293    o = evas_object_rectangle_add(p->evas);
294    evas_object_color_set(o, 0, 0, 0, 0);
295    p->hot_object = o;
296    evas_object_event_callback_add(o, EVAS_CALLBACK_MOVE,
297                                   _e_pointer_cb_move, p);
298    /* init edje */
299    evas_object_move(p->pointer_object, 0, 0);
300    evas_object_resize(p->pointer_object, p->w, p->h);
301    evas_object_show(p->pointer_object);
302 }
303
304 static void
305 _e_pointer_canvas_del(E_Pointer *p)
306 {
307    if (!p) return;
308    if (p->pointer_object) evas_object_del(p->pointer_object);
309    if (p->hot_object) evas_object_del(p->hot_object);
310    if (p->evas) evas_free(p->evas);
311    if (p->pixels) free(p->pixels);
312    p->pointer_object = NULL;
313    p->hot_object = NULL;
314    p->evas = NULL;
315    p->pixels = NULL;
316 }
317
318 static void
319 _e_pointer_cb_move(void        *data,
320                    Evas        *e __UNUSED__,
321                    Evas_Object *obj __UNUSED__,
322                    void        *event_info __UNUSED__)
323 {
324    E_Pointer *p;
325    Evas_Coord x, y;
326
327    if (!e_config->show_cursor) return;
328
329    if (!(p = data)) return;
330    if (!p->e_cursor) return;
331    edje_object_part_geometry_get(p->pointer_object, "e.swallow.hotspot",
332                                  &x, &y, NULL, NULL);
333    if ((p->hot.x != x) || (p->hot.y != y))
334      {
335         p->hot.x = x;
336         p->hot.y = y;
337         p->hot.update = 1;
338      }
339 }
340
341 static void
342 _e_pointer_free(E_Pointer *p)
343 {
344    if (!p) return;
345    _e_pointers = eina_list_remove(_e_pointers, p);
346
347    _e_pointer_canvas_del(p);
348
349    E_FREE_LIST(p->stack, _e_pointer_stack_free);
350
351    if (p->type) eina_stringshare_del(p->type);
352    if (p->idle_timer) ecore_timer_del(p->idle_timer);
353    if (p->idle_poller) ecore_poller_del(p->idle_poller);
354
355    p->type = NULL;
356    p->idle_timer = NULL;
357    p->idle_poller = NULL;
358    E_FREE(p);
359 }
360
361 static void
362 _e_pointer_stack_free(E_Pointer_Stack *elem)
363 {
364    if (elem->type) eina_stringshare_del(elem->type);
365    free(elem);
366 }
367
368 static void
369 _e_pointer_type_set(E_Pointer  *p,
370                     const char *type)
371 {
372    if (!p) return;
373
374    /* Check if this pointer is already set */
375    if ((p->type) && (!strcmp(p->type, type))) return;
376
377    eina_stringshare_replace(&p->type, type);
378
379    /* Do not set type if in "hidden mode" */
380    if (!e_config->show_cursor)
381      {
382         ecore_x_window_cursor_set(p->win, 0);
383         return;
384      }
385
386    if (p->e_cursor)
387      {
388         char cursor[1024];
389         Evas_Coord x, y;
390
391         if (!p->evas) _e_pointer_canvas_add(p);
392         if (p->color)
393           snprintf(cursor, sizeof(cursor),
394                    "e/pointer/enlightenment/%s/color", type);
395         else
396           snprintf(cursor, sizeof(cursor),
397                    "e/pointer/enlightenment/%s/mono", type);
398         if (!e_theme_edje_object_set(p->pointer_object,
399                                      "base/theme/pointer", cursor))
400           goto fallback;
401         edje_object_part_swallow(p->pointer_object, "e.swallow.hotspot",
402                                  p->hot_object);
403         edje_object_part_geometry_get(p->pointer_object, "e.swallow.hotspot",
404                                       &x, &y, NULL, NULL);
405         if ((p->hot.x != x) || (p->hot.y != y))
406           {
407              p->hot.x = x;
408              p->hot.y = y;
409           }
410         p->hot.update = 1;
411         return;
412      }
413 fallback:
414    {
415       Ecore_X_Cursor cursor = 0;
416
417       if (p->evas) _e_pointer_canvas_del(p);
418       if (!strcmp(type, "move"))
419         cursor = ecore_x_cursor_shape_get(ECORE_X_CURSOR_FLEUR);
420 #if 0
421       else if (!strcmp(type, "resize"))
422         cursor = ecore_x_cursor_shape_get(ECORE_X_CURSOR_SIZING);
423 #endif
424       else if (!strcmp(type, "resize_tl"))
425         cursor = ecore_x_cursor_shape_get(ECORE_X_CURSOR_TOP_LEFT_CORNER);
426       else if (!strcmp(type, "resize_t"))
427         cursor = ecore_x_cursor_shape_get(ECORE_X_CURSOR_TOP_SIDE);
428       else if (!strcmp(type, "resize_tr"))
429         cursor = ecore_x_cursor_shape_get(ECORE_X_CURSOR_TOP_RIGHT_CORNER);
430       else if (!strcmp(type, "resize_r"))
431         cursor = ecore_x_cursor_shape_get(ECORE_X_CURSOR_RIGHT_SIDE);
432       else if (!strcmp(type, "resize_br"))
433         cursor = ecore_x_cursor_shape_get(ECORE_X_CURSOR_BOTTOM_RIGHT_CORNER);
434       else if (!strcmp(type, "resize_b"))
435         cursor = ecore_x_cursor_shape_get(ECORE_X_CURSOR_BOTTOM_SIDE);
436       else if (!strcmp(type, "resize_bl"))
437         cursor = ecore_x_cursor_shape_get(ECORE_X_CURSOR_BOTTOM_LEFT_CORNER);
438       else if (!strcmp(type, "resize_l"))
439         cursor = ecore_x_cursor_shape_get(ECORE_X_CURSOR_LEFT_SIDE);
440       else if (!strcmp(type, "entry"))
441         cursor = ecore_x_cursor_shape_get(ECORE_X_CURSOR_XTERM);
442       else if (!strcmp(type, "default"))
443         cursor = ecore_x_cursor_shape_get(ECORE_X_CURSOR_LEFT_PTR);
444       else if (!strcmp(type, "plus"))
445         cursor = ecore_x_cursor_shape_get(ECORE_X_CURSOR_PLUS);
446       else if (!strcmp(type, "hand"))
447         cursor = ecore_x_cursor_shape_get(ECORE_X_CURSOR_HAND1);
448       else
449         {
450            printf("Unknown pointer type: %s\n", type);
451            cursor = ecore_x_cursor_shape_get(ECORE_X_CURSOR_ARROW);
452         }
453       if (!cursor) printf("X Cursor for %s is missing\n", type);
454       ecore_x_window_cursor_set(p->win, cursor);
455       if (cursor) ecore_x_cursor_free(cursor);
456    }
457 }
458
459 static void
460 _e_pointer_active_handle(E_Pointer *p)
461 {
462    if (!p) return;
463
464    /* we got some mouse event - if there was an idle timer emit an active
465     * signal as we WERE idle, NOW we are active */
466    if (p->idle_timer)
467      {
468         ecore_timer_del(p->idle_timer);
469         p->idle_timer = NULL;
470      }
471    if (p->idle_poller)
472      {
473         ecore_poller_del(p->idle_poller);
474         p->idle_poller = NULL;
475      }
476    if (p->idle)
477      {
478         if (p->pointer_object)
479           edje_object_signal_emit(p->pointer_object, "e,state,mouse,active", "e");
480         p->idle = 0;
481      }
482    if (e_powersave_mode_get() >= E_POWERSAVE_MODE_MEDIUM) return;
483    /* and schedule a pre-idle check in 1 second if no more events happen */
484    if (!e_config->idle_cursor) return;
485    p->idle_timer = ecore_timer_loop_add(1.0, _e_pointer_cb_idle_timer_pre, p);
486 }
487
488 static Eina_Bool
489 _e_pointer_cb_mouse_down(void *data __UNUSED__,
490                          int   type __UNUSED__,
491                          void *event __UNUSED__)
492 {
493    Eina_List *l;
494    E_Pointer *p;
495
496    EINA_LIST_FOREACH(_e_pointers, l, p)
497      {
498         _e_pointer_active_handle(p);
499         if (e_powersave_mode_get() < E_POWERSAVE_MODE_EXTREME)
500           {
501              if (p->pointer_object)
502                edje_object_signal_emit(p->pointer_object,
503                                        "e,action,mouse,down", "e");
504           }
505      }
506    return ECORE_CALLBACK_PASS_ON;
507 }
508
509 static Eina_Bool
510 _e_pointer_cb_mouse_up(void *data __UNUSED__,
511                        int   type __UNUSED__,
512                        void *event __UNUSED__)
513 {
514    Eina_List *l;
515    E_Pointer *p;
516
517    EINA_LIST_FOREACH(_e_pointers, l, p)
518      {
519         _e_pointer_active_handle(p);
520         if (e_powersave_mode_get() < E_POWERSAVE_MODE_EXTREME)
521           {
522              if (p->pointer_object)
523                edje_object_signal_emit(p->pointer_object,
524                                        "e,action,mouse,up", "e");
525           }
526      }
527    return ECORE_CALLBACK_PASS_ON;
528 }
529
530 static Eina_Bool
531 _e_pointer_cb_mouse_move(void *data __UNUSED__,
532                          int   type __UNUSED__,
533                          void *event __UNUSED__)
534 {
535    Eina_List *l;
536    E_Pointer *p;
537
538    EINA_LIST_FOREACH(_e_pointers, l, p)
539      {
540         _e_pointer_active_handle(p);
541         if (e_powersave_mode_get() < E_POWERSAVE_MODE_HIGH)
542           {
543              if (p->pointer_object)
544                edje_object_signal_emit(p->pointer_object,
545                                        "e,action,mouse,move", "e");
546           }
547      }
548    return ECORE_CALLBACK_PASS_ON;
549 }
550
551 static Eina_Bool
552 _e_pointer_cb_mouse_wheel(void *data __UNUSED__,
553                           int   type __UNUSED__,
554                           void *event __UNUSED__)
555 {
556    Eina_List *l;
557    E_Pointer *p;
558
559    EINA_LIST_FOREACH(_e_pointers, l, p)
560      {
561         _e_pointer_active_handle(p);
562         if (e_powersave_mode_get() < E_POWERSAVE_MODE_EXTREME)
563           {
564              if (p->pointer_object)
565                edje_object_signal_emit(p->pointer_object,
566                                        "e,action,mouse,wheel", "e");
567           }
568      }
569    return ECORE_CALLBACK_PASS_ON;
570 }
571
572 static Eina_Bool
573 _e_pointer_cb_idle_timer_pre(void *data)
574 {
575    E_Pointer *p;
576    int x, y;
577
578    if (!(p = data)) return ECORE_CALLBACK_RENEW;
579    ecore_x_pointer_xy_get(p->win, &x, &y);
580    p->x = x;
581    p->y = y;
582    p->idle_timer = ecore_timer_loop_add(4.0, _e_pointer_cb_idle_timer_wait, p);
583    return ECORE_CALLBACK_CANCEL;
584 }
585
586 static Eina_Bool
587 _e_pointer_cb_idle_timer_wait(void *data)
588 {
589    E_Pointer *p;
590
591    if (!(p = data)) return ECORE_CALLBACK_RENEW;
592    if ((e_powersave_mode_get() >= E_POWERSAVE_MODE_MEDIUM) ||
593        (!e_config->idle_cursor))
594      {
595         if (p->idle_poller) ecore_poller_del(p->idle_poller);
596         p->idle_poller = NULL;
597         p->idle_timer = NULL;
598         return ECORE_CALLBACK_CANCEL;
599      }
600    if (!p->idle_poller)
601      p->idle_poller = ecore_poller_add(ECORE_POLLER_CORE, 64,
602                                        _e_pointer_cb_idle_poller, p);
603    p->idle_timer = NULL;
604    return ECORE_CALLBACK_CANCEL;
605 }
606
607 static Eina_Bool
608 _e_pointer_cb_idle_poller(void *data)
609 {
610    E_Pointer *p;
611    int x, y;
612
613    if (!(p = data)) return ECORE_CALLBACK_RENEW;
614    if ((e_powersave_mode_get() >= E_POWERSAVE_MODE_MEDIUM) ||
615        (!e_config->idle_cursor))
616      {
617         p->idle_poller = NULL;
618         return ECORE_CALLBACK_CANCEL;
619      }
620    /* check if pointer actually moved since the 1 second post-mouse move idle
621     * pre-timer that fetches the position */
622    ecore_x_pointer_xy_get(p->win, &x, &y);
623    if ((x != p->x) || (y != p->y))
624      {
625         /* it moved - so we are not idle yet - record position and wait
626          * 4 secons more */
627           p->x = x;
628           p->y = y;
629           if (p->idle)
630             {
631                if (p->pointer_object)
632                  edje_object_signal_emit(p->pointer_object,
633                                          "e,state,mouse,active", "e");
634                p->idle = 0;
635             }
636           /* use poller to check from now on */
637           return ECORE_CALLBACK_RENEW;
638      }
639    /* we are idle - report it if not idle before */
640    if (!p->idle)
641      {
642         if (p->pointer_object)
643           edje_object_signal_emit(p->pointer_object, "e,state,mouse,idle", "e");
644         p->idle = 1;
645      }
646    return ECORE_CALLBACK_RENEW;
647 }