1 #include <Elementary.h>
2 #include <Elementary_Cursor.h>
5 #ifdef HAVE_ELEMENTARY_X
7 #include <Ecore_X_Cursor.h>
11 * @defgroup Cursors Cursors
13 * The Cursor is an internal smart object used to customize the
14 * cursor displayed over objects (or widgets).
15 * It can use default X cursors (if using X), or cursors from a
19 #define _cursor_key "_elm_cursor"
24 #ifdef HAVE_ELEMENTARY_X
29 #ifdef HAVE_ELEMENTARY_X
30 #define CURSOR(_name, _xid) \
33 #define CURSOR(_name, _xid) \
37 /* Please keep order in sync with Ecore_X_Cursor.h values! */
38 struct _Cursor_Id _cursors[] =
40 CURSOR(ELM_CURSOR_X , ECORE_X_CURSOR_X ),
41 CURSOR(ELM_CURSOR_ARROW , ECORE_X_CURSOR_ARROW ),
42 CURSOR(ELM_CURSOR_BASED_ARROW_DOWN , ECORE_X_CURSOR_BASED_ARROW_DOWN ),
43 CURSOR(ELM_CURSOR_BASED_ARROW_UP , ECORE_X_CURSOR_UP ),
44 CURSOR(ELM_CURSOR_BOAT , ECORE_X_CURSOR_BOAT ),
45 CURSOR(ELM_CURSOR_BOGOSITY , ECORE_X_CURSOR_BOGOSITY ),
46 CURSOR(ELM_CURSOR_BOTTOM_LEFT_CORNER , ECORE_X_CURSOR_BOTTOM_LEFT_CORNER ),
47 CURSOR(ELM_CURSOR_BOTTOM_RIGHT_CORNER, ECORE_X_CURSOR_BOTTOM_RIGHT_CORNER),
48 CURSOR(ELM_CURSOR_BOTTOM_SIDE , ECORE_X_CURSOR_BOTTOM_SIDE ),
49 CURSOR(ELM_CURSOR_BOTTOM_TEE , ECORE_X_CURSOR_BOTTOM_TEE ),
50 CURSOR(ELM_CURSOR_BOX_SPIRAL , ECORE_X_CURSOR_BOX_SPIRAL ),
51 CURSOR(ELM_CURSOR_CENTER_PTR , ECORE_X_CURSOR_CENTER_PTR ),
52 CURSOR(ELM_CURSOR_CIRCLE , ECORE_X_CURSOR_CIRCLE ),
53 CURSOR(ELM_CURSOR_CLOCK , ECORE_X_CURSOR_CLOCK ),
54 CURSOR(ELM_CURSOR_COFFEE_MUG , ECORE_X_CURSOR_COFFEE_MUG ),
55 CURSOR(ELM_CURSOR_CROSS , ECORE_X_CURSOR_CROSS ),
56 CURSOR(ELM_CURSOR_CROSS_REVERSE , ECORE_X_CURSOR_CROSS_REVERSE ),
57 CURSOR(ELM_CURSOR_CROSSHAIR , ECORE_X_CURSOR_CROSSHAIR ),
58 CURSOR(ELM_CURSOR_DIAMOND_CROSS , ECORE_X_CURSOR_DIAMOND_CROSS ),
59 CURSOR(ELM_CURSOR_DOT , ECORE_X_CURSOR_DOT ),
60 CURSOR(ELM_CURSOR_DOT_BOX_MASK , ECORE_X_CURSOR_DOT_BOX_MASK ),
61 CURSOR(ELM_CURSOR_DOUBLE_ARROW , ECORE_X_CURSOR_DOUBLE_ARROW ),
62 CURSOR(ELM_CURSOR_DRAFT_LARGE , ECORE_X_CURSOR_DRAFT_LARGE ),
63 CURSOR(ELM_CURSOR_DRAFT_SMALL , ECORE_X_CURSOR_DRAFT_SMALL ),
64 CURSOR(ELM_CURSOR_DRAPED_BOX , ECORE_X_CURSOR_DRAPED_BOX ),
65 CURSOR(ELM_CURSOR_EXCHANGE , ECORE_X_CURSOR_EXCHANGE ),
66 CURSOR(ELM_CURSOR_FLEUR , ECORE_X_CURSOR_FLEUR ),
67 CURSOR(ELM_CURSOR_GOBBLER , ECORE_X_CURSOR_GOBBLER ),
68 CURSOR(ELM_CURSOR_GUMBY , ECORE_X_CURSOR_GUMBY ),
69 CURSOR(ELM_CURSOR_HAND1 , ECORE_X_CURSOR_HAND1 ),
70 CURSOR(ELM_CURSOR_HAND2 , ECORE_X_CURSOR_HAND2 ),
71 CURSOR(ELM_CURSOR_HEART , ECORE_X_CURSOR_HEART ),
72 CURSOR(ELM_CURSOR_ICON , ECORE_X_CURSOR_ICON ),
73 CURSOR(ELM_CURSOR_IRON_CROSS , ECORE_X_CURSOR_IRON_CROSS ),
74 CURSOR(ELM_CURSOR_LEFT_PTR , ECORE_X_CURSOR_LEFT_PTR ),
75 CURSOR(ELM_CURSOR_LEFT_SIDE , ECORE_X_CURSOR_LEFT_SIDE ),
76 CURSOR(ELM_CURSOR_LEFT_TEE , ECORE_X_CURSOR_LEFT_TEE ),
77 CURSOR(ELM_CURSOR_LEFTBUTTON , ECORE_X_CURSOR_LEFTBUTTON ),
78 CURSOR(ELM_CURSOR_LL_ANGLE , ECORE_X_CURSOR_LL_ANGLE ),
79 CURSOR(ELM_CURSOR_LR_ANGLE , ECORE_X_CURSOR_LR_ANGLE ),
80 CURSOR(ELM_CURSOR_MAN , ECORE_X_CURSOR_MAN ),
81 CURSOR(ELM_CURSOR_MIDDLEBUTTON , ECORE_X_CURSOR_MIDDLEBUTTON ),
82 CURSOR(ELM_CURSOR_MOUSE , ECORE_X_CURSOR_MOUSE ),
83 CURSOR(ELM_CURSOR_PENCIL , ECORE_X_CURSOR_PENCIL ),
84 CURSOR(ELM_CURSOR_PIRATE , ECORE_X_CURSOR_PIRATE ),
85 CURSOR(ELM_CURSOR_PLUS , ECORE_X_CURSOR_PLUS ),
86 CURSOR(ELM_CURSOR_QUESTION_ARROW , ECORE_X_CURSOR_QUESTION_ARROW ),
87 CURSOR(ELM_CURSOR_RIGHT_PTR , ECORE_X_CURSOR_RIGHT_PTR ),
88 CURSOR(ELM_CURSOR_RIGHT_SIDE , ECORE_X_CURSOR_RIGHT_SIDE ),
89 CURSOR(ELM_CURSOR_RIGHT_TEE , ECORE_X_CURSOR_RIGHT_TEE ),
90 CURSOR(ELM_CURSOR_RIGHTBUTTON , ECORE_X_CURSOR_RIGHTBUTTON ),
91 CURSOR(ELM_CURSOR_RTL_LOGO , ECORE_X_CURSOR_RTL_LOGO ),
92 CURSOR(ELM_CURSOR_SAILBOAT , ECORE_X_CURSOR_SAILBOAT ),
93 CURSOR(ELM_CURSOR_SB_DOWN_ARROW , ECORE_X_CURSOR_SB_DOWN_ARROW ),
94 CURSOR(ELM_CURSOR_SB_H_DOUBLE_ARROW , ECORE_X_CURSOR_SB_H_DOUBLE_ARROW ),
95 CURSOR(ELM_CURSOR_SB_LEFT_ARROW , ECORE_X_CURSOR_SB_LEFT_ARROW ),
96 CURSOR(ELM_CURSOR_SB_RIGHT_ARROW , ECORE_X_CURSOR_SB_RIGHT_ARROW ),
97 CURSOR(ELM_CURSOR_SB_UP_ARROW , ECORE_X_CURSOR_SB_UP_ARROW ),
98 CURSOR(ELM_CURSOR_SB_V_DOUBLE_ARROW , ECORE_X_CURSOR_SB_V_DOUBLE_ARROW ),
99 CURSOR(ELM_CURSOR_SHUTTLE , ECORE_X_CURSOR_SHUTTLE ),
100 CURSOR(ELM_CURSOR_SIZING , ECORE_X_CURSOR_SIZING ),
101 CURSOR(ELM_CURSOR_SPIDER , ECORE_X_CURSOR_SPIDER ),
102 CURSOR(ELM_CURSOR_SPRAYCAN , ECORE_X_CURSOR_SPRAYCAN ),
103 CURSOR(ELM_CURSOR_STAR , ECORE_X_CURSOR_STAR ),
104 CURSOR(ELM_CURSOR_TARGET , ECORE_X_CURSOR_TARGET ),
105 CURSOR(ELM_CURSOR_TCROSS , ECORE_X_CURSOR_TCROSS ),
106 CURSOR(ELM_CURSOR_TOP_LEFT_ARROW , ECORE_X_CURSOR_TOP_LEFT_ARROW ),
107 CURSOR(ELM_CURSOR_TOP_LEFT_CORNER , ECORE_X_CURSOR_TOP_LEFT_CORNER ),
108 CURSOR(ELM_CURSOR_TOP_RIGHT_CORNER , ECORE_X_CURSOR_TOP_RIGHT_CORNER ),
109 CURSOR(ELM_CURSOR_TOP_SIDE , ECORE_X_CURSOR_TOP_SIDE ),
110 CURSOR(ELM_CURSOR_TOP_TEE , ECORE_X_CURSOR_TOP_TEE ),
111 CURSOR(ELM_CURSOR_TREK , ECORE_X_CURSOR_TREK ),
112 CURSOR(ELM_CURSOR_UL_ANGLE , ECORE_X_CURSOR_UL_ANGLE ),
113 CURSOR(ELM_CURSOR_UMBRELLA , ECORE_X_CURSOR_UMBRELLA ),
114 CURSOR(ELM_CURSOR_UR_ANGLE , ECORE_X_CURSOR_UR_ANGLE ),
115 CURSOR(ELM_CURSOR_WATCH , ECORE_X_CURSOR_WATCH ),
116 CURSOR(ELM_CURSOR_XTERM , ECORE_X_CURSOR_XTERM )
118 static const int _cursors_count = sizeof(_cursors)/sizeof(struct _Cursor_Id);
120 #define ELM_CURSOR_GET_OR_RETURN(cur, obj, ...) \
126 CRITICAL("Null pointer: " #obj); \
127 return __VA_ARGS__; \
129 cur = evas_object_data_get((obj), _cursor_key); \
132 ERR("Object does not have cursor: " #obj); \
133 return __VA_ARGS__; \
141 Evas_Object *eventarea, *owner;
142 const char *style, *cursor_name;
146 #ifdef HAVE_ELEMENTARY_X
147 Ecore_X_Cursor cursor;
151 Eina_Bool use_engine:1;
152 Eina_Bool engine_only:1;
156 _elm_cursor_obj_del(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
158 Elm_Cursor *cur = data;
160 if (cur) cur->obj = NULL;
164 _elm_cursor_obj_add(Evas_Object *obj, Elm_Cursor *cur)
168 cur->obj = edje_object_add(cur->evas);
173 if (!_elm_theme_object_set(obj, cur->obj, "cursor", cur->cursor_name,
174 cur->style ? cur->style : "default"))
176 evas_object_del(cur->obj);
181 evas_object_event_callback_add(cur->obj, EVAS_CALLBACK_DEL,
182 _elm_cursor_obj_del, cur);
184 edje_object_size_min_get(cur->obj, &x, &y);
185 evas_object_resize(cur->obj, x, y);
190 _elm_cursor_set_hot_spots(Elm_Cursor *cur)
194 str = edje_object_data_get(cur->obj, "hot_x");
195 if (str) cur->hot_x = atoi(str);
198 str = edje_object_data_get(cur->obj, "hot_y");
199 if (str) cur->hot_y = atoi(str);
204 _elm_cursor_mouse_in(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
206 Elm_Cursor *cur = data;
208 if (cur->visible) return;
209 evas_event_freeze(cur->evas);
210 cur->visible = EINA_TRUE;
211 if ((!cur->engine_only) && (!cur->use_engine))
214 _elm_cursor_obj_add(cur->eventarea, cur);
215 ecore_evas_object_cursor_set(cur->ee, cur->obj,
216 ELM_OBJECT_LAYER_CURSOR, cur->hot_x,
221 #ifdef HAVE_ELEMENTARY_X
224 ecore_x_window_cursor_set(cur->win, cur->cursor);
228 evas_event_thaw(cur->evas);
232 _elm_cursor_mouse_out(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
234 Evas_Object *sobj_parent;
235 Elm_Cursor *pcur = NULL;
236 Elm_Cursor *cur = data;
238 if (!cur->visible) return;
239 evas_event_freeze(cur->evas);
240 cur->visible = EINA_FALSE;
242 sobj_parent = evas_object_data_get(cur->eventarea, "elm-parent");
245 pcur = evas_object_data_get((sobj_parent), _cursor_key);
246 if ((pcur) && (pcur->visible)) break;
247 sobj_parent = evas_object_data_get(sobj_parent, "elm-parent");
252 pcur->visible = EINA_FALSE;
253 evas_event_thaw(cur->evas);
254 _elm_cursor_mouse_in(pcur, NULL, NULL, NULL);
258 if ((!cur->engine_only) || (!cur->use_engine))
260 ecore_evas_object_cursor_set(cur->ee, NULL, ELM_OBJECT_LAYER_CURSOR,
261 cur->hot_x, cur->hot_y);
265 #ifdef HAVE_ELEMENTARY_X
268 ecore_x_window_cursor_set(cur->win, ECORE_X_CURSOR_X);
272 evas_event_thaw(cur->evas);
276 _elm_cursor_del(void *data __UNUSED__, Evas *evas __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
278 elm_object_cursor_unset(obj);
282 _elm_cursor_strcmp(const void *data1, const void *data2)
284 const struct _Cursor_Id *c1 = data1;
285 const struct _Cursor_Id *c2 = data2;
286 return strcmp (c1->name, c2->name);
290 _elm_cursor_cur_set(Elm_Cursor *cur)
292 if (cur->engine_only)
294 INF("Using only engine cursors");
295 cur->use_engine = EINA_TRUE;
297 else if (_elm_cursor_obj_add(cur->eventarea, cur))
299 _elm_cursor_set_hot_spots(cur);
300 cur->use_engine = EINA_FALSE;
301 elm_widget_cursor_add(cur->owner, cur);
305 INF("Cursor couldn't be found on theme: %s", cur->cursor_name);
306 cur->use_engine = EINA_TRUE;
311 #ifdef HAVE_ELEMENTARY_X
312 struct _Cursor_Id cur_search, *cur_id;
314 cur_search.name = cur->cursor_name;
315 cur_id = bsearch(&(cur->cursor_name), _cursors, _cursors_count,
316 sizeof(struct _Cursor_Id), _elm_cursor_strcmp);
318 cur->win = elm_win_xwindow_get(cur->eventarea);
323 INF("X cursor couldn't be found: %s. Using default.",
325 cur->cursor = ecore_x_cursor_shape_get(ECORE_X_CURSOR_X);
328 cur->cursor = ecore_x_cursor_shape_get(cur_id->id);
335 * Set the cursor to be shown when mouse is over the object
337 * Set the cursor that will be displayed when mouse is over the
338 * object. The object can have only one cursor set to it, so if
339 * this function is called twice for an object, the previous set
341 * If using X cursors, a definition of all the valid cursor names
342 * is listed on Elementary_Cursors.h. If an invalid name is set
343 * the default cursor will be used.
345 * This is an internal function that is used by objects with sub-items
346 * that want to provide different cursors for each of them. The @a
347 * owner object should be an elm_widget and will be used to track
348 * theme changes and to feed @a func and @a del_cb. The @a eventarea
349 * may be any object and is the one that should be used later on with
350 * elm_object_cursor apis, such as elm_object_cursor_unset().
352 * @param eventarea the object being attached a cursor.
353 * @param owner the elm_widget that owns this object, will be used to
354 * track theme changes and to be used in @a func or @a del_cb.
355 * @param cursor the cursor name to be used.
361 elm_object_sub_cursor_set(Evas_Object *eventarea, Evas_Object *owner, const char *cursor)
363 Elm_Cursor *cur = NULL;
365 cur = evas_object_data_get(eventarea, _cursor_key);
367 elm_object_cursor_unset(eventarea);
371 cur = ELM_NEW(Elm_Cursor);
375 cur->eventarea = eventarea;
376 cur->engine_only = _elm_config->cursor_engine_only;
377 cur->visible = EINA_FALSE;
379 cur->cursor_name = eina_stringshare_add(cursor);
380 if (!cur->cursor_name)
381 ERR("Could not store cursor name %s", cursor);
383 cur->evas = evas_object_evas_get(eventarea);
384 cur->ee = ecore_evas_ecore_evas_get(cur->evas);
386 _elm_cursor_cur_set(cur);
388 evas_object_data_set(eventarea, _cursor_key, cur);
390 evas_object_event_callback_add(eventarea, EVAS_CALLBACK_MOUSE_IN,
391 _elm_cursor_mouse_in, cur);
392 evas_object_event_callback_add(eventarea, EVAS_CALLBACK_MOUSE_OUT,
393 _elm_cursor_mouse_out, cur);
394 evas_object_event_callback_add(eventarea, EVAS_CALLBACK_DEL,
395 _elm_cursor_del, cur);
399 * Set the cursor to be shown when mouse is over the object
401 * Set the cursor that will be displayed when mouse is over the
402 * object. The object can have only one cursor set to it, so if
403 * this function is called twice for an object, the previous set
405 * If using X cursors, a definition of all the valid cursor names
406 * is listed on Elementary_Cursors.h. If an invalid name is set
407 * the default cursor will be used.
409 * @param obj the object being set a cursor.
410 * @param cursor the cursor name to be used.
415 elm_object_cursor_set(Evas_Object *obj, const char *cursor)
417 EINA_SAFETY_ON_NULL_RETURN(obj);
418 elm_object_sub_cursor_set(obj, obj, cursor);
422 * Get the cursor to be shown when mouse is over the object
424 * @param obj an object with cursor already set.
425 * @return the cursor name.
430 elm_object_cursor_get(const Evas_Object *obj)
432 ELM_CURSOR_GET_OR_RETURN(cur, obj, NULL);
433 return cur->cursor_name;
437 * Unset cursor for object
439 * Unset cursor for object, and set the cursor to default if the mouse
440 * was over this object.
442 * @param obj Target object
443 * @see elm_object_cursor_set()
448 elm_object_cursor_unset(Evas_Object *obj)
450 ELM_CURSOR_GET_OR_RETURN(cur, obj);
452 eina_stringshare_del(cur->cursor_name);
453 eina_stringshare_del(cur->style);
456 elm_widget_cursor_del(cur->owner, cur);
459 evas_object_del(cur->obj);
463 if (!cur->use_engine)
464 ecore_evas_object_cursor_set(cur->ee, NULL, ELM_OBJECT_LAYER_CURSOR,
465 cur->hot_x, cur->hot_y);
466 #ifdef HAVE_ELEMENTARY_X
468 ecore_x_window_cursor_set(cur->win, ECORE_X_CURSOR_X);
472 evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_IN,
473 _elm_cursor_mouse_in);
474 evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_OUT,
475 _elm_cursor_mouse_out);
476 evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _elm_cursor_del);
478 evas_object_data_del(obj, _cursor_key);
483 * Sets a different style for this object cursor.
485 * @note before you set a style you should define a cursor with
486 * elm_object_cursor_set()
488 * @param obj an object with cursor already set.
489 * @param style the theme style to use (default, transparent, ...)
494 elm_object_cursor_style_set(Evas_Object *obj, const char *style)
496 ELM_CURSOR_GET_OR_RETURN(cur, obj);
498 if (!eina_stringshare_replace(&cur->style, style))
499 ERR("Could not set current style=%s", style);
501 if (cur->use_engine) return;
505 if (!_elm_cursor_obj_add(obj, cur))
506 ERR("Could not create cursor object");
508 _elm_cursor_set_hot_spots(cur);
512 if (!_elm_theme_object_set(obj, cur->obj, "cursor", cur->cursor_name,
514 ERR("Could not apply the theme to the cursor style=%s", style);
516 _elm_cursor_set_hot_spots(cur);
521 * Get the style for this object cursor.
523 * @param obj an object with cursor already set.
524 * @return style the theme style in use, defaults to "default". If the
525 * object does not have a cursor set, then NULL is returned.
530 elm_object_cursor_style_get(const Evas_Object *obj)
532 ELM_CURSOR_GET_OR_RETURN(cur, obj, NULL);
533 return cur->style ? cur->style : "default";
537 * Notify cursor should recalculate its theme.
541 elm_cursor_theme(Elm_Cursor *cur)
543 if ((!cur) || (!cur->obj)) return;
544 if (!_elm_theme_object_set(cur->eventarea, cur->obj, "cursor",
545 cur->cursor_name, cur->style))
546 ERR("Could not apply the theme to the cursor style=%s", cur->style);
548 _elm_cursor_set_hot_spots(cur);
552 * Set if the cursor set should be searched on the theme or should use
553 * the provided by the engine, only.
555 * @note before you set if should look on theme you should define a cursor
556 * with elm_object_cursor_set(). By default it will only look for cursors
557 * provided by the engine.
559 * @param obj an object with cursor already set.
560 * @param engine_only boolean to define it cursors should be looked only
561 * between the provided by the engine or searched on widget's theme as well.
566 elm_object_cursor_engine_only_set(Evas_Object *obj, Eina_Bool engine_only)
568 ELM_CURSOR_GET_OR_RETURN(cur, obj);
569 cur->engine_only = engine_only;
572 evas_object_del(cur->obj);
575 _elm_cursor_cur_set(cur);
579 * Get the cursor engine only usage for this object cursor.
581 * @param obj an object with cursor already set.
582 * @return engine_only boolean to define it cursors should be looked only
583 * between the provided by the engine or searched on widget's theme as well. If
584 * the object does not have a cursor set, then EINA_FALSE is returned.
589 elm_object_cursor_engine_only_get(const Evas_Object *obj)
591 ELM_CURSOR_GET_OR_RETURN(cur, obj, EINA_FALSE);
592 return cur->engine_only;
596 * Get the configured cursor engine only usage
598 * This gets the globally configured exclusive usage of engine cursors.
600 * @return 1 if only engine cursors should be used
604 elm_cursor_engine_only_get(void)
606 return _elm_config->cursor_engine_only;
610 * Set the configured cursor engine only usage
612 * This sets the globally configured exclusive usage of engine cursors.
613 * It won't affect cursors set before changing this value.
615 * @param engine_only If 1 only engine cursors will be enabled, if 0 will
616 * look for them on theme before.
617 * @return EINA_TRUE if value is valid and setted (0 or 1)
621 elm_cursor_engine_only_set(int engine_only)
623 if ((engine_only < 0) || (engine_only > 1)) return EINA_FALSE;
624 _elm_config->cursor_engine_only = engine_only;