1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4
5 #include <Elementary.h>
6 #include <Elementary_Cursor.h>
7
8 #include "elm_priv.h"
9
10 #ifdef HAVE_ELEMENTARY_X
11 #include <Ecore_X.h>
12 #include <Ecore_X_Cursor.h>
13 #endif
14
15 #ifdef HAVE_ELEMENTARY_WIN32
16 #include <Ecore_Win32.h>
17 #endif
18
19 #define _cursor_key "_elm_cursor"
20
21 struct _Cursor_Id
22 {
23 const char *name;
24
25 #if defined(HAVE_ELEMENTARY_X) || defined(HAVE_ELEMENTARY_COCOA) || defined(HAVE_ELEMENTARY_WIN32)
26 int id; /* For X */
27 int cid; /* For Cocoa */
28 #endif
29 };
30
31 #if defined(HAVE_ELEMENTARY_X)
32 # if defined(HAVE_ELEMENTARY_COCOA)
33 # define CURSOR(_name, _id, _cid) {_name, ECORE_X_CURSOR_##_id, _cid}
34 # else
35 # define CURSOR(_name, _id, _cid) { _name, ECORE_X_CURSOR_##_id, -1 }
36 # endif
37 #elif defined(HAVE_ELEMENTARY_COCOA)
38 # define CURSOR(_name, _id, _cid) {_name, -1, _cid}
39 #elif defined(HAVE_ELEMENTARY_WIN32)
40 # define CURSOR(_name, _id, _cid) {_name, ECORE_WIN32_CURSOR_X11_SHAPE_##_id, -1 }
41 #else
42 # define CURSOR(_name, _id, _cid) { _name }
43 #endif
44
45 #if defined(HAVE_ELEMENTARY_X) || defined(HAVE_ELEMENTARY_COCOA) || defined(HAVE_ELEMENTARY_WIN32)
46 /* Please keep order in sync with Ecore_X_Cursor.h values! */
47 static struct _Cursor_Id _cursors[] =
48 {
49 CURSOR(ELM_CURSOR_X , X , ECORE_COCOA_CURSOR_CROSSHAIR),
50 CURSOR(ELM_CURSOR_ARROW , ARROW , ECORE_COCOA_CURSOR_ARROW),
51 CURSOR(ELM_CURSOR_BASED_ARROW_DOWN , BASED_ARROW_DOWN , ECORE_COCOA_CURSOR_DEFAULT),
52 CURSOR(ELM_CURSOR_BASED_ARROW_UP , UP , ECORE_COCOA_CURSOR_DEFAULT),
53 CURSOR(ELM_CURSOR_BOAT , BOAT , ECORE_COCOA_CURSOR_DEFAULT),
54 CURSOR(ELM_CURSOR_BOGOSITY , BOGOSITY , ECORE_COCOA_CURSOR_DEFAULT),
55 CURSOR(ELM_CURSOR_BOTTOM_LEFT_CORNER , BOTTOM_LEFT_CORNER , ECORE_COCOA_CURSOR_DEFAULT),
56 CURSOR(ELM_CURSOR_BOTTOM_RIGHT_CORNER, BOTTOM_RIGHT_CORNER, ECORE_COCOA_CURSOR_DEFAULT),
57 CURSOR(ELM_CURSOR_BOTTOM_SIDE , BOTTOM_SIDE , ECORE_COCOA_CURSOR_RESIZE_DOWN),
58 CURSOR(ELM_CURSOR_BOTTOM_TEE , BOTTOM_TEE , ECORE_COCOA_CURSOR_RESIZE_DOWN),
59 CURSOR(ELM_CURSOR_BOX_SPIRAL , BOX_SPIRAL , ECORE_COCOA_CURSOR_DEFAULT),
60 CURSOR(ELM_CURSOR_CENTER_PTR , CENTER_PTR , ECORE_COCOA_CURSOR_DEFAULT),
61 CURSOR(ELM_CURSOR_CIRCLE , CIRCLE , ECORE_COCOA_CURSOR_DEFAULT),
62 CURSOR(ELM_CURSOR_CLOCK , CLOCK , ECORE_COCOA_CURSOR_DEFAULT),
63 CURSOR(ELM_CURSOR_COFFEE_MUG , COFFEE_MUG , ECORE_COCOA_CURSOR_DEFAULT),
64 CURSOR(ELM_CURSOR_CROSS , CROSS , ECORE_COCOA_CURSOR_CROSSHAIR),
65 CURSOR(ELM_CURSOR_CROSS_REVERSE , CROSS_REVERSE , ECORE_COCOA_CURSOR_CROSSHAIR),
66 CURSOR(ELM_CURSOR_CROSSHAIR , CROSSHAIR , ECORE_COCOA_CURSOR_CROSSHAIR),
67 CURSOR(ELM_CURSOR_DIAMOND_CROSS , DIAMOND_CROSS , ECORE_COCOA_CURSOR_DEFAULT),
68 CURSOR(ELM_CURSOR_DOT , DOT , ECORE_COCOA_CURSOR_DEFAULT),
69 CURSOR(ELM_CURSOR_DOT_BOX_MASK , DOT_BOX_MASK , ECORE_COCOA_CURSOR_DEFAULT),
70 CURSOR(ELM_CURSOR_DOUBLE_ARROW , DOUBLE_ARROW , ECORE_COCOA_CURSOR_RESIZE_UP_DOWN),
71 CURSOR(ELM_CURSOR_DRAFT_LARGE , DRAFT_LARGE , ECORE_COCOA_CURSOR_DEFAULT),
72 CURSOR(ELM_CURSOR_DRAFT_SMALL , DRAFT_SMALL , ECORE_COCOA_CURSOR_DEFAULT),
73 CURSOR(ELM_CURSOR_DRAPED_BOX , DRAPED_BOX , ECORE_COCOA_CURSOR_DEFAULT),
74 CURSOR(ELM_CURSOR_EXCHANGE , EXCHANGE , ECORE_COCOA_CURSOR_DEFAULT),
75 CURSOR(ELM_CURSOR_FLEUR , FLEUR , ECORE_COCOA_CURSOR_CLOSED_HAND),
76 CURSOR(ELM_CURSOR_GOBBLER , GOBBLER , ECORE_COCOA_CURSOR_DEFAULT),
77 CURSOR(ELM_CURSOR_GUMBY , GUMBY , ECORE_COCOA_CURSOR_DEFAULT),
78 CURSOR(ELM_CURSOR_HAND1 , HAND1 , ECORE_COCOA_CURSOR_POINTING_HAND),
79 CURSOR(ELM_CURSOR_HAND2 , HAND2 , ECORE_COCOA_CURSOR_POINTING_HAND),
80 CURSOR(ELM_CURSOR_HEART , HEART , ECORE_COCOA_CURSOR_DEFAULT),
81 CURSOR(ELM_CURSOR_ICON , ICON , ECORE_COCOA_CURSOR_DEFAULT),
82 CURSOR(ELM_CURSOR_IRON_CROSS , IRON_CROSS , ECORE_COCOA_CURSOR_DEFAULT),
83 CURSOR(ELM_CURSOR_LEFT_PTR , LEFT_PTR , ECORE_COCOA_CURSOR_ARROW),
84 CURSOR(ELM_CURSOR_LEFT_SIDE , LEFT_SIDE , ECORE_COCOA_CURSOR_RESIZE_LEFT),
85 CURSOR(ELM_CURSOR_LEFT_TEE , LEFT_TEE , ECORE_COCOA_CURSOR_RESIZE_LEFT),
86 CURSOR(ELM_CURSOR_LEFTBUTTON , LEFTBUTTON , ECORE_COCOA_CURSOR_DEFAULT),
87 CURSOR(ELM_CURSOR_LL_ANGLE , LL_ANGLE , ECORE_COCOA_CURSOR_DEFAULT),
88 CURSOR(ELM_CURSOR_LR_ANGLE , LR_ANGLE , ECORE_COCOA_CURSOR_DEFAULT),
89 CURSOR(ELM_CURSOR_MAN , MAN , ECORE_COCOA_CURSOR_DEFAULT),
90 CURSOR(ELM_CURSOR_MIDDLEBUTTON , MIDDLEBUTTON , ECORE_COCOA_CURSOR_DEFAULT),
91 CURSOR(ELM_CURSOR_MOUSE , MOUSE , ECORE_COCOA_CURSOR_DEFAULT),
92 CURSOR(ELM_CURSOR_PENCIL , PENCIL , ECORE_COCOA_CURSOR_DEFAULT),
93 CURSOR(ELM_CURSOR_PIRATE , PIRATE , ECORE_COCOA_CURSOR_DEFAULT),
94 CURSOR(ELM_CURSOR_PLUS , PLUS , ECORE_COCOA_CURSOR_CROSSHAIR),
95 CURSOR(ELM_CURSOR_QUESTION_ARROW , QUESTION_ARROW , ECORE_COCOA_CURSOR_DEFAULT),
96 CURSOR(ELM_CURSOR_RIGHT_PTR , RIGHT_PTR , ECORE_COCOA_CURSOR_DEFAULT),
97 CURSOR(ELM_CURSOR_RIGHT_SIDE , RIGHT_SIDE , ECORE_COCOA_CURSOR_RESIZE_RIGHT),
98 CURSOR(ELM_CURSOR_RIGHT_TEE , RIGHT_TEE , ECORE_COCOA_CURSOR_RESIZE_RIGHT),
99 CURSOR(ELM_CURSOR_RIGHTBUTTON , RIGHTBUTTON , ECORE_COCOA_CURSOR_DEFAULT),
100 CURSOR(ELM_CURSOR_RTL_LOGO , RTL_LOGO , ECORE_COCOA_CURSOR_DEFAULT),
101 CURSOR(ELM_CURSOR_SAILBOAT , SAILBOAT , ECORE_COCOA_CURSOR_DEFAULT),
102 CURSOR(ELM_CURSOR_SB_DOWN_ARROW , SB_DOWN_ARROW , ECORE_COCOA_CURSOR_RESIZE_DOWN),
103 CURSOR(ELM_CURSOR_SB_H_DOUBLE_ARROW , SB_H_DOUBLE_ARROW , ECORE_COCOA_CURSOR_RESIZE_LEFT_RIGHT),
104 CURSOR(ELM_CURSOR_SB_LEFT_ARROW , SB_LEFT_ARROW , ECORE_COCOA_CURSOR_RESIZE_LEFT),
105 CURSOR(ELM_CURSOR_SB_RIGHT_ARROW , SB_RIGHT_ARROW , ECORE_COCOA_CURSOR_RESIZE_RIGHT),
106 CURSOR(ELM_CURSOR_SB_UP_ARROW , SB_UP_ARROW , ECORE_COCOA_CURSOR_RESIZE_UP),
107 CURSOR(ELM_CURSOR_SB_V_DOUBLE_ARROW , SB_V_DOUBLE_ARROW , ECORE_COCOA_CURSOR_RESIZE_UP_DOWN),
108 CURSOR(ELM_CURSOR_SHUTTLE , SHUTTLE , ECORE_COCOA_CURSOR_DEFAULT),
109 CURSOR(ELM_CURSOR_SIZING , SIZING , ECORE_COCOA_CURSOR_DEFAULT),
110 CURSOR(ELM_CURSOR_SPIDER , SPIDER , ECORE_COCOA_CURSOR_DEFAULT),
111 CURSOR(ELM_CURSOR_SPRAYCAN , SPRAYCAN , ECORE_COCOA_CURSOR_DEFAULT),
112 CURSOR(ELM_CURSOR_STAR , STAR , ECORE_COCOA_CURSOR_DEFAULT),
113 CURSOR(ELM_CURSOR_TARGET , TARGET , ECORE_COCOA_CURSOR_DEFAULT),
114 CURSOR(ELM_CURSOR_TCROSS , TCROSS , ECORE_COCOA_CURSOR_CROSSHAIR),
115 CURSOR(ELM_CURSOR_TOP_LEFT_ARROW , TOP_LEFT_ARROW , ECORE_COCOA_CURSOR_DEFAULT),
116 CURSOR(ELM_CURSOR_TOP_LEFT_CORNER , TOP_LEFT_CORNER , ECORE_COCOA_CURSOR_DEFAULT),
117 CURSOR(ELM_CURSOR_TOP_RIGHT_CORNER , TOP_RIGHT_CORNER , ECORE_COCOA_CURSOR_DEFAULT),
118 CURSOR(ELM_CURSOR_TOP_SIDE , TOP_SIDE , ECORE_COCOA_CURSOR_RESIZE_UP),
119 CURSOR(ELM_CURSOR_TOP_TEE , TOP_TEE , ECORE_COCOA_CURSOR_RESIZE_UP),
120 CURSOR(ELM_CURSOR_TREK , TREK , ECORE_COCOA_CURSOR_DEFAULT),
121 CURSOR(ELM_CURSOR_UL_ANGLE , UL_ANGLE , ECORE_COCOA_CURSOR_DEFAULT),
122 CURSOR(ELM_CURSOR_UMBRELLA , UMBRELLA , ECORE_COCOA_CURSOR_DEFAULT),
123 CURSOR(ELM_CURSOR_UR_ANGLE , UR_ANGLE , ECORE_COCOA_CURSOR_DEFAULT),
124 CURSOR(ELM_CURSOR_WATCH , WATCH , ECORE_COCOA_CURSOR_DEFAULT),
125 CURSOR(ELM_CURSOR_XTERM , XTERM , ECORE_COCOA_CURSOR_IBEAM)
126 };
127
128 static const int _cursors_count = sizeof(_cursors)/sizeof(struct _Cursor_Id);
129 #endif
130
131 #define ELM_CURSOR_GET_OR_RETURN(cur, obj, ...) \
132 Elm_Cursor *cur; \
133 do \
134 { \
135 if (!(obj)) \
136 { \
137 CRI("Null pointer: " #obj); \
138 return __VA_ARGS__; \
139 } \
140 cur = evas_object_data_get((obj), _cursor_key); \
141 if (!cur) \
142 { \
143 ERR("Object does not have cursor: " #obj); \
144 return __VA_ARGS__; \
145 } \
146 } \
147 while (0)
148
149 struct _Elm_Cursor
150 {
151 Evas_Object *obj, *hotobj;
152 Evas_Object *eventarea, *owner;
153 const char *style, *cursor_name;
154 int hot_x, hot_y;
155 Ecore_Evas *ee;
156 Evas *evas;
157 Ecore_Job *hotupdate_job;
158 #ifdef HAVE_ELEMENTARY_X
159 struct {
160 Ecore_X_Cursor cursor;
161 Ecore_X_Window win;
162 } x;
163 #endif
164 #ifdef HAVE_ELEMENTARY_WL2
165 struct {
166 Ecore_Wl2_Window *win;
167 } wl;
168 #endif
169 #ifdef HAVE_ELEMENTARY_WIN32
170 struct {
171 Ecore_Win32_Cursor *cursor;
172 Ecore_Win32_Window *win;
173 } win32;
174 #endif
175
176 #ifdef HAVE_ELEMENTARY_COCOA
177 struct {
178 Ecore_Cocoa_Cursor cursor;
179 Ecore_Cocoa_Window *win;
180 } cocoa;
181 #endif
182 struct
183 {
184 Evas_Object *obj;
185 int layer;
186 int x, y;
187 } prev;
188
189 Eina_Bool visible:1;
190 Eina_Bool use_engine:1;
191 Eina_Bool theme_search:1;
192 };
193
194 static void
_elm_cursor_obj_hints(void * data,Evas * evas EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)195 _elm_cursor_obj_hints(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
196 {
197 Elm_Cursor *cur = data;
198 int x, y;
199
200 evas_object_size_hint_min_get(cur->obj, &x, &y);
201 if ((x < 8) || (y < 8))
202 {
203 x = 8;
204 y = 8;
205 }
206 evas_object_resize(cur->obj, x, y);
207 }
208
209 static void
_elm_cursor_obj_del(void * data,Evas * evas EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)210 _elm_cursor_obj_del(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
211 {
212 Elm_Cursor *cur = data;
213
214 if (cur)
215 {
216 evas_object_event_callback_del_full(cur->obj, EVAS_CALLBACK_DEL,
217 _elm_cursor_obj_del, cur);
218 evas_object_event_callback_del_full(cur->obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
219 _elm_cursor_obj_hints, cur);
220 cur->obj = NULL;
221 ELM_SAFE_FREE(cur->hotobj, evas_object_del);
222 }
223 }
224
225 static void
_elm_cursor_set_hot_spots(Elm_Cursor * cur)226 _elm_cursor_set_hot_spots(Elm_Cursor *cur)
227 {
228 const char *str;
229 Evas_Coord cx, cy, cw, ch, x, y, w, h;
230 int prev_hot_x, prev_hot_y;
231
232 if (!cur->visible) return;
233
234 prev_hot_x = cur->hot_x;
235 prev_hot_y = cur->hot_y;
236
237 evas_object_geometry_get(cur->obj, &cx, &cy, &cw, &ch);
238 evas_object_geometry_get(cur->hotobj, &x, &y, &w, &h);
239 cur->hot_x = (x + (w / 2)) - cx;
240 cur->hot_y = (y + (h / 2)) - cy;
241
242 str = edje_object_data_get(cur->obj, "hot_x");
243 if (str) cur->hot_x = atoi(str);
244 str = edje_object_data_get(cur->obj, "hot_y");
245 if (str) cur->hot_y = atoi(str);
246
247 if ((cur->visible) &&
248 ((prev_hot_x != cur->hot_x) || (prev_hot_y != cur->hot_y)))
249 {
250 ecore_evas_object_cursor_set(cur->ee, cur->obj,
251 ELM_OBJECT_LAYER_CURSOR,
252 cur->hot_x, cur->hot_y);
253 }
254 }
255
256 static void
_elm_cursor_set_hot_spots_job(void * data)257 _elm_cursor_set_hot_spots_job(void *data)
258 {
259 Elm_Cursor *cur = data;
260
261 cur->hotupdate_job = NULL;
262
263 _elm_cursor_set_hot_spots(cur);
264 }
265
266 static void
_elm_cursor_hot_change(void * data,Evas * evas EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)267 _elm_cursor_hot_change(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
268 {
269 Elm_Cursor *cur = data;
270 if (cur->hotupdate_job) ecore_job_del(cur->hotupdate_job);
271 cur->hotupdate_job = ecore_job_add(_elm_cursor_set_hot_spots_job, data);
272 }
273
274 static Eina_Bool
_elm_cursor_obj_add(Evas_Object * obj,Elm_Cursor * cur)275 _elm_cursor_obj_add(Evas_Object *obj, Elm_Cursor *cur)
276 {
277 #ifdef HAVE_ELEMENTARY_WL2
278 const char *engine_name;
279
280 engine_name = ecore_evas_engine_name_get(cur->ee);
281 if ((engine_name) &&
282 ((!strcmp(engine_name, ELM_WAYLAND_SHM)) ||
283 (!strcmp(engine_name, ELM_WAYLAND_EGL))))
284 return EINA_FALSE;
285 #endif
286
287 cur->obj = edje_object_add(cur->evas);
288 if (!cur->obj) return EINA_FALSE;
289 edje_object_freeze(cur->obj);
290 edje_object_update_hints_set(cur->obj, 1);
291
292 if (elm_widget_theme_object_set(obj, cur->obj, "cursor", cur->cursor_name,
293 cur->style ? cur->style : "default") == EFL_UI_THEME_APPLY_ERROR_GENERIC)
294 {
295 ELM_SAFE_FREE(cur->obj, evas_object_del);
296 return EINA_FALSE;
297 }
298 evas_object_data_set(cur->obj, "elm-cursor", (void*)1);
299 cur->hotobj = evas_object_rectangle_add(cur->evas);
300 evas_object_color_set(cur->hotobj, 0, 0, 0, 0);
301 evas_object_event_callback_add(cur->obj, EVAS_CALLBACK_MOVE,
302 _elm_cursor_hot_change, cur);
303 evas_object_event_callback_add(cur->obj, EVAS_CALLBACK_RESIZE,
304 _elm_cursor_hot_change, cur);
305 evas_object_event_callback_add(cur->hotobj, EVAS_CALLBACK_MOVE,
306 _elm_cursor_hot_change, cur);
307 evas_object_event_callback_add(cur->hotobj, EVAS_CALLBACK_RESIZE,
308 _elm_cursor_hot_change, cur);
309
310 if (elm_widget_is_legacy(obj))
311 {
312 if (edje_object_part_exists(cur->obj, "elm.swallow.hotspot"))
313 edje_object_part_swallow(cur->obj, "elm.swallow.hotspot", cur->hotobj);
314 else if (edje_object_part_exists(cur->obj, "elm.content.hotspot"))
315 edje_object_part_swallow(cur->obj, "elm.content.hotspot", cur->hotobj);
316 else
317 {
318 ELM_SAFE_FREE(cur->hotobj, evas_object_del);
319 ELM_SAFE_FREE(cur->obj, evas_object_del);
320 return EINA_FALSE;
321 }
322 }
323 else
324 {
325 if (edje_object_part_exists(cur->obj, "efl.hotspot"))
326 edje_object_part_swallow(cur->obj, "efl.hotspot", cur->hotobj);
327 else if (edje_object_part_exists(cur->obj, "efl.content.hotspot"))
328 edje_object_part_swallow(cur->obj, "efl.content.hotspot", cur->hotobj);
329 else
330 {
331 ELM_SAFE_FREE(cur->hotobj, evas_object_del);
332 ELM_SAFE_FREE(cur->obj, evas_object_del);
333 return EINA_FALSE;
334 }
335 }
336
337 evas_object_event_callback_add(cur->obj, EVAS_CALLBACK_DEL,
338 _elm_cursor_obj_del, cur);
339 evas_object_event_callback_add(cur->obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
340 _elm_cursor_obj_hints, cur);
341 edje_object_thaw(cur->obj);
342
343 return EINA_TRUE;
344 }
345
346 static void
_elm_cursor_set(Elm_Cursor * cur)347 _elm_cursor_set(Elm_Cursor *cur)
348 {
349 evas_event_freeze(cur->evas);
350 if (!cur->use_engine)
351 {
352 if (cur->visible) goto end;
353
354 if (!cur->obj)
355 _elm_cursor_obj_add(cur->owner, cur);
356 if (cur->obj)
357 {
358 ecore_evas_cursor_get(cur->ee, &cur->prev.obj, &cur->prev.layer, &cur->prev.x, &cur->prev.y);
359 if (cur->prev.obj)
360 {
361 if (evas_object_data_get(cur->prev.obj, "elm-cursor"))
362 memset(&cur->prev, 0, sizeof(cur->prev));
363 else
364 ecore_evas_cursor_unset(cur->ee);
365 }
366 ecore_evas_object_cursor_set(cur->ee, cur->obj,
367 ELM_OBJECT_LAYER_CURSOR, cur->hot_x,
368 cur->hot_y);
369 }
370 cur->visible = !!cur->obj;
371 }
372 else
373 {
374 cur->visible = EINA_TRUE;
375 if (cur->obj)
376 {
377 evas_object_del(cur->obj);
378 cur->obj = NULL;
379 ELM_SAFE_FREE(cur->hotobj, evas_object_del);
380 }
381 #ifdef HAVE_ELEMENTARY_X
382 if (cur->x.win)
383 ecore_x_window_cursor_set(cur->x.win, cur->x.cursor);
384 #endif
385 #ifdef HAVE_ELEMENTARY_WL2
386 if (cur->wl.win)
387 {
388 Evas_Object *top;
389
390 top = elm_widget_top_get(cur->owner);
391 if ((top) && (efl_isa(top, EFL_UI_WIN_CLASS)))
392 _elm_win_wl_cursor_set(top, cur->cursor_name);
393 }
394 #endif
395
396 #ifdef HAVE_ELEMENTARY_COCOA
397 if (cur->cocoa.win)
398 ecore_cocoa_window_cursor_set(cur->cocoa.win, cur->cocoa.cursor);
399 #endif
400
401 #ifdef HAVE_ELEMENTARY_WIN32
402 if (cur->win32.win)
403 ecore_win32_window_cursor_set(cur->win32.win, cur->win32.cursor);
404 #endif
405 }
406 end:
407 evas_event_thaw(cur->evas);
408 }
409
410 static void
_elm_cursor_mouse_in(void * data,Evas * evas EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info)411 _elm_cursor_mouse_in(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
412 {
413 Elm_Cursor *cur = data;
414
415 Evas_Event_Mouse_In *ev = event_info;
416 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
417
418 _elm_cursor_set(cur);
419 }
420
421 static void
_elm_cursor_mouse_out(void * data,Evas * evas EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info)422 _elm_cursor_mouse_out(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
423 {
424 Evas_Object *sobj_parent;
425 Elm_Cursor *pcur = NULL;
426 Elm_Cursor *cur = data;
427
428 Evas_Event_Mouse_Out *ev = event_info;
429 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
430
431 if (!cur->visible) return;
432 evas_event_freeze(cur->evas);
433 cur->visible = EINA_FALSE;
434
435 sobj_parent = evas_object_data_get(cur->eventarea, "elm-parent");
436 while (sobj_parent)
437 {
438 pcur = evas_object_data_get((sobj_parent), _cursor_key);
439 if ((pcur) && (pcur->visible)) break;
440 sobj_parent = evas_object_data_get(sobj_parent, "elm-parent");
441 }
442
443 if (pcur)
444 {
445 pcur->visible = EINA_FALSE;
446 evas_event_thaw(cur->evas);
447 _elm_cursor_set(pcur);
448 return;
449 }
450
451 if (!cur->use_engine)
452 {
453 if (cur->prev.obj)
454 ecore_evas_object_cursor_set(cur->ee, cur->prev.obj, cur->prev.layer,
455 cur->prev.x, cur->prev.y);
456 else
457 ecore_evas_object_cursor_set(cur->ee, NULL, ELM_OBJECT_LAYER_CURSOR,
458 cur->hot_x, cur->hot_y);
459 memset(&cur->prev, 0, sizeof(cur->prev));
460 }
461 else
462 {
463 #ifdef HAVE_ELEMENTARY_X
464 if (cur->x.win)
465 ecore_x_window_cursor_set(cur->x.win, ECORE_X_CURSOR_X);
466 #endif
467 #ifdef HAVE_ELEMENTARY_WL2
468 if (cur->wl.win)
469 {
470 Evas_Object *top;
471
472 top = elm_widget_top_get(cur->owner);
473 if ((top) && (efl_isa(top, EFL_UI_WIN_CLASS)))
474 _elm_win_wl_cursor_set(top, NULL);
475 }
476 #endif
477
478 #ifdef HAVE_ELEMENTARY_COCOA
479 if (cur->cocoa.win)
480 ecore_cocoa_window_cursor_set(cur->cocoa.win, ECORE_COCOA_CURSOR_DEFAULT);
481 #endif
482
483 #ifdef HAVE_ELEMENTARY_WIN32
484 if (cur->win32.win)
485 ecore_win32_window_cursor_set(cur->win32.win, ecore_win32_cursor_shaped_new(ECORE_WIN32_CURSOR_SHAPE_ARROW));
486 #endif
487 }
488 evas_event_thaw(cur->evas);
489 }
490
491 static void
_elm_cursor_del(void * data EINA_UNUSED,Evas * evas EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)492 _elm_cursor_del(void *data EINA_UNUSED, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
493 {
494 elm_object_cursor_unset(obj);
495 }
496
497 #if defined(HAVE_ELEMENTARY_X) || defined(HAVE_ELEMENTARY_COCOA) || defined(HAVE_ELEMENTARY_WIN32)
498 static int
_elm_cursor_strcmp(const void * data1,const void * data2)499 _elm_cursor_strcmp(const void *data1, const void *data2)
500 {
501 const struct _Cursor_Id *c1 = data1;
502 const struct _Cursor_Id *c2 = data2;
503 return strcmp (c1->name, c2->name);
504 }
505 #endif
506
507 static void
_elm_cursor_cur_set(Elm_Cursor * cur)508 _elm_cursor_cur_set(Elm_Cursor *cur)
509 {
510 if (!cur->theme_search)
511 {
512 INF("Using only engine cursors");
513 cur->use_engine = EINA_TRUE;
514 }
515 else if (_elm_cursor_obj_add(cur->owner, cur))
516 {
517 _elm_cursor_set_hot_spots(cur);
518 cur->use_engine = EINA_FALSE;
519 elm_widget_cursor_add(cur->owner, cur);
520 }
521 else
522 {
523 INF("Cursor couldn't be found on theme: %s", cur->cursor_name);
524 cur->use_engine = EINA_TRUE;
525 }
526
527 #ifdef HAVE_ELEMENTARY_DRM
528 const char *engine_name;
529
530 engine_name = ecore_evas_engine_name_get(cur->ee);
531 if ((engine_name) && (!strcmp(engine_name, ELM_DRM)))
532 cur->use_engine = EINA_FALSE;
533 #endif
534
535 if (cur->use_engine)
536 {
537 Evas_Object *top;
538
539 top = elm_widget_top_get(cur->owner);
540 if ((top) && (efl_isa(top, EFL_UI_WIN_CLASS)))
541 {
542 #ifdef HAVE_ELEMENTARY_X
543 cur->x.win = elm_win_xwindow_get(top);
544 if (cur->x.win)
545 {
546 struct _Cursor_Id *cur_id;
547
548 cur_id = bsearch(&(cur->cursor_name), _cursors, _cursors_count,
549 sizeof(struct _Cursor_Id), _elm_cursor_strcmp);
550
551 if (!cur_id)
552 {
553 INF("X cursor couldn't be found: %s. Using default.",
554 cur->cursor_name);
555 cur->x.cursor = ecore_x_cursor_shape_get(ECORE_X_CURSOR_X);
556 }
557 else
558 cur->x.cursor = ecore_x_cursor_shape_get(cur_id->id);
559 }
560 #endif
561
562 #ifdef HAVE_ELEMENTARY_COCOA
563 cur->cocoa.win = elm_win_cocoa_window_get(top);
564 if (cur->cocoa.win)
565 {
566 struct _Cursor_Id *cur_id;
567
568 cur_id = bsearch(&(cur->cursor_name), _cursors, _cursors_count,
569 sizeof(struct _Cursor_Id), _elm_cursor_strcmp);
570 if (!cur_id)
571 {
572 INF("Cocoa Cursor couldn't be found: %s. Using default...",
573 cur->cursor_name);
574 cur->cocoa.cursor = ECORE_COCOA_CURSOR_DEFAULT;
575 }
576 else
577 cur->cocoa.cursor = cur_id->cid;
578 }
579 #endif
580 #ifdef HAVE_ELEMENTARY_WL2
581 cur->wl.win = elm_win_wl_window_get(top);
582 #endif
583 #ifdef HAVE_ELEMENTARY_WIN32
584 cur->win32.win = elm_win_win32_window_get(top);
585 if (cur->win32.win)
586 {
587 struct _Cursor_Id *cur_id;
588
589 cur_id = bsearch(&(cur->cursor_name), _cursors, _cursors_count,
590 sizeof(struct _Cursor_Id), _elm_cursor_strcmp);
591
592 if (!cur_id)
593 {
594 INF("Win32 X cursor couldn't be found: %s. Using default.",
595 cur->cursor_name);
596 cur->win32.cursor = ecore_win32_cursor_shaped_new(ECORE_WIN32_CURSOR_SHAPE_ARROW);
597 }
598 else
599 cur->win32.cursor = (Ecore_Win32_Cursor *)ecore_win32_cursor_x11_shaped_get(cur_id->id);
600 }
601 #endif
602 }
603 }
604
605 if (efl_canvas_pointer_inside_get(cur->eventarea, NULL))
606 _elm_cursor_set(cur);
607 }
608
609 /**
610 * Set the cursor to be shown when mouse is over the object
611 *
612 * Set the cursor that will be displayed when mouse is over the
613 * object. The object can have only one cursor set to it, so if
614 * this function is called twice for an object, the previous set
615 * will be unset.
616 * If using X cursors, a definition of all the valid cursor names
617 * is listed on Elementary_Cursors.h. If an invalid name is set
618 * the default cursor will be used.
619 *
620 * This is an internal function that is used by objects with sub-items
621 * that want to provide different cursors for each of them. The @a
622 * owner object should be an elm_widget and will be used to track
623 * theme changes and to feed @a func and @a del_cb. The @a eventarea
624 * may be any object and is the one that should be used later on with
625 * elm_object_cursor apis, such as elm_object_cursor_unset().
626 *
627 * @param eventarea the object being attached a cursor.
628 * @param owner the elm_widget that owns this object, will be used to
629 * track theme changes and to be used in @a func or @a del_cb.
630 * @param cursor the cursor name to be used.
631 *
632 * @internal
633 * @ingroup Elm_Cursors
634 */
635 void
elm_object_sub_cursor_set(Evas_Object * eventarea,Evas_Object * owner,const char * cursor)636 elm_object_sub_cursor_set(Evas_Object *eventarea, Evas_Object *owner, const char *cursor)
637 {
638 Elm_Cursor *cur = NULL;
639
640 cur = evas_object_data_get(eventarea, _cursor_key);
641 if (cur)
642 elm_object_cursor_unset(eventarea);
643
644 if (!cursor) return;
645
646 cur = ELM_NEW(Elm_Cursor);
647 if (!cur) return;
648
649 cur->owner = owner;
650 cur->eventarea = eventarea;
651 cur->theme_search = !_elm_config->cursor_engine_only;
652 cur->visible = EINA_FALSE;
653 cur->style = eina_stringshare_add("default");
654
655 cur->cursor_name = eina_stringshare_add(cursor);
656 if (!cur->cursor_name)
657 ERR("Could not store cursor name %s", cursor);
658
659 cur->evas = evas_object_evas_get(eventarea);
660 cur->ee = ecore_evas_ecore_evas_get(cur->evas);
661
662 _elm_cursor_cur_set(cur);
663
664 evas_object_data_set(eventarea, _cursor_key, cur);
665
666 evas_object_event_callback_add(eventarea, EVAS_CALLBACK_MOUSE_IN,
667 _elm_cursor_mouse_in, cur);
668 evas_object_event_callback_add(eventarea, EVAS_CALLBACK_MOUSE_OUT,
669 _elm_cursor_mouse_out, cur);
670 evas_object_event_callback_add(eventarea, EVAS_CALLBACK_DEL,
671 _elm_cursor_del, cur);
672 }
673
674 EOLIAN Eina_Bool
_efl_ui_widget_cursor_set(Evas_Object * obj,Elm_Widget_Smart_Data * pd EINA_UNUSED,const char * cursor)675 _efl_ui_widget_cursor_set(Evas_Object *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED,
676 const char *cursor)
677 {
678 EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
679 elm_object_sub_cursor_set(obj, obj, cursor);
680 return EINA_TRUE;
681 }
682
683 const char *
elm_object_sub_cursor_get(const Evas_Object * obj)684 elm_object_sub_cursor_get(const Evas_Object *obj)
685 {
686 ELM_CURSOR_GET_OR_RETURN(cur, obj, NULL);
687 return cur->cursor_name;
688 }
689
690 EOLIAN const char *
_efl_ui_widget_cursor_get(const Evas_Object * obj,Elm_Widget_Smart_Data * pd EINA_UNUSED)691 _efl_ui_widget_cursor_get(const Evas_Object *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED)
692 {
693 return elm_object_sub_cursor_get(obj);
694 }
695
696 EAPI void
elm_object_cursor_unset(Evas_Object * obj)697 elm_object_cursor_unset(Evas_Object *obj)
698 {
699 ELM_CURSOR_GET_OR_RETURN(cur, obj);
700
701 eina_stringshare_del(cur->cursor_name);
702 cur->cursor_name = NULL;
703 eina_stringshare_del(cur->style);
704 cur->style = NULL;
705
706 if (cur->owner)
707 elm_widget_cursor_del(cur->owner, cur);
708
709 if (cur->obj)
710 {
711 evas_object_event_callback_del_full(cur->obj, EVAS_CALLBACK_DEL,
712 _elm_cursor_obj_del, cur);
713 evas_object_event_callback_del_full(cur->obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
714 _elm_cursor_obj_hints, cur);
715 ELM_SAFE_FREE(cur->obj, evas_object_del);
716 }
717
718 if (cur->visible)
719 {
720 if (!cur->use_engine)
721 ecore_evas_object_cursor_set(cur->ee, NULL, ELM_OBJECT_LAYER_CURSOR,
722 cur->hot_x, cur->hot_y);
723 #ifdef HAVE_ELEMENTARY_X
724 else if (cur->x.win)
725 ecore_x_window_cursor_set(cur->x.win, ECORE_X_CURSOR_X);
726 #endif
727 #ifdef HAVE_ELEMENTARY_COCOA
728 else if (cur->cocoa.win)
729 ecore_cocoa_window_cursor_set(cur->cocoa.win, ECORE_COCOA_CURSOR_DEFAULT);
730 #endif
731 #ifdef HAVE_ELEMENTARY_WL2
732 else if (cur->wl.win)
733 {
734 Evas_Object *top;
735
736 top = elm_widget_top_get(cur->owner);
737 if ((top) && (efl_isa(top, EFL_UI_WIN_CLASS)))
738 _elm_win_wl_cursor_set(top, NULL);
739 }
740 #endif
741 #ifdef HAVE_ELEMENTARY_WIN32
742 else
743 ecore_win32_window_cursor_set(cur->win32.win, ecore_win32_cursor_shaped_new(ECORE_WIN32_CURSOR_SHAPE_ARROW));
744 #endif
745 }
746
747 evas_object_event_callback_del_full(obj, EVAS_CALLBACK_MOUSE_IN,
748 _elm_cursor_mouse_in, cur);
749 evas_object_event_callback_del_full(obj, EVAS_CALLBACK_MOUSE_OUT,
750 _elm_cursor_mouse_out, cur);
751 evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL,
752 _elm_cursor_del, cur);
753 evas_object_data_del(obj, _cursor_key);
754
755 if (cur->hotupdate_job) ecore_job_del(cur->hotupdate_job);
756 cur->hotupdate_job = NULL;
757
758 free(cur);
759 }
760
761 Eina_Bool
elm_object_sub_cursor_style_set(Evas_Object * obj,const char * style)762 elm_object_sub_cursor_style_set(Evas_Object *obj, const char *style)
763 {
764 ELM_CURSOR_GET_OR_RETURN(cur, obj, EINA_FALSE);
765
766 if (!eina_stringshare_replace(&cur->style, style))
767 ERR("Could not set current style=%s", style);
768
769 if (cur->use_engine) return EINA_FALSE;
770
771 if (!cur->obj)
772 {
773 if (!_elm_cursor_obj_add(cur->owner, cur))
774 {
775 ERR("Could not create cursor object");
776 return EINA_FALSE;
777 }
778 else
779 _elm_cursor_set_hot_spots(cur);
780 }
781 else
782 {
783 if (elm_widget_theme_object_set(obj, cur->obj, "cursor", cur->cursor_name,
784 style) == EFL_UI_THEME_APPLY_ERROR_GENERIC)
785 {
786 ERR("Could not apply the theme to the cursor style=%s", style);
787 return EINA_FALSE;
788 }
789 else
790 _elm_cursor_set_hot_spots(cur);
791 }
792
793 return EINA_TRUE;
794 }
795
796 EOLIAN Eina_Bool
_efl_ui_widget_cursor_style_set(Evas_Object * obj,Elm_Widget_Smart_Data * pd EINA_UNUSED,const char * style)797 _efl_ui_widget_cursor_style_set(Evas_Object *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED,
798 const char *style)
799 {
800 return elm_object_sub_cursor_style_set(obj, style);
801 }
802
803 const char *
elm_object_sub_cursor_style_get(const Evas_Object * obj)804 elm_object_sub_cursor_style_get(const Evas_Object *obj)
805 {
806 ELM_CURSOR_GET_OR_RETURN(cur, obj, NULL);
807 return cur->style ? cur->style : "default";
808 }
809
810 EOLIAN const char *
_efl_ui_widget_cursor_style_get(const Evas_Object * obj,Elm_Widget_Smart_Data * pd EINA_UNUSED)811 _efl_ui_widget_cursor_style_get(const Evas_Object *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED)
812 {
813 return elm_object_sub_cursor_style_get(obj);
814 }
815
816 /**
817 * Notify cursor should recalculate its theme.
818 * @internal
819 */
820 void
elm_cursor_theme(Elm_Cursor * cur)821 elm_cursor_theme(Elm_Cursor *cur)
822 {
823 if ((!cur) || (!cur->obj)) return;
824 if (elm_widget_theme_object_set(cur->owner, cur->obj, "cursor",
825 cur->cursor_name, cur->style) == EFL_UI_THEME_APPLY_ERROR_GENERIC)
826 ERR("Could not apply the theme to the cursor style=%s", cur->style);
827 else
828 _elm_cursor_set_hot_spots(cur);
829 }
830
831 Eina_Bool
elm_object_sub_cursor_theme_search_enabled_set(Evas_Object * obj,Eina_Bool theme_search)832 elm_object_sub_cursor_theme_search_enabled_set(Evas_Object *obj, Eina_Bool theme_search)
833 {
834 ELM_CURSOR_GET_OR_RETURN(cur, obj, EINA_FALSE);
835 cur->theme_search = theme_search;
836 ELM_SAFE_FREE(cur->obj, evas_object_del);
837 _elm_cursor_cur_set(cur);
838 return EINA_TRUE;
839 }
840
841 EOLIAN Eina_Bool
_efl_ui_widget_cursor_theme_search_enabled_set(Evas_Object * obj,Elm_Widget_Smart_Data * pd EINA_UNUSED,Eina_Bool theme_search)842 _efl_ui_widget_cursor_theme_search_enabled_set(Evas_Object *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED,
843 Eina_Bool theme_search)
844 {
845 return elm_object_sub_cursor_theme_search_enabled_set(obj, theme_search);
846 }
847
848 Eina_Bool
elm_object_sub_cursor_theme_search_enabled_get(const Evas_Object * obj)849 elm_object_sub_cursor_theme_search_enabled_get(const Evas_Object *obj)
850 {
851 ELM_CURSOR_GET_OR_RETURN(cur, obj, EINA_FALSE);
852 return cur->theme_search;
853 }
854
855 EOLIAN Eina_Bool
_efl_ui_widget_cursor_theme_search_enabled_get(const Evas_Object * obj,Elm_Widget_Smart_Data * pd EINA_UNUSED)856 _efl_ui_widget_cursor_theme_search_enabled_get(const Evas_Object *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED)
857 {
858 return elm_object_sub_cursor_theme_search_enabled_get(obj);
859 }
860