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
222 ecore_x_window_cursor_set(cur->win, cur->cursor);
225 evas_event_thaw(cur->evas);
229 _elm_cursor_mouse_out(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
231 Evas_Object *sobj_parent;
232 Elm_Cursor *pcur = NULL;
233 Elm_Cursor *cur = data;
235 if (!cur->visible) return;
236 evas_event_freeze(cur->evas);
237 cur->visible = EINA_FALSE;
239 sobj_parent = evas_object_data_get(cur->eventarea, "elm-parent");
242 pcur = evas_object_data_get((sobj_parent), _cursor_key);
243 if ((pcur) && (pcur->visible)) break;
244 sobj_parent = evas_object_data_get(sobj_parent, "elm-parent");
249 pcur->visible = EINA_FALSE;
250 evas_event_thaw(cur->evas);
251 _elm_cursor_mouse_in(pcur, NULL, NULL, NULL);
255 if ((!cur->engine_only) || (!cur->use_engine))
257 ecore_evas_object_cursor_set(cur->ee, NULL, ELM_OBJECT_LAYER_CURSOR,
258 cur->hot_x, cur->hot_y);
262 #ifdef HAVE_ELEMENTARY_X
263 ecore_x_window_cursor_set(cur->win, ECORE_X_CURSOR_X);
266 evas_event_thaw(cur->evas);
270 _elm_cursor_del(void *data __UNUSED__, Evas *evas __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
272 elm_object_cursor_unset(obj);
276 _elm_cursor_strcmp(const void *data1, const void *data2)
278 const struct _Cursor_Id *c1 = data1;
279 const struct _Cursor_Id *c2 = data2;
280 return strcmp (c1->name, c2->name);
284 _elm_cursor_cur_set(Elm_Cursor *cur)
286 if (cur->engine_only)
288 INF("Using only engine cursors");
289 cur->use_engine = EINA_TRUE;
291 else if (_elm_cursor_obj_add(cur->eventarea, cur))
293 _elm_cursor_set_hot_spots(cur);
294 cur->use_engine = EINA_FALSE;
295 elm_widget_cursor_add(cur->owner, cur);
299 INF("Cursor couldn't be found on theme: %s", cur->cursor_name);
300 cur->use_engine = EINA_TRUE;
305 #ifdef HAVE_ELEMENTARY_X
306 struct _Cursor_Id cur_search, *cur_id;
308 cur_search.name = cur->cursor_name;
309 cur_id = bsearch(&(cur->cursor_name), _cursors, _cursors_count,
310 sizeof(struct _Cursor_Id), _elm_cursor_strcmp);
312 cur->win = elm_win_xwindow_get(cur->eventarea);
315 INF("X cursor couldn't be found: %s. Using default.",
317 cur->cursor = ecore_x_cursor_shape_get(ECORE_X_CURSOR_X);
320 cur->cursor = ecore_x_cursor_shape_get(cur_id->id);
326 * Set the cursor to be shown when mouse is over the object
328 * Set the cursor that will be displayed when mouse is over the
329 * object. The object can have only one cursor set to it, so if
330 * this function is called twice for an object, the previous set
332 * If using X cursors, a definition of all the valid cursor names
333 * is listed on Elementary_Cursors.h. If an invalid name is set
334 * the default cursor will be used.
336 * This is an internal function that is used by objects with sub-items
337 * that want to provide different cursors for each of them. The @a
338 * owner object should be an elm_widget and will be used to track
339 * theme changes and to feed @a func and @a del_cb. The @a eventarea
340 * may be any object and is the one that should be used later on with
341 * elm_object_cursor apis, such as elm_object_cursor_unset().
343 * @param eventarea the object being attached a cursor.
344 * @param owner the elm_widget that owns this object, will be used to
345 * track theme changes and to be used in @a func or @a del_cb.
346 * @param cursor the cursor name to be used.
352 elm_object_sub_cursor_set(Evas_Object *eventarea, Evas_Object *owner, const char *cursor)
354 Elm_Cursor *cur = NULL;
356 cur = evas_object_data_get(eventarea, _cursor_key);
358 elm_object_cursor_unset(eventarea);
362 cur = ELM_NEW(Elm_Cursor);
366 cur->eventarea = eventarea;
367 cur->engine_only = _elm_config->cursor_engine_only;
368 cur->visible = EINA_FALSE;
370 cur->cursor_name = eina_stringshare_add(cursor);
371 if (!cur->cursor_name)
372 ERR("Could not store cursor name %s", cursor);
374 cur->evas = evas_object_evas_get(eventarea);
375 cur->ee = ecore_evas_ecore_evas_get(cur->evas);
377 _elm_cursor_cur_set(cur);
379 evas_object_data_set(eventarea, _cursor_key, cur);
381 evas_object_event_callback_add(eventarea, EVAS_CALLBACK_MOUSE_IN,
382 _elm_cursor_mouse_in, cur);
383 evas_object_event_callback_add(eventarea, EVAS_CALLBACK_MOUSE_OUT,
384 _elm_cursor_mouse_out, cur);
385 evas_object_event_callback_add(eventarea, EVAS_CALLBACK_DEL,
386 _elm_cursor_del, cur);
390 * Set the cursor to be shown when mouse is over the object
392 * Set the cursor that will be displayed when mouse is over the
393 * object. The object can have only one cursor set to it, so if
394 * this function is called twice for an object, the previous set
396 * If using X cursors, a definition of all the valid cursor names
397 * is listed on Elementary_Cursors.h. If an invalid name is set
398 * the default cursor will be used.
400 * @param obj the object being set a cursor.
401 * @param cursor the cursor name to be used.
406 elm_object_cursor_set(Evas_Object *obj, const char *cursor)
408 EINA_SAFETY_ON_NULL_RETURN(obj);
409 elm_object_sub_cursor_set(obj, obj, cursor);
413 * Get the cursor to be shown when mouse is over the object
415 * @param obj an object with cursor already set.
416 * @return the cursor name.
421 elm_object_cursor_get(const Evas_Object *obj)
423 ELM_CURSOR_GET_OR_RETURN(cur, obj, NULL);
424 return cur->cursor_name;
428 * Unset cursor for object
430 * Unset cursor for object, and set the cursor to default if the mouse
431 * was over this object.
433 * @param obj Target object
434 * @see elm_object_cursor_set()
439 elm_object_cursor_unset(Evas_Object *obj)
441 ELM_CURSOR_GET_OR_RETURN(cur, obj);
443 eina_stringshare_del(cur->cursor_name);
444 eina_stringshare_del(cur->style);
447 elm_widget_cursor_del(cur->owner, cur);
450 evas_object_del(cur->obj);
454 if (!cur->use_engine)
455 ecore_evas_object_cursor_set(cur->ee, NULL, ELM_OBJECT_LAYER_CURSOR,
456 cur->hot_x, cur->hot_y);
457 #ifdef HAVE_ELEMENTARY_X
459 ecore_x_window_cursor_set(cur->win, ECORE_X_CURSOR_X);
463 evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_IN,
464 _elm_cursor_mouse_in);
465 evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_OUT,
466 _elm_cursor_mouse_out);
467 evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _elm_cursor_del);
469 evas_object_data_del(obj, _cursor_key);
474 * Sets a different style for this object cursor.
476 * @note before you set a style you should define a cursor with
477 * elm_object_cursor_set()
479 * @param obj an object with cursor already set.
480 * @param style the theme style to use (default, transparent, ...)
485 elm_object_cursor_style_set(Evas_Object *obj, const char *style)
487 ELM_CURSOR_GET_OR_RETURN(cur, obj);
489 if (!eina_stringshare_replace(&cur->style, style))
490 ERR("Could not set current style=%s", style);
492 if (cur->use_engine) return;
496 if (!_elm_cursor_obj_add(obj, cur))
497 ERR("Could not create cursor object");
499 _elm_cursor_set_hot_spots(cur);
503 if (!_elm_theme_object_set(obj, cur->obj, "cursor", cur->cursor_name,
505 ERR("Could not apply the theme to the cursor style=%s", style);
507 _elm_cursor_set_hot_spots(cur);
512 * Get the style for this object cursor.
514 * @param obj an object with cursor already set.
515 * @return style the theme style in use, defaults to "default". If the
516 * object does not have a cursor set, then NULL is returned.
521 elm_object_cursor_style_get(const Evas_Object *obj)
523 ELM_CURSOR_GET_OR_RETURN(cur, obj, NULL);
524 return cur->style ? cur->style : "default";
528 * Notify cursor should recalculate its theme.
532 elm_cursor_theme(Elm_Cursor *cur)
534 if ((!cur) || (!cur->obj)) return;
535 if (!_elm_theme_object_set(cur->eventarea, cur->obj, "cursor",
536 cur->cursor_name, cur->style))
537 ERR("Could not apply the theme to the cursor style=%s", cur->style);
539 _elm_cursor_set_hot_spots(cur);
543 * Set if the cursor set should be searched on the theme or should use
544 * the provided by the engine, only.
546 * @note before you set if should look on theme you should define a cursor
547 * with elm_object_cursor_set(). By default it will only look for cursors
548 * provided by the engine.
550 * @param obj an object with cursor already set.
551 * @param engine_only boolean to define it cursors should be looked only
552 * between the provided by the engine or searched on widget's theme as well.
557 elm_object_cursor_engine_only_set(Evas_Object *obj, Eina_Bool engine_only)
559 ELM_CURSOR_GET_OR_RETURN(cur, obj);
560 cur->engine_only = engine_only;
563 evas_object_del(cur->obj);
566 _elm_cursor_cur_set(cur);
570 * Get the cursor engine only usage for this object cursor.
572 * @param obj an object with cursor already set.
573 * @return engine_only boolean to define it cursors should be looked only
574 * between the provided by the engine or searched on widget's theme as well. If
575 * the object does not have a cursor set, then EINA_FALSE is returned.
580 elm_object_cursor_engine_only_get(const Evas_Object *obj)
582 ELM_CURSOR_GET_OR_RETURN(cur, obj, EINA_FALSE);
583 return cur->engine_only;
587 * Get the configured cursor engine only usage
589 * This gets the globally configured exclusive usage of engine cursors.
591 * @return 1 if only engine cursors should be used
595 elm_cursor_engine_only_get(void)
597 return _elm_config->cursor_engine_only;
601 * Set the configured cursor engine only usage
603 * This sets the globally configured exclusive usage of engine cursors.
604 * It won't affect cursors set before changing this value.
606 * @param engine_only If 1 only engine cursors will be enabled, if 0 will
607 * look for them on theme before.
608 * @return EINA_TRUE if value is valid and setted (0 or 1)
612 elm_cursor_engine_only_set(int engine_only)
614 if ((engine_only < 0) || (engine_only > 1)) return EINA_FALSE;
615 _elm_config->cursor_engine_only = engine_only;