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