aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/elementary/src/lib/els_cursor.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/elementary/src/lib/els_cursor.c')
-rw-r--r--libraries/elementary/src/lib/els_cursor.c506
1 files changed, 506 insertions, 0 deletions
diff --git a/libraries/elementary/src/lib/els_cursor.c b/libraries/elementary/src/lib/els_cursor.c
new file mode 100644
index 0000000..7e8a625
--- /dev/null
+++ b/libraries/elementary/src/lib/els_cursor.c
@@ -0,0 +1,506 @@
1#include <Elementary.h>
2#include <Elementary_Cursor.h>
3#include "elm_priv.h"
4
5#ifdef HAVE_ELEMENTARY_X
6#include <Ecore_X.h>
7#include <Ecore_X_Cursor.h>
8#endif
9
10#define _cursor_key "_elm_cursor"
11
12struct _Cursor_Id
13{
14 const char *name;
15#ifdef HAVE_ELEMENTARY_X
16 int id;
17#endif
18};
19
20#ifdef HAVE_ELEMENTARY_X
21#define CURSOR(_name, _xid) \
22 {_name , _xid}
23# else
24#define CURSOR(_name, _xid) \
25 {_name}
26#endif
27
28/* Please keep order in sync with Ecore_X_Cursor.h values! */
29struct _Cursor_Id _cursors[] =
30{
31 CURSOR(ELM_CURSOR_X , ECORE_X_CURSOR_X ),
32 CURSOR(ELM_CURSOR_ARROW , ECORE_X_CURSOR_ARROW ),
33 CURSOR(ELM_CURSOR_BASED_ARROW_DOWN , ECORE_X_CURSOR_BASED_ARROW_DOWN ),
34 CURSOR(ELM_CURSOR_BASED_ARROW_UP , ECORE_X_CURSOR_UP ),
35 CURSOR(ELM_CURSOR_BOAT , ECORE_X_CURSOR_BOAT ),
36 CURSOR(ELM_CURSOR_BOGOSITY , ECORE_X_CURSOR_BOGOSITY ),
37 CURSOR(ELM_CURSOR_BOTTOM_LEFT_CORNER , ECORE_X_CURSOR_BOTTOM_LEFT_CORNER ),
38 CURSOR(ELM_CURSOR_BOTTOM_RIGHT_CORNER, ECORE_X_CURSOR_BOTTOM_RIGHT_CORNER),
39 CURSOR(ELM_CURSOR_BOTTOM_SIDE , ECORE_X_CURSOR_BOTTOM_SIDE ),
40 CURSOR(ELM_CURSOR_BOTTOM_TEE , ECORE_X_CURSOR_BOTTOM_TEE ),
41 CURSOR(ELM_CURSOR_BOX_SPIRAL , ECORE_X_CURSOR_BOX_SPIRAL ),
42 CURSOR(ELM_CURSOR_CENTER_PTR , ECORE_X_CURSOR_CENTER_PTR ),
43 CURSOR(ELM_CURSOR_CIRCLE , ECORE_X_CURSOR_CIRCLE ),
44 CURSOR(ELM_CURSOR_CLOCK , ECORE_X_CURSOR_CLOCK ),
45 CURSOR(ELM_CURSOR_COFFEE_MUG , ECORE_X_CURSOR_COFFEE_MUG ),
46 CURSOR(ELM_CURSOR_CROSS , ECORE_X_CURSOR_CROSS ),
47 CURSOR(ELM_CURSOR_CROSS_REVERSE , ECORE_X_CURSOR_CROSS_REVERSE ),
48 CURSOR(ELM_CURSOR_CROSSHAIR , ECORE_X_CURSOR_CROSSHAIR ),
49 CURSOR(ELM_CURSOR_DIAMOND_CROSS , ECORE_X_CURSOR_DIAMOND_CROSS ),
50 CURSOR(ELM_CURSOR_DOT , ECORE_X_CURSOR_DOT ),
51 CURSOR(ELM_CURSOR_DOT_BOX_MASK , ECORE_X_CURSOR_DOT_BOX_MASK ),
52 CURSOR(ELM_CURSOR_DOUBLE_ARROW , ECORE_X_CURSOR_DOUBLE_ARROW ),
53 CURSOR(ELM_CURSOR_DRAFT_LARGE , ECORE_X_CURSOR_DRAFT_LARGE ),
54 CURSOR(ELM_CURSOR_DRAFT_SMALL , ECORE_X_CURSOR_DRAFT_SMALL ),
55 CURSOR(ELM_CURSOR_DRAPED_BOX , ECORE_X_CURSOR_DRAPED_BOX ),
56 CURSOR(ELM_CURSOR_EXCHANGE , ECORE_X_CURSOR_EXCHANGE ),
57 CURSOR(ELM_CURSOR_FLEUR , ECORE_X_CURSOR_FLEUR ),
58 CURSOR(ELM_CURSOR_GOBBLER , ECORE_X_CURSOR_GOBBLER ),
59 CURSOR(ELM_CURSOR_GUMBY , ECORE_X_CURSOR_GUMBY ),
60 CURSOR(ELM_CURSOR_HAND1 , ECORE_X_CURSOR_HAND1 ),
61 CURSOR(ELM_CURSOR_HAND2 , ECORE_X_CURSOR_HAND2 ),
62 CURSOR(ELM_CURSOR_HEART , ECORE_X_CURSOR_HEART ),
63 CURSOR(ELM_CURSOR_ICON , ECORE_X_CURSOR_ICON ),
64 CURSOR(ELM_CURSOR_IRON_CROSS , ECORE_X_CURSOR_IRON_CROSS ),
65 CURSOR(ELM_CURSOR_LEFT_PTR , ECORE_X_CURSOR_LEFT_PTR ),
66 CURSOR(ELM_CURSOR_LEFT_SIDE , ECORE_X_CURSOR_LEFT_SIDE ),
67 CURSOR(ELM_CURSOR_LEFT_TEE , ECORE_X_CURSOR_LEFT_TEE ),
68 CURSOR(ELM_CURSOR_LEFTBUTTON , ECORE_X_CURSOR_LEFTBUTTON ),
69 CURSOR(ELM_CURSOR_LL_ANGLE , ECORE_X_CURSOR_LL_ANGLE ),
70 CURSOR(ELM_CURSOR_LR_ANGLE , ECORE_X_CURSOR_LR_ANGLE ),
71 CURSOR(ELM_CURSOR_MAN , ECORE_X_CURSOR_MAN ),
72 CURSOR(ELM_CURSOR_MIDDLEBUTTON , ECORE_X_CURSOR_MIDDLEBUTTON ),
73 CURSOR(ELM_CURSOR_MOUSE , ECORE_X_CURSOR_MOUSE ),
74 CURSOR(ELM_CURSOR_PENCIL , ECORE_X_CURSOR_PENCIL ),
75 CURSOR(ELM_CURSOR_PIRATE , ECORE_X_CURSOR_PIRATE ),
76 CURSOR(ELM_CURSOR_PLUS , ECORE_X_CURSOR_PLUS ),
77 CURSOR(ELM_CURSOR_QUESTION_ARROW , ECORE_X_CURSOR_QUESTION_ARROW ),
78 CURSOR(ELM_CURSOR_RIGHT_PTR , ECORE_X_CURSOR_RIGHT_PTR ),
79 CURSOR(ELM_CURSOR_RIGHT_SIDE , ECORE_X_CURSOR_RIGHT_SIDE ),
80 CURSOR(ELM_CURSOR_RIGHT_TEE , ECORE_X_CURSOR_RIGHT_TEE ),
81 CURSOR(ELM_CURSOR_RIGHTBUTTON , ECORE_X_CURSOR_RIGHTBUTTON ),
82 CURSOR(ELM_CURSOR_RTL_LOGO , ECORE_X_CURSOR_RTL_LOGO ),
83 CURSOR(ELM_CURSOR_SAILBOAT , ECORE_X_CURSOR_SAILBOAT ),
84 CURSOR(ELM_CURSOR_SB_DOWN_ARROW , ECORE_X_CURSOR_SB_DOWN_ARROW ),
85 CURSOR(ELM_CURSOR_SB_H_DOUBLE_ARROW , ECORE_X_CURSOR_SB_H_DOUBLE_ARROW ),
86 CURSOR(ELM_CURSOR_SB_LEFT_ARROW , ECORE_X_CURSOR_SB_LEFT_ARROW ),
87 CURSOR(ELM_CURSOR_SB_RIGHT_ARROW , ECORE_X_CURSOR_SB_RIGHT_ARROW ),
88 CURSOR(ELM_CURSOR_SB_UP_ARROW , ECORE_X_CURSOR_SB_UP_ARROW ),
89 CURSOR(ELM_CURSOR_SB_V_DOUBLE_ARROW , ECORE_X_CURSOR_SB_V_DOUBLE_ARROW ),
90 CURSOR(ELM_CURSOR_SHUTTLE , ECORE_X_CURSOR_SHUTTLE ),
91 CURSOR(ELM_CURSOR_SIZING , ECORE_X_CURSOR_SIZING ),
92 CURSOR(ELM_CURSOR_SPIDER , ECORE_X_CURSOR_SPIDER ),
93 CURSOR(ELM_CURSOR_SPRAYCAN , ECORE_X_CURSOR_SPRAYCAN ),
94 CURSOR(ELM_CURSOR_STAR , ECORE_X_CURSOR_STAR ),
95 CURSOR(ELM_CURSOR_TARGET , ECORE_X_CURSOR_TARGET ),
96 CURSOR(ELM_CURSOR_TCROSS , ECORE_X_CURSOR_TCROSS ),
97 CURSOR(ELM_CURSOR_TOP_LEFT_ARROW , ECORE_X_CURSOR_TOP_LEFT_ARROW ),
98 CURSOR(ELM_CURSOR_TOP_LEFT_CORNER , ECORE_X_CURSOR_TOP_LEFT_CORNER ),
99 CURSOR(ELM_CURSOR_TOP_RIGHT_CORNER , ECORE_X_CURSOR_TOP_RIGHT_CORNER ),
100 CURSOR(ELM_CURSOR_TOP_SIDE , ECORE_X_CURSOR_TOP_SIDE ),
101 CURSOR(ELM_CURSOR_TOP_TEE , ECORE_X_CURSOR_TOP_TEE ),
102 CURSOR(ELM_CURSOR_TREK , ECORE_X_CURSOR_TREK ),
103 CURSOR(ELM_CURSOR_UL_ANGLE , ECORE_X_CURSOR_UL_ANGLE ),
104 CURSOR(ELM_CURSOR_UMBRELLA , ECORE_X_CURSOR_UMBRELLA ),
105 CURSOR(ELM_CURSOR_UR_ANGLE , ECORE_X_CURSOR_UR_ANGLE ),
106 CURSOR(ELM_CURSOR_WATCH , ECORE_X_CURSOR_WATCH ),
107 CURSOR(ELM_CURSOR_XTERM , ECORE_X_CURSOR_XTERM )
108};
109static const int _cursors_count = sizeof(_cursors)/sizeof(struct _Cursor_Id);
110
111#define ELM_CURSOR_GET_OR_RETURN(cur, obj, ...) \
112 Elm_Cursor *cur; \
113 do \
114 { \
115 if (!(obj)) \
116 { \
117 CRITICAL("Null pointer: " #obj); \
118 return __VA_ARGS__; \
119 } \
120 cur = evas_object_data_get((obj), _cursor_key); \
121 if (!cur) \
122 { \
123 ERR("Object does not have cursor: " #obj); \
124 return __VA_ARGS__; \
125 } \
126 } \
127 while (0)
128
129struct _Elm_Cursor
130{
131 Evas_Object *obj;
132 Evas_Object *eventarea, *owner;
133 const char *style, *cursor_name;
134 int hot_x, hot_y;
135 Ecore_Evas *ee;
136 Evas *evas;
137#ifdef HAVE_ELEMENTARY_X
138 Ecore_X_Cursor cursor;
139 Ecore_X_Window win;
140#endif
141 Eina_Bool visible:1;
142 Eina_Bool use_engine:1;
143 Eina_Bool engine_only:1;
144};
145
146static void
147_elm_cursor_obj_del(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
148{
149 Elm_Cursor *cur = data;
150
151 if (cur) cur->obj = NULL;
152}
153
154static Eina_Bool
155_elm_cursor_obj_add(Evas_Object *obj, Elm_Cursor *cur)
156{
157 int x, y;
158
159 cur->obj = edje_object_add(cur->evas);
160
161 if (!cur->obj)
162 return EINA_FALSE;
163
164 if (!_elm_theme_object_set(obj, cur->obj, "cursor", cur->cursor_name,
165 cur->style ? cur->style : "default"))
166 {
167 evas_object_del(cur->obj);
168 cur->obj = NULL;
169 return EINA_FALSE;
170 }
171
172 evas_object_event_callback_add(cur->obj, EVAS_CALLBACK_DEL,
173 _elm_cursor_obj_del, cur);
174
175 edje_object_size_min_get(cur->obj, &x, &y);
176 evas_object_resize(cur->obj, x, y);
177 return EINA_TRUE;
178}
179
180static void
181_elm_cursor_set_hot_spots(Elm_Cursor *cur)
182{
183 const char *str;
184
185 str = edje_object_data_get(cur->obj, "hot_x");
186 if (str) cur->hot_x = atoi(str);
187 else cur->hot_x = 0;
188
189 str = edje_object_data_get(cur->obj, "hot_y");
190 if (str) cur->hot_y = atoi(str);
191 else cur->hot_y = 0;
192}
193
194static void
195_elm_cursor_mouse_in(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
196{
197 Elm_Cursor *cur = data;
198
199 if (cur->visible) return;
200 evas_event_freeze(cur->evas);
201 cur->visible = EINA_TRUE;
202 if ((!cur->engine_only) && (!cur->use_engine))
203 {
204 if (!cur->obj)
205 _elm_cursor_obj_add(cur->eventarea, cur);
206 ecore_evas_object_cursor_set(cur->ee, cur->obj,
207 ELM_OBJECT_LAYER_CURSOR, cur->hot_x,
208 cur->hot_y);
209 }
210 else
211 {
212#ifdef HAVE_ELEMENTARY_X
213 if (cur->win)
214 {
215 ecore_x_window_cursor_set(cur->win, cur->cursor);
216 }
217#endif
218 }
219 evas_event_thaw(cur->evas);
220}
221
222static void
223_elm_cursor_mouse_out(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
224{
225 Evas_Object *sobj_parent;
226 Elm_Cursor *pcur = NULL;
227 Elm_Cursor *cur = data;
228
229 if (!cur->visible) return;
230 evas_event_freeze(cur->evas);
231 cur->visible = EINA_FALSE;
232
233 sobj_parent = evas_object_data_get(cur->eventarea, "elm-parent");
234 while (sobj_parent)
235 {
236 pcur = evas_object_data_get((sobj_parent), _cursor_key);
237 if ((pcur) && (pcur->visible)) break;
238 sobj_parent = evas_object_data_get(sobj_parent, "elm-parent");
239 }
240
241 if (pcur)
242 {
243 pcur->visible = EINA_FALSE;
244 evas_event_thaw(cur->evas);
245 _elm_cursor_mouse_in(pcur, NULL, NULL, NULL);
246 return;
247 }
248
249 if ((!cur->engine_only) || (!cur->use_engine))
250 {
251 ecore_evas_object_cursor_set(cur->ee, NULL, ELM_OBJECT_LAYER_CURSOR,
252 cur->hot_x, cur->hot_y);
253 }
254 else
255 {
256#ifdef HAVE_ELEMENTARY_X
257 if (cur->win)
258 {
259 ecore_x_window_cursor_set(cur->win, ECORE_X_CURSOR_X);
260 }
261#endif
262 }
263 evas_event_thaw(cur->evas);
264}
265
266static void
267_elm_cursor_del(void *data __UNUSED__, Evas *evas __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
268{
269 elm_object_cursor_unset(obj);
270}
271
272#ifdef HAVE_ELEMENTARY_X
273static int
274_elm_cursor_strcmp(const void *data1, const void *data2)
275{
276 const struct _Cursor_Id *c1 = data1;
277 const struct _Cursor_Id *c2 = data2;
278 return strcmp (c1->name, c2->name);
279}
280#endif
281
282static void
283_elm_cursor_cur_set(Elm_Cursor *cur)
284{
285 if (cur->engine_only)
286 {
287 INF("Using only engine cursors");
288 cur->use_engine = EINA_TRUE;
289 }
290 else if (_elm_cursor_obj_add(cur->eventarea, cur))
291 {
292 _elm_cursor_set_hot_spots(cur);
293 cur->use_engine = EINA_FALSE;
294 elm_widget_cursor_add(cur->owner, cur);
295 }
296 else
297 {
298 INF("Cursor couldn't be found on theme: %s", cur->cursor_name);
299 cur->use_engine = EINA_TRUE;
300 }
301
302 if (cur->use_engine)
303 {
304#ifdef HAVE_ELEMENTARY_X
305 struct _Cursor_Id *cur_id;
306
307 cur_id = bsearch(&(cur->cursor_name), _cursors, _cursors_count,
308 sizeof(struct _Cursor_Id), _elm_cursor_strcmp);
309
310 cur->win = elm_win_xwindow_get(cur->eventarea);
311 if (cur->win)
312 {
313 if (!cur_id)
314 {
315 INF("X cursor couldn't be found: %s. Using default.",
316 cur->cursor_name);
317 cur->cursor = ecore_x_cursor_shape_get(ECORE_X_CURSOR_X);
318 }
319 else
320 cur->cursor = ecore_x_cursor_shape_get(cur_id->id);
321 }
322#endif
323 }
324}
325
326/**
327 * Set the cursor to be shown when mouse is over the object
328 *
329 * Set the cursor that will be displayed when mouse is over the
330 * object. The object can have only one cursor set to it, so if
331 * this function is called twice for an object, the previous set
332 * will be unset.
333 * If using X cursors, a definition of all the valid cursor names
334 * is listed on Elementary_Cursors.h. If an invalid name is set
335 * the default cursor will be used.
336 *
337 * This is an internal function that is used by objects with sub-items
338 * that want to provide different cursors for each of them. The @a
339 * owner object should be an elm_widget and will be used to track
340 * theme changes and to feed @a func and @a del_cb. The @a eventarea
341 * may be any object and is the one that should be used later on with
342 * elm_object_cursor apis, such as elm_object_cursor_unset().
343 *
344 * @param eventarea the object being attached a cursor.
345 * @param owner the elm_widget that owns this object, will be used to
346 * track theme changes and to be used in @a func or @a del_cb.
347 * @param cursor the cursor name to be used.
348 *
349 * @internal
350 * @ingroup Cursors
351 */
352void
353elm_object_sub_cursor_set(Evas_Object *eventarea, Evas_Object *owner, const char *cursor)
354{
355 Elm_Cursor *cur = NULL;
356
357 cur = evas_object_data_get(eventarea, _cursor_key);
358 if (cur)
359 elm_object_cursor_unset(eventarea);
360
361 if (!cursor) return;
362
363 cur = ELM_NEW(Elm_Cursor);
364 if (!cur) return;
365
366 cur->owner = owner;
367 cur->eventarea = eventarea;
368 cur->engine_only = _elm_config->cursor_engine_only;
369 cur->visible = EINA_FALSE;
370
371 cur->cursor_name = eina_stringshare_add(cursor);
372 if (!cur->cursor_name)
373 ERR("Could not store cursor name %s", cursor);
374
375 cur->evas = evas_object_evas_get(eventarea);
376 cur->ee = ecore_evas_ecore_evas_get(cur->evas);
377
378 _elm_cursor_cur_set(cur);
379
380 evas_object_data_set(eventarea, _cursor_key, cur);
381
382 evas_object_event_callback_add(eventarea, EVAS_CALLBACK_MOUSE_IN,
383 _elm_cursor_mouse_in, cur);
384 evas_object_event_callback_add(eventarea, EVAS_CALLBACK_MOUSE_OUT,
385 _elm_cursor_mouse_out, cur);
386 evas_object_event_callback_add(eventarea, EVAS_CALLBACK_DEL,
387 _elm_cursor_del, cur);
388}
389
390EAPI void
391elm_object_cursor_set(Evas_Object *obj, const char *cursor)
392{
393 EINA_SAFETY_ON_NULL_RETURN(obj);
394 elm_object_sub_cursor_set(obj, obj, cursor);
395}
396
397EAPI const char *
398elm_object_cursor_get(const Evas_Object *obj)
399{
400 ELM_CURSOR_GET_OR_RETURN(cur, obj, NULL);
401 return cur->cursor_name;
402}
403
404EAPI void
405elm_object_cursor_unset(Evas_Object *obj)
406{
407 ELM_CURSOR_GET_OR_RETURN(cur, obj);
408
409 eina_stringshare_del(cur->cursor_name);
410 eina_stringshare_del(cur->style);
411
412 if (cur->owner)
413 elm_widget_cursor_del(cur->owner, cur);
414
415 if (cur->obj)
416 evas_object_del(cur->obj);
417
418 if (cur->visible)
419 {
420 if (!cur->use_engine)
421 ecore_evas_object_cursor_set(cur->ee, NULL, ELM_OBJECT_LAYER_CURSOR,
422 cur->hot_x, cur->hot_y);
423#ifdef HAVE_ELEMENTARY_X
424 else if (cur->win)
425 ecore_x_window_cursor_set(cur->win, ECORE_X_CURSOR_X);
426#endif
427 }
428
429 evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_IN,
430 _elm_cursor_mouse_in);
431 evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_OUT,
432 _elm_cursor_mouse_out);
433 evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _elm_cursor_del);
434
435 evas_object_data_del(obj, _cursor_key);
436 free(cur);
437}
438
439EAPI void
440elm_object_cursor_style_set(Evas_Object *obj, const char *style)
441{
442 ELM_CURSOR_GET_OR_RETURN(cur, obj);
443
444 if (!eina_stringshare_replace(&cur->style, style))
445 ERR("Could not set current style=%s", style);
446
447 if (cur->use_engine) return;
448
449 if (!cur->obj)
450 {
451 if (!_elm_cursor_obj_add(obj, cur))
452 ERR("Could not create cursor object");
453 else
454 _elm_cursor_set_hot_spots(cur);
455 }
456 else
457 {
458 if (!_elm_theme_object_set(obj, cur->obj, "cursor", cur->cursor_name,
459 style))
460 ERR("Could not apply the theme to the cursor style=%s", style);
461 else
462 _elm_cursor_set_hot_spots(cur);
463 }
464}
465
466EAPI const char *
467elm_object_cursor_style_get(const Evas_Object *obj)
468{
469 ELM_CURSOR_GET_OR_RETURN(cur, obj, NULL);
470 return cur->style ? cur->style : "default";
471}
472
473/**
474 * Notify cursor should recalculate its theme.
475 * @internal
476 */
477void
478elm_cursor_theme(Elm_Cursor *cur)
479{
480 if ((!cur) || (!cur->obj)) return;
481 if (!_elm_theme_object_set(cur->eventarea, cur->obj, "cursor",
482 cur->cursor_name, cur->style))
483 ERR("Could not apply the theme to the cursor style=%s", cur->style);
484 else
485 _elm_cursor_set_hot_spots(cur);
486}
487
488EAPI void elm_object_cursor_theme_search_enabled_set(Evas_Object *obj, Eina_Bool theme_search)
489{
490 ELM_CURSOR_GET_OR_RETURN(cur, obj);
491 cur->engine_only = theme_search;
492 if (cur->obj)
493 {
494 evas_object_del(cur->obj);
495 cur->obj = NULL;
496 }
497 _elm_cursor_cur_set(cur);
498}
499
500
501EAPI Eina_Bool
502elm_object_cursor_theme_search_enabled_get(const Evas_Object *obj)
503{
504 ELM_CURSOR_GET_OR_RETURN(cur, obj, EINA_FALSE);
505 return cur->engine_only;
506}