3865abe9db85d9b4ce7d90c2f1061c1088425e4f
[framework/uifw/elementary.git] / src / lib / els_tooltip.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 #ifdef ISCOMFITOR
5 # define STR(X) #X
6 # define STUPID(X) STR(X)
7 # define TTDBG(x...) fprintf(stderr, STUPID(__LINE__)": " x)
8 #else
9 # define TTDBG(X...)
10 #endif
11
12 static const char _tooltip_key[] = "_elm_tooltip";
13
14 #define ELM_TOOLTIP_GET_OR_RETURN(tt, obj, ...)         \
15   Elm_Tooltip *tt;                                      \
16   do                                                    \
17     {                                                   \
18        if (!(obj))                                      \
19          {                                              \
20             CRITICAL("Null pointer: " #obj);            \
21             return __VA_ARGS__;                         \
22          }                                              \
23        tt = evas_object_data_get((obj), _tooltip_key);  \
24        if (!tt)                                         \
25          {                                              \
26             ERR("Object does not have tooltip: " #obj); \
27             return __VA_ARGS__;                         \
28          }                                              \
29     }                                                   \
30   while (0)
31
32 struct _Elm_Tooltip
33 {
34    Elm_Tooltip_Content_Cb   func;
35    Evas_Smart_Cb            del_cb;
36    const void              *data;
37    const char              *style;
38    Evas                    *evas, *tt_evas;
39    Evas_Object             *eventarea, *owner;
40    Evas_Object             *tooltip, *content;
41    Evas_Object             *tt_win;
42    Ecore_Timer             *show_timer;
43    Ecore_Timer             *hide_timer;
44    Ecore_Job               *reconfigure_job;
45    struct {
46       Evas_Coord            x, y, bx, by;
47    } pad;
48    struct {
49       double                x, y;
50    } rel_pos;
51    double                   hide_timeout; /* from theme */
52    Eina_Bool                visible_lock:1;
53    Eina_Bool                changed_style:1;
54    Eina_Bool                free_size : 1;
55 };
56
57 static void _elm_tooltip_reconfigure(Elm_Tooltip *tt);
58 static void _elm_tooltip_reconfigure_job_start(Elm_Tooltip *tt);
59 static void _elm_tooltip_reconfigure_job_stop(Elm_Tooltip *tt);
60 static void _elm_tooltip_hide_anim_start(Elm_Tooltip *tt);
61 static void _elm_tooltip_hide_anim_stop(Elm_Tooltip *tt);
62 static void _elm_tooltip_show_timer_stop(Elm_Tooltip *tt);
63 static void _elm_tooltip_hide(Elm_Tooltip *tt);
64 static void _elm_tooltip_data_clean(Elm_Tooltip *tt);
65
66 static void
67 _elm_tooltip_content_changed_hints_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
68 {
69    _elm_tooltip_reconfigure_job_start(data);
70 }
71
72 static void
73 _elm_tooltip_content_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
74 {
75    Elm_Tooltip *tt = data;
76    tt->content = NULL;
77    tt->visible_lock = EINA_FALSE;
78    if (tt->tooltip) _elm_tooltip_hide(tt);
79 }
80
81 static void
82 _elm_tooltip_obj_move_cb(void *data, Evas *e  __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info  __UNUSED__)
83 {
84    Elm_Tooltip *tt = data;
85    _elm_tooltip_reconfigure_job_start(tt);
86 }
87
88 static void
89 _elm_tooltip_obj_resize_cb(void *data, Evas *e  __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info  __UNUSED__)
90 {
91    Elm_Tooltip *tt = data;
92    _elm_tooltip_reconfigure_job_start(tt);
93 }
94
95 static void
96 _elm_tooltip_obj_mouse_move_cb(void *data, Evas *e  __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info  __UNUSED__)
97 {
98    Elm_Tooltip *tt = data;
99    _elm_tooltip_reconfigure_job_start(tt);
100 }
101
102 static void
103 _elm_tooltip_show(Elm_Tooltip *tt)
104 {
105    _elm_tooltip_show_timer_stop(tt);
106    _elm_tooltip_hide_anim_stop(tt);
107
108    if (tt->tooltip)
109      {
110         _elm_tooltip_reconfigure_job_start(tt);
111         return;
112      }
113    if (tt->free_size)
114      {
115         tt->tt_win = elm_win_add(NULL, "tooltip", ELM_WIN_BASIC);
116         elm_win_borderless_set(tt->tt_win, EINA_TRUE);
117         elm_win_override_set(tt->tt_win, EINA_TRUE);
118         tt->tt_evas = evas_object_evas_get(tt->tt_win);
119         tt->tooltip = edje_object_add(tt->tt_evas);
120         evas_object_move(tt->tooltip, 0, 0);
121         elm_win_resize_object_add(tt->tt_win, tt->tooltip);
122 #ifdef HAVE_ELEMENTARY_X
123         ecore_x_window_shape_input_rectangle_set(elm_win_xwindow_get(tt->tt_win), 0, 0, 0, 0);
124 #endif
125         evas_object_show(tt->tt_win);
126      }
127    else
128       tt->tooltip = edje_object_add(tt->evas);
129    if (!tt->tooltip) return;
130
131    evas_object_layer_set(tt->tt_win ?: tt->tooltip, ELM_OBJECT_LAYER_TOOLTIP);
132
133    evas_object_event_callback_add
134      (tt->eventarea, EVAS_CALLBACK_MOVE, _elm_tooltip_obj_move_cb, tt);
135    evas_object_event_callback_add
136      (tt->eventarea, EVAS_CALLBACK_RESIZE, _elm_tooltip_obj_resize_cb, tt);
137    evas_object_event_callback_add
138      (tt->eventarea, EVAS_CALLBACK_MOUSE_MOVE, _elm_tooltip_obj_mouse_move_cb, tt);
139
140    tt->changed_style = EINA_TRUE;
141    _elm_tooltip_reconfigure_job_start(tt);
142 }
143
144 static void
145 _elm_tooltip_content_del(Elm_Tooltip *tt)
146 {
147    if (!tt->content) return;
148
149    evas_object_event_callback_del_full
150      (tt->content, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
151       _elm_tooltip_content_changed_hints_cb, tt);
152    evas_object_event_callback_del_full
153      (tt->content, EVAS_CALLBACK_DEL,
154       _elm_tooltip_content_del_cb, tt);
155    evas_object_hide(tt->content);
156    evas_object_del(tt->content);
157    tt->content = NULL;
158 }
159
160
161 static void
162 _elm_tooltip_hide(Elm_Tooltip *tt)
163 {
164    Evas_Object *del;
165    _elm_tooltip_show_timer_stop(tt);
166    _elm_tooltip_hide_anim_stop(tt);
167    _elm_tooltip_reconfigure_job_stop(tt);
168
169    if (!tt->tooltip) return;
170    if (tt->visible_lock) return;
171
172    _elm_tooltip_content_del(tt);
173
174    evas_object_event_callback_del_full
175      (tt->eventarea, EVAS_CALLBACK_MOVE, _elm_tooltip_obj_move_cb, tt);
176    evas_object_event_callback_del_full
177      (tt->eventarea, EVAS_CALLBACK_RESIZE, _elm_tooltip_obj_resize_cb, tt);
178    evas_object_event_callback_del_full
179      (tt->eventarea, EVAS_CALLBACK_MOUSE_MOVE, _elm_tooltip_obj_mouse_move_cb, tt);
180
181    del = tt->tt_win ?: tt->tooltip;
182
183    tt->tt_win = NULL;
184    tt->tt_evas = NULL;
185    tt->tooltip = NULL;
186    evas_object_del(del);
187 }
188
189 static void
190 _elm_tooltip_reconfigure_job(void *data)
191 {
192    Elm_Tooltip *tt = data;
193    tt->reconfigure_job = NULL;
194    _elm_tooltip_reconfigure(data);
195 }
196
197 static void
198 _elm_tooltip_reconfigure_job_stop(Elm_Tooltip *tt)
199 {
200    if (!tt->reconfigure_job) return;
201    ecore_job_del(tt->reconfigure_job);
202    tt->reconfigure_job = NULL;
203 }
204
205 static void
206 _elm_tooltip_reconfigure_job_start(Elm_Tooltip *tt)
207 {
208    if (tt->reconfigure_job) ecore_job_del(tt->reconfigure_job);
209    tt->reconfigure_job = ecore_job_add(_elm_tooltip_reconfigure_job, tt);
210 }
211
212 static Eina_Bool
213 _elm_tooltip_hide_anim_cb(void *data)
214 {
215    Elm_Tooltip *tt = data;
216    tt->hide_timer = NULL;
217    _elm_tooltip_hide(tt);
218    return EINA_FALSE;
219 }
220
221 static void
222 _elm_tooltip_hide_anim_start(Elm_Tooltip *tt)
223 {
224    double extra = 0;
225    if (tt->hide_timer) return;
226    /* hide slightly faster when in window mode to look less stupid */
227    if ((tt->hide_timeout > 0) && tt->tt_win) extra = 0.1;
228    edje_object_signal_emit(tt->tooltip, "elm,action,hide", "elm");
229    tt->hide_timer = ecore_timer_add
230      (tt->hide_timeout - extra, _elm_tooltip_hide_anim_cb, tt);
231 }
232
233 static void
234 _elm_tooltip_hide_anim_stop(Elm_Tooltip *tt)
235 {
236    if (!tt->hide_timer) return;
237    if (tt->tooltip)
238      edje_object_signal_emit(tt->tooltip, "elm,action,show", "elm");
239    ecore_timer_del(tt->hide_timer);
240    tt->hide_timer = NULL;
241 }
242
243 static void
244 _elm_tooltip_reconfigure(Elm_Tooltip *tt)
245 {
246    Evas_Coord ox, oy, ow, oh, px, py, tx, ty, tw, th, cw = 0, ch = 0;
247    Evas_Coord eminw, eminh, ominw, ominh;
248    double rel_x, rel_y;
249    Eina_Bool inside_eventarea;
250
251    _elm_tooltip_reconfigure_job_stop(tt);
252
253    if (tt->hide_timer) return;
254    if (!tt->tooltip) return;
255    if (tt->changed_style)
256      {
257         const char *style = tt->style ? tt->style : "default";
258         const char *str;
259         if (!_elm_theme_object_set(tt->tt_win ? NULL : tt->owner, tt->tooltip, "tooltip", "base", style))
260           {
261              ERR("Could not apply the theme to the tooltip! style=%s", style);
262              if (tt->tt_win) evas_object_del(tt->tt_win);
263              else evas_object_del(tt->tooltip);
264              tt->tt_win = NULL;
265              tt->tt_evas = NULL;
266              tt->tooltip = NULL;
267              return;
268           }
269
270         tt->rel_pos.x = 0;
271         tt->rel_pos.y = 0;
272
273         tt->pad.x = 0;
274         tt->pad.y = 0;
275         tt->pad.bx = 0;
276         tt->pad.by = 0;
277         tt->hide_timeout = 0.0;
278
279         str = edje_object_data_get(tt->tooltip, "transparent");
280         if (tt->tt_win)
281           {  /* FIXME: hardcoded here is bad */
282              if (str && (!strcmp(str, "enabled")))
283                {
284                   elm_win_alpha_set(tt->tt_win, EINA_TRUE);
285 <<<<<<< HEAD
286                   elm_win_transparent_set(tt->tt_win, EINA_TRUE);
287 =======
288 >>>>>>> remotes/origin/upstream
289                }
290              else
291                {
292                   elm_win_alpha_set(tt->tt_win, EINA_FALSE);
293 <<<<<<< HEAD
294                   elm_win_transparent_set(tt->tt_win, EINA_FALSE);
295 =======
296 >>>>>>> remotes/origin/upstream
297                }
298           }
299
300         str = edje_object_data_get(tt->tooltip, "pad_x");
301         if (str) tt->pad.x = atoi(str);
302         str = edje_object_data_get(tt->tooltip, "pad_y");
303         if (str) tt->pad.y = atoi(str);
304
305         str = edje_object_data_get(tt->tooltip, "pad_border_x");
306         if (str) tt->pad.bx = atoi(str);
307         str = edje_object_data_get(tt->tooltip, "pad_border_y");
308         if (str) tt->pad.by = atoi(str);
309
310         str = edje_object_data_get(tt->tooltip, "hide_timeout");
311         if (str)
312           {
313              tt->hide_timeout = atof(str);
314              if (tt->hide_timeout < 0.0) tt->hide_timeout = 0.0;
315           }
316
317         evas_object_pass_events_set(tt->tooltip, EINA_TRUE);
318         tt->changed_style = EINA_FALSE;
319         if (tt->tooltip)
320           edje_object_part_swallow(tt->tooltip, "elm.swallow.content",
321                                    tt->content);
322
323         edje_object_signal_emit(tt->tooltip, "elm,action,show", "elm");
324      }
325
326    if (!tt->content)
327      {
328         tt->content = tt->func((void *)tt->data, tt->owner, tt->tt_win ? : tt->owner);
329         if (!tt->content)
330           {
331              WRN("could not create tooltip content!");
332              if (tt->tt_win) evas_object_del(tt->tt_win);
333              else evas_object_del(tt->tooltip);
334
335              tt->tt_win = NULL;
336              tt->tt_evas = NULL;
337              tt->tooltip = NULL;
338              return;
339           }
340         evas_object_show(tt->content);
341         evas_object_layer_set(tt->content, ELM_OBJECT_LAYER_TOOLTIP);
342         evas_object_pass_events_set(tt->content, EINA_TRUE);
343         edje_object_part_swallow
344           (tt->tooltip, "elm.swallow.content", tt->content);
345         evas_object_event_callback_add(tt->content, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
346            _elm_tooltip_content_changed_hints_cb, tt);
347         evas_object_event_callback_add(tt->content, EVAS_CALLBACK_DEL,
348            _elm_tooltip_content_del_cb, tt);
349
350      }
351    TTDBG("*******RECALC\n");
352    evas_object_size_hint_min_get(tt->content, &ominw, &ominh);
353    edje_object_size_min_get(tt->tooltip, &eminw, &eminh);
354
355    if (eminw && (ominw < eminw)) ominw = eminw;
356    if (eminw && (ominh < eminh)) ominh = eminh;
357
358    if (ominw < 1) ominw = 10; /* at least it is noticeable */
359    if (ominh < 1) ominh = 10; /* at least it is noticeable */
360
361    edje_object_size_min_restricted_calc(tt->tooltip, &tw, &th, ominw, ominh);
362    TTDBG("TTSIZE:  tw=%d,th=%d,ominw=%d,ominh=%d\n", tw, th, ominw, ominh);
363
364    if (tt->tt_win)
365      elm_win_screen_size_get(elm_object_top_widget_get(tt->owner), NULL, NULL, &cw, &ch);
366    if (!cw)
367      evas_output_size_get(tt->tt_evas ?: tt->evas, &cw, &ch);
368    TTDBG("SCREEN:  cw=%d,ch=%d\n", cw, ch);
369
370    evas_object_geometry_get(tt->eventarea, &ox, &oy, &ow, &oh);
371    TTDBG("EVENTAREA:  ox=%d,oy=%d,ow=%d,oh=%d\n", ox, oy, ow, oh);
372
373    if (tt->tt_win)
374      {
375         int x, y;
376         Evas_Object *win = elm_object_top_widget_get(tt->owner);
377 #ifdef HAVE_ELEMENTARY_X
378         Ecore_X_Window xwin = elm_win_xwindow_get(win);
379         ecore_x_pointer_xy_get(xwin, &px, &py);
380 #endif
381         elm_win_screen_position_get(win, &x, &y);
382         ox += x;
383         if (px) px += x;
384         oy += y;
385         if (py) py += y;
386      }
387    else
388      evas_pointer_canvas_xy_get(tt->evas, &px, &py);
389    TTDBG("POINTER:  px=%d,py=%d\n", px, py);
390    inside_eventarea = ((px >= ox) && (py >= oy) &&
391                        (px <= ox + ow) && (py <= oy + oh));
392    if (inside_eventarea)
393      {
394         /* try to position bottom right corner at pointer */
395         tx = px - tw;
396         ty = py - th;
397         TTDBG("INIT (EVENTAREA)\n");
398      }
399    else
400      {
401         /* try centered on middle of eventarea */
402         tx = ox + (ow / 2) - (tw / 2);
403         if (0 > (th - oy - oh)) ty = oy + th;
404         else ty = oy - oh;
405         TTDBG("INIT (INTERPRETED)\n");
406      }
407    TTDBG("ADJUST (POINTER):  tx=%d,ty=%d\n", tx, ty);
408    if (tx < 0)
409      {
410         /* if we're offscreen, try to flip over the Y axis */
411         if (abs((tx + 2 * tw) - cw) < abs(tx))
412           tx += tw;
413      }
414    else if ((tx > px) && (px > tw))
415      {
416         if (tx + tw < cw)
417           tx += tw;
418      }
419    if (ty < 0)
420      {
421         /* if we're offscreen, try to flip over the X axis */
422         if (abs((ty + 2 * th) - ch) < abs(ty))
423           ty += th;
424      }
425    else if ((ty > py) && (py > th))
426      {
427         if (ty + th < ch)
428           ty += th;
429      }
430    TTDBG("ADJUST (FLIP):  tx=%d,ty=%d\n", tx, ty);
431    if (inside_eventarea)
432      {
433         if ((tx == px) && ((tx + tw + tt->pad.x < cw) || (tx + tw > cw))) tx += tt->pad.x;
434         else if ((tx - tt->pad.x > 0) || (tx < 0)) tx -= tt->pad.x;
435         if ((ty == py) && ((ty + th + tt->pad.y < ch) || (ty + th > ch))) ty += tt->pad.y;
436         else if ((ty - tt->pad.y > 0) || (ty < 0)) ty -= tt->pad.y;
437      }
438    TTDBG("PAD:  tx=%d,ty=%d\n", tx, ty);
439    if (tt->pad.bx * 2 + tw < cw)
440      {
441         if (tx < tt->pad.bx) tx = tt->pad.bx;
442         else if ((tx >= tw) && (tx + tt->pad.bx <= cw)) tx += tt->pad.bx;
443         else if (tx - tt->pad.bx >= 0) tx -= tt->pad.bx;
444      }
445    else if (tx < 0) tx -= tt->pad.bx;
446    else if (tx > cw) tx += tt->pad.bx;
447    if (tt->pad.by * 2 + th < ch)
448      {
449         if (ty < tt->pad.by) ty = tt->pad.by;
450         else if ((ty >= th) && (ty + tt->pad.by <= ch)) ty += tt->pad.by;
451         else if (ty - tt->pad.by >= 0) ty -= tt->pad.by;
452      }
453    else if (ty < 0) ty -= tt->pad.by;
454    else if (ty > ch) ty += tt->pad.by;
455    TTDBG("PAD (BORDER):  tx=%d,ty=%d\n", tx, ty);
456    if ((tx < 0) || (ty < 0))
457      {
458         TTDBG("POSITIONING FAILED! THIS IS A BUG SOMEWHERE!\n");
459         return;
460      }
461    evas_object_move(tt->tt_win ? : tt->tooltip, tx, ty);
462    evas_object_resize(tt->tt_win ? : tt->tooltip, tw, th);
463    evas_object_show(tt->tooltip);
464
465    if (inside_eventarea)
466      {
467         rel_x = (px - tx) / (double)tw;
468         rel_y = (py - ty) / (double)th;
469      }
470    else
471      {
472         rel_x = (ox + (ow / 2) - tx) / (double)tw;
473         rel_y = (oy + (oh / 2) - ty) / (double)th;
474      }
475
476 #define FDIF(a, b) (fabs((a) - (b)) > 0.0001)
477    if ((FDIF(rel_x, tt->rel_pos.x)) || (FDIF(rel_y, tt->rel_pos.y)))
478      {
479         Edje_Message_Float_Set *msg;
480
481         msg = alloca(sizeof(Edje_Message_Float_Set) + sizeof(double));
482         msg->count = 2;
483         msg->val[0] = rel_x;
484         msg->val[1] = rel_y;
485         tt->rel_pos.x = rel_x;
486         tt->rel_pos.y = rel_y;
487
488         edje_object_message_send(tt->tooltip, EDJE_MESSAGE_FLOAT_SET, 1, msg);
489      }
490 #undef FDIF
491 }
492
493 static void
494 _elm_tooltip_show_timer_stop(Elm_Tooltip *tt)
495 {
496    if (!tt->show_timer) return;
497    ecore_timer_del(tt->show_timer);
498    tt->show_timer = NULL;
499 }
500
501 static Eina_Bool
502 _elm_tooltip_timer_show_cb(void *data)
503 {
504    Elm_Tooltip *tt = data;
505    tt->show_timer = NULL;
506    _elm_tooltip_show(tt);
507    return ECORE_CALLBACK_CANCEL;
508 }
509
510 static void
511 _elm_tooltip_obj_mouse_in_cb(void *data, Evas *e  __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info  __UNUSED__)
512 {
513    Elm_Tooltip *tt = data;
514
515    _elm_tooltip_hide_anim_stop(tt);
516
517    if ((tt->show_timer) || (tt->tooltip)) return;
518
519    tt->show_timer = ecore_timer_add
520      (_elm_config->tooltip_delay, _elm_tooltip_timer_show_cb, tt);
521 }
522
523 static void
524 _elm_tooltip_obj_mouse_out_cb(Elm_Tooltip *tt, Evas *e  __UNUSED__, Evas_Object *obj __UNUSED__, Evas_Event_Mouse_Out *event __UNUSED__)
525 {
526    if (tt->visible_lock) return;
527
528    if (!tt->tooltip)
529      {
530         _elm_tooltip_show_timer_stop(tt);
531         return;
532      }
533    _elm_tooltip_hide_anim_start(tt);
534 }
535
536 static void _elm_tooltip_obj_free_cb(void *data, Evas *e  __UNUSED__, Evas_Object *obj, void *event_info  __UNUSED__);
537
538 static void
539 _elm_tooltip_unset(Elm_Tooltip *tt)
540 {
541    tt->visible_lock = EINA_FALSE;
542    _elm_tooltip_hide(tt);
543    _elm_tooltip_data_clean(tt);
544
545    if (tt->eventarea)
546      {
547         evas_object_event_callback_del_full
548           (tt->eventarea, EVAS_CALLBACK_MOUSE_IN,
549            _elm_tooltip_obj_mouse_in_cb, tt);
550         evas_object_event_callback_del_full
551           (tt->eventarea, EVAS_CALLBACK_MOUSE_OUT,
552            (Evas_Object_Event_Cb)_elm_tooltip_obj_mouse_out_cb, tt);
553         evas_object_event_callback_del_full
554           (tt->eventarea, EVAS_CALLBACK_FREE, _elm_tooltip_obj_free_cb, tt);
555
556         evas_object_data_del(tt->eventarea, _tooltip_key);
557      }
558    if (tt->owner)
559      {
560         evas_object_event_callback_del_full
561           (tt->owner, EVAS_CALLBACK_FREE, _elm_tooltip_obj_free_cb, tt);
562         elm_widget_tooltip_del(tt->owner, tt);
563      }
564
565    eina_stringshare_del(tt->style);
566    free(tt);
567 }
568
569 static void
570 _elm_tooltip_obj_free_cb(void *data, Evas *e  __UNUSED__, Evas_Object *obj, void *event_info  __UNUSED__)
571 {
572    Elm_Tooltip *tt = data;
573    if (tt->eventarea == obj) tt->eventarea = NULL;
574    if (tt->owner == obj) tt->owner = NULL;
575    _elm_tooltip_unset(tt);
576 }
577
578 static Evas_Object *
579 _elm_tooltip_label_create(void *data, Evas_Object *obj __UNUSED__, Evas_Object *tooltip)
580 {
581    Evas_Object *label = elm_label_add(tooltip);
582    if (!label)
583      return NULL;
584    elm_object_style_set(label, "tooltip");
585    elm_object_text_set(label, data);
586    return label;
587 }
588
589 static Evas_Object *
590 _elm_tooltip_trans_label_create(void *data, Evas_Object *obj __UNUSED__, Evas_Object *tooltip)
591 {
592    Evas_Object *label = elm_label_add(tooltip);
593    const char **text = data;
594    if (!label)
595      return NULL;
596    elm_object_style_set(label, "tooltip");
597    elm_object_domain_translatable_text_set(label, text[0], text[1]);
598    return label;
599 }
600
601 static void
602 _elm_tooltip_label_del_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
603 {
604    eina_stringshare_del(data);
605 }
606
607 static void
608 _elm_tooltip_trans_label_del_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
609 {
610    const char **text = data;
611    eina_stringshare_del(text[0]);
612    eina_stringshare_del(text[1]);
613    free(text);
614 }
615
616 static void
617 _elm_tooltip_data_clean(Elm_Tooltip *tt)
618 {
619    if (tt->del_cb) tt->del_cb((void *)tt->data, tt->owner, NULL);
620
621    _elm_tooltip_content_del(tt);
622
623    tt->data = NULL;
624    tt->del_cb = NULL;
625 }
626
627 /**
628  * Notify tooltip should recalculate its theme.
629  * @internal
630  */
631 void
632 elm_tooltip_theme(Elm_Tooltip *tt)
633 {
634    if (!tt->tooltip) return;
635    tt->changed_style = EINA_TRUE;
636    _elm_tooltip_reconfigure_job_start(tt);
637 }
638
639
640 /**
641  * Set the content to be shown in the tooltip object for specific event area.
642  *
643  * Setup the tooltip to object. The object @a eventarea can have only
644  * one tooltip, so any previous tooltip data is removed. @p func(with
645  * @p data) will be called every time that need show the tooltip and
646  * it should return a valid Evas_Object. This object is then managed
647  * fully by tooltip system and is deleted when the tooltip is gone.
648  *
649  * This is an internal function that is used by objects with sub-items
650  * that want to provide different tooltips for each of them. The @a
651  * owner object should be an elm_widget and will be used to track
652  * theme changes and to feed @a func and @a del_cb. The @a eventarea
653  * may be any object and is the one that should be used later on with
654  * elm_object_tooltip apis, such as elm_object_tooltip_hide(),
655  * elm_object_tooltip_show() or elm_object_tooltip_unset().
656  *
657  * @param eventarea the object being attached a tooltip.
658  * @param owner the elm_widget that owns this object, will be used to
659  *        track theme changes and to be used in @a func or @a del_cb.
660  * @param func the function used to create the tooltip contents. The
661  *        @a Evas_Object parameters will receive @a owner as value.
662  * @param data what to provide to @a func as callback data/context.
663  * @param del_cb called when data is not needed anymore, either when
664  *        another callback replaces @p func, the tooltip is unset with
665  *        elm_object_tooltip_unset() or the owner object @a obj
666  *        dies. This callback receives as the first parameter the
667  *        given @a data, and @c event_info is NULL.
668  *
669  * @internal
670  * @ingroup Tooltips
671  */
672 void
673 elm_object_sub_tooltip_content_cb_set(Evas_Object *eventarea, Evas_Object *owner, Elm_Tooltip_Content_Cb func, const void *data, Evas_Smart_Cb del_cb)
674 {
675    Elm_Tooltip *tt = NULL;
676    Eina_Bool just_created;
677
678    EINA_SAFETY_ON_NULL_GOTO(owner, error);
679    EINA_SAFETY_ON_NULL_GOTO(eventarea, error);
680
681    if (!func)
682      {
683         elm_object_tooltip_unset(eventarea);
684         return;
685      }
686
687    tt = evas_object_data_get(eventarea, _tooltip_key);
688    if (tt)
689      {
690         if (tt->owner != owner)
691           {
692              if (tt->owner != eventarea)
693                evas_object_event_callback_del_full
694                  (tt->owner, EVAS_CALLBACK_FREE, _elm_tooltip_obj_free_cb, tt);
695
696              elm_widget_tooltip_del(tt->owner, tt);
697
698              if (owner != eventarea)
699                evas_object_event_callback_add
700                  (owner, EVAS_CALLBACK_FREE, _elm_tooltip_obj_free_cb, tt);
701
702              elm_widget_tooltip_add(tt->owner, tt);
703           }
704
705         if ((tt->func == func) && (tt->data == data) &&
706             (tt->del_cb == del_cb))
707           return;
708         _elm_tooltip_data_clean(tt);
709         just_created = EINA_FALSE;
710      }
711    else
712      {
713         tt = ELM_NEW(Elm_Tooltip);
714         if (!tt) goto error;
715
716         tt->owner = owner;
717         tt->eventarea = eventarea;
718         tt->evas = evas_object_evas_get(eventarea);
719         evas_object_data_set(eventarea, _tooltip_key, tt);
720
721         just_created = EINA_TRUE;
722
723         evas_object_event_callback_add(eventarea, EVAS_CALLBACK_MOUSE_IN,
724            _elm_tooltip_obj_mouse_in_cb, tt);
725         evas_object_event_callback_add(eventarea, EVAS_CALLBACK_MOUSE_OUT,
726            (Evas_Object_Event_Cb)_elm_tooltip_obj_mouse_out_cb, tt);
727         evas_object_event_callback_add(eventarea, EVAS_CALLBACK_FREE,
728            _elm_tooltip_obj_free_cb, tt);
729
730         if (owner != eventarea)
731           evas_object_event_callback_add
732             (owner, EVAS_CALLBACK_FREE, _elm_tooltip_obj_free_cb, tt);
733
734         elm_widget_tooltip_add(tt->owner, tt);
735      }
736
737    tt->func = func;
738    tt->data = data;
739    tt->del_cb = del_cb;
740
741    if (!just_created) _elm_tooltip_reconfigure_job_start(tt);
742    return;
743
744  error:
745    if (del_cb) del_cb((void *)data, owner, NULL);
746 }
747
748 /**
749  * Force show tooltip of object
750  *
751  * @param obj Target object
752  *
753  * Force show the tooltip and disable hide on mouse_out.
754  * If another content is set as tooltip, the visible tooltip will hididen and
755  * showed again with new content.
756  * This can force show more than one tooltip at a time.
757  *
758  * @ingroup Tooltips
759  */
760 EAPI void
761 elm_object_tooltip_show(Evas_Object *obj)
762 {
763    ELM_TOOLTIP_GET_OR_RETURN(tt, obj);
764    tt->visible_lock = EINA_TRUE;
765    _elm_tooltip_show(tt);
766 }
767
768 /**
769  * Force hide tooltip of object
770  *
771  * @param obj Target object
772  *
773  * Force hide the tooltip and (re)enable future mouse interations.
774  *
775  * @ingroup Tooltips
776  */
777 EAPI void
778 elm_object_tooltip_hide(Evas_Object *obj)
779 {
780    ELM_TOOLTIP_GET_OR_RETURN(tt, obj);
781    tt->visible_lock = EINA_FALSE;
782    _elm_tooltip_hide_anim_start(tt);
783 }
784
785 /**
786  * Set the text to be shown in the tooltip object
787  *
788  * @param obj Target object
789  * @param text The text to set in the content
790  *
791  * Setup the text as tooltip to object. The object can have only one tooltip,
792  * so any previous tooltip data is removed.
793  * This method call internaly the elm_tooltip_content_cb_set().
794  *
795  * @ingroup Tooltips
796  */
797 EAPI void
798 elm_object_tooltip_text_set(Evas_Object *obj, const char *text)
799 {
800    EINA_SAFETY_ON_NULL_RETURN(obj);
801    EINA_SAFETY_ON_NULL_RETURN(text);
802
803    text = eina_stringshare_add(text);
804    elm_object_tooltip_content_cb_set
805      (obj, _elm_tooltip_label_create, text, _elm_tooltip_label_del_cb);
806 }
807
808 /**
809  */
810 EAPI void
811 elm_object_tooltip_domain_translatable_text_set(Evas_Object *obj, const char *domain, const char *text)
812 {
813    const char **data;
814    EINA_SAFETY_ON_NULL_RETURN(obj);
815    EINA_SAFETY_ON_NULL_RETURN(text);
816
817    data = malloc(2 * sizeof(char *));
818    if (!data) return;
819    data[0] = eina_stringshare_add(domain);
820    data[1] = eina_stringshare_add(text);
821    elm_object_tooltip_content_cb_set
822      (obj, _elm_tooltip_trans_label_create, data,
823       _elm_tooltip_trans_label_del_cb);
824 }
825
826 /**
827  * Set the content to be shown in the tooltip object
828  *
829  * Setup the tooltip to object. The object can have only one tooltip,
830  * so any previous tooltip data is removed. @p func(with @p data) will
831  * be called every time that need show the tooltip and it should
832  * return a valid Evas_Object. This object is then managed fully by
833  * tooltip system and is deleted when the tooltip is gone.
834  *
835  * @param obj the object being attached a tooltip.
836  * @param func the function used to create the tooltip contents.
837  * @param data what to provide to @a func as callback data/context.
838  * @param del_cb called when data is not needed anymore, either when
839  *        another callback replaces @p func, the tooltip is unset with
840  *        elm_object_tooltip_unset() or the owner object @a obj
841  *        dies. This callback receives as the first parameter the
842  *        given @a data, and @c event_info is NULL.
843  *
844  * @ingroup Tooltips
845  */
846 EAPI void
847 elm_object_tooltip_content_cb_set(Evas_Object *obj, Elm_Tooltip_Content_Cb func, const void *data, Evas_Smart_Cb del_cb)
848 {
849    elm_object_sub_tooltip_content_cb_set(obj, obj, func, data, del_cb);
850 }
851
852 /**
853  * Unset tooltip from object
854  *
855  * @param obj Target object
856  *
857  * Remove tooltip from object. The callback provided as del_cb to
858  * elm_object_tooltip_content_cb_set() will be called to notify it is
859  * not used anymore.
860  *
861  * @see elm_object_tooltip_content_cb_set()
862  *
863  * @ingroup Tooltips
864  */
865 EAPI void
866 elm_object_tooltip_unset(Evas_Object *obj)
867 {
868    ELM_TOOLTIP_GET_OR_RETURN(tt, obj);
869    _elm_tooltip_unset(tt);
870 }
871
872 /**
873  * Sets a different style for this object tooltip.
874  *
875  * @note before you set a style you should define a tooltip with
876  *       elm_object_tooltip_content_cb_set() or
877  *       elm_object_tooltip_text_set().
878  *
879  * @param obj an object with tooltip already set.
880  * @param style the theme style to use (default, transparent, ...)
881  */
882 EAPI void
883 elm_object_tooltip_style_set(Evas_Object *obj, const char *style)
884 {
885    ELM_TOOLTIP_GET_OR_RETURN(tt, obj);
886    if (!eina_stringshare_replace(&tt->style, style)) return;
887    elm_tooltip_theme(tt);
888 }
889
890 /**
891  * Get the style for this object tooltip.
892  *
893  * @param obj an object with tooltip already set.
894  * @return style the theme style in use, defaults to "default". If the
895  *         object does not have a tooltip set, then NULL is returned.
896  */
897 EAPI const char *
898 elm_object_tooltip_style_get(const Evas_Object *obj)
899 {
900    ELM_TOOLTIP_GET_OR_RETURN(tt, obj, NULL);
901    return tt->style ? tt->style : "default";
902 }
903
904 /**
905 <<<<<<< HEAD
906  * Get the configured tooltip delay
907  *
908  * This gets the globally configured tooltip delay in seconds
909  *
910  * @return The tooltip delay
911  * @ingroup Tooltips
912  */
913 EAPI double
914 elm_tooltip_delay_get(void)
915 {
916    return _elm_config->tooltip_delay;
917 }
918
919 /**
920  * Set the configured tooltip delay
921  *
922  * This sets the globally configured delay to tooltip
923  *
924  * @param delay The delay to show the tooltip
925  * @return EINA_TRUE if value is valid and setted
926  * @ingroup Tooltips
927  */
928 EAPI Eina_Bool
929 elm_tooltip_delay_set(double delay)
930 {
931    if (delay < 0.0) return EINA_FALSE;
932    _elm_config->tooltip_delay = delay;
933    return EINA_TRUE;
934 }
935
936 /**
937 =======
938 >>>>>>> remotes/origin/upstream
939  * @brief Disable size restrictions on an object's tooltip
940  * @param obj The tooltip's anchor object
941  * @param disable If EINA_TRUE, size restrictions are disabled
942  * @return EINA_FALSE on failure, EINA_TRUE on success
943  *
944 <<<<<<< HEAD
945  * This function allows a tooltip to expand beyond its parant window's canvas.
946 =======
947  * This function allows a tooltip to expand beyond its parent window's canvas.
948 >>>>>>> remotes/origin/upstream
949  * It will instead be limited only by the size of the display.
950  */
951 EAPI Eina_Bool
952 elm_object_tooltip_window_mode_set(Evas_Object *obj, Eina_Bool disable)
953 {
954    ELM_TOOLTIP_GET_OR_RETURN(tt, obj, EINA_FALSE);
955    return tt->free_size = disable;
956 }
957
958 /**
959  * @brief Retrieve size restriction state of an object's tooltip
960  * @param obj The tooltip's anchor object
961  * @return If EINA_TRUE, size restrictions are disabled
962  *
963  * This function returns whether a tooltip is allowed to expand beyond
964 <<<<<<< HEAD
965  * its parant window's canvas.
966 =======
967  * its parent window's canvas.
968 >>>>>>> remotes/origin/upstream
969  * It will instead be limited only by the size of the display.
970  */
971 EAPI Eina_Bool
972 elm_object_tooltip_window_mode_get(const Evas_Object *obj)
973 {
974    ELM_TOOLTIP_GET_OR_RETURN(tt, obj, EINA_FALSE);
975    return tt->free_size;
976 }