Elementary: Added the infrastructure for ui-mirroring support.
[framework/uifw/elementary.git] / src / lib / elm_widget.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 static const char SMART_NAME[] = "elm_widget";
5
6 #define API_ENTRY \
7    Smart_Data *sd = evas_object_smart_data_get(obj); \
8    if ((!obj) || (!sd) || (!_elm_widget_is(obj)))
9 #define INTERNAL_ENTRY \
10    Smart_Data *sd = evas_object_smart_data_get(obj); \
11    if (!sd) return;
12
13 typedef struct _Smart_Data Smart_Data;
14 typedef struct _Edje_Signal_Data Edje_Signal_Data;
15 typedef struct _Elm_Event_Cb_Data Elm_Event_Cb_Data;
16
17 struct _Smart_Data
18 {
19    Evas_Object   *obj;
20    const char    *type;
21    Evas_Object   *parent_obj;
22    Evas_Coord     x, y, w, h;
23    Eina_List     *subobjs;
24    Evas_Object   *resize_obj;
25    Evas_Object   *hover_obj;
26    Eina_List     *tooltips, *cursors;
27    void         (*del_func) (Evas_Object *obj);
28    void         (*del_pre_func) (Evas_Object *obj);
29    void         (*focus_func) (Evas_Object *obj);
30    void         (*activate_func) (Evas_Object *obj);
31    void         (*disable_func) (Evas_Object *obj);
32    void         (*theme_func) (Evas_Object *obj);
33    Eina_Bool    (*event_func) (Evas_Object *obj, Evas_Object *source, Evas_Callback_Type type, void *event_info);
34    void         (*signal_func) (Evas_Object *obj, const char *emission,
35                                 const char *source);
36    void         (*callback_add_func) (Evas_Object *obj, const char *emission,
37                                 const char *source, void (*func) (void *data,
38                                    Evas_Object *o, const char *emission,
39                                    const char *source), void *data);
40    void         (*callback_del_func) (Evas_Object *obj, const char *emission,
41                                   const char *source, void (*func) (void *data,
42                                      Evas_Object *o, const char *emission,
43                                      const char *source), void *data);
44    void         (*changed_func) (Evas_Object *obj);
45    Eina_Bool    (*focus_next_func) (const Evas_Object *obj, Elm_Focus_Direction dir,
46                                     Evas_Object **next);
47    void         (*on_focus_func) (void *data, Evas_Object *obj);
48    void          *on_focus_data;
49    void         (*on_change_func) (void *data, Evas_Object *obj);
50    void          *on_change_data;
51    void         (*on_show_region_func) (void *data, Evas_Object *obj);
52    void          *on_show_region_data;
53    void         (*focus_region_func) (Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h);
54    void         (*on_focus_region_func) (const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h);
55    void          *data;
56    Evas_Coord     rx, ry, rw, rh;
57    int            scroll_hold;
58    int            scroll_freeze;
59    double         scale;
60    Elm_Theme     *theme;
61    const char    *style;
62    unsigned int   focus_order;
63    Eina_Bool      focus_order_on_calc;
64    
65    int            child_drag_x_locked;
66    int            child_drag_y_locked;
67
68    Eina_List     *edje_signals;
69
70    Eina_Bool      drag_x_locked : 1;
71    Eina_Bool      drag_y_locked : 1;
72    
73    Eina_Bool      can_focus : 1;
74    Eina_Bool      child_can_focus : 1;
75    Eina_Bool      focused : 1;
76    Eina_Bool      highlight_ignore : 1;
77    Eina_Bool      highlight_in_theme : 1;
78    Eina_Bool      disabled : 1;
79    Eina_Bool      is_mirrored : 1;
80
81    Eina_List     *focus_chain;
82    Eina_List     *event_cb;
83 };
84
85 struct _Edje_Signal_Data
86 {
87    Evas_Object *obj;
88    Edje_Signal_Cb func;
89    const char *emission;
90    const char *source;
91    void *data;
92 };
93
94 struct _Elm_Event_Cb_Data {
95      Elm_Event_Cb func;
96      const void *data;
97 };
98
99 /* local subsystem functions */
100 static void _smart_reconfigure(Smart_Data *sd);
101 static void _smart_add(Evas_Object *obj);
102 static void _smart_del(Evas_Object *obj);
103 static void _smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y);
104 static void _smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h);
105 static void _smart_show(Evas_Object *obj);
106 static void _smart_hide(Evas_Object *obj);
107 static void _smart_color_set(Evas_Object *obj, int r, int g, int b, int a);
108 static void _smart_clip_set(Evas_Object *obj, Evas_Object * clip);
109 static void _smart_clip_unset(Evas_Object *obj);
110 static void _smart_calculate(Evas_Object *obj);
111 static void _smart_init(void);
112
113 static void _if_focused_revert(Evas_Object *obj, Eina_Bool can_focus_only);
114 static Evas_Object *_newest_focus_order_get(Evas_Object *obj, unsigned int *newest_focus_order, Eina_Bool can_focus_only);
115
116 /* local subsystem globals */
117 static Evas_Smart *_e_smart = NULL;
118 static Eina_List  *widtypes = NULL;
119
120 static unsigned int focus_order = 0;
121
122 // internal funcs
123 static inline Eina_Bool
124 _elm_widget_is(const Evas_Object *obj)
125 {
126    const char *type = evas_object_type_get(obj);
127    return type == SMART_NAME;
128 }
129
130 static inline Eina_Bool
131 _is_focusable(Evas_Object *obj)
132 {
133    API_ENTRY return EINA_FALSE;
134    return sd->can_focus || (sd->child_can_focus);
135 }
136
137 static void
138 _unfocus_parents(Evas_Object *obj)
139 {
140    for (; obj; obj = elm_widget_parent_get(obj))
141      {
142         Smart_Data *sd = evas_object_smart_data_get(obj);
143         if (!sd) return;
144         if (!sd->focused) return;
145         sd->focused = 0;
146      }
147 }
148
149 static void
150 _focus_parents(Evas_Object *obj)
151 {
152    for (; obj; obj = elm_widget_parent_get(obj))
153      {
154         Smart_Data *sd = evas_object_smart_data_get(obj);
155         if (!sd) return;
156         if (sd->focused) return;
157         sd->focused = 1;
158      }
159 }
160
161 static void
162 _sub_obj_del(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
163 {
164    Smart_Data *sd = data;
165
166    if (_elm_widget_is(obj))
167      {
168         if (elm_widget_focus_get(obj)) _unfocus_parents(sd->obj);
169      }
170    if (obj == sd->resize_obj)
171      sd->resize_obj = NULL;
172    else if (obj == sd->hover_obj)
173      sd->hover_obj = NULL;
174    else
175      sd->subobjs = eina_list_remove(sd->subobjs, obj);
176    evas_object_smart_callback_call(sd->obj, "sub-object-del", obj);
177 }
178
179 static void
180 _sub_obj_mouse_down(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
181 {
182    Evas_Object *o = obj;
183    do 
184      {
185         if (_elm_widget_is(o)) break;
186         o = evas_object_smart_parent_get(o);
187      }
188    while (o);
189    if (!o) return;
190    if (!_is_focusable(o)) return;
191    elm_widget_focus_steal(o);
192 }
193
194 static void
195 _propagate_x_drag_lock(Evas_Object *obj, int dir)
196 {
197    Smart_Data *sd = evas_object_smart_data_get(obj);
198    if (sd->parent_obj)
199      {
200         Smart_Data *sd2 = evas_object_smart_data_get(sd->parent_obj);
201         if (sd2)
202           {
203              sd2->child_drag_x_locked += dir;
204              _propagate_x_drag_lock(sd->parent_obj, dir);
205           }
206      }
207 }
208
209 static void
210 _propagate_y_drag_lock(Evas_Object *obj, int dir)
211 {
212    Smart_Data *sd = evas_object_smart_data_get(obj);
213    if (sd->parent_obj)
214      {
215         Smart_Data *sd2 = evas_object_smart_data_get(sd->parent_obj);
216         if (sd2)
217           {
218              sd2->child_drag_y_locked += dir;
219              _propagate_y_drag_lock(sd->parent_obj, dir);
220           }
221      }
222 }
223
224 static void
225 _propagate_event(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info)
226 {
227    INTERNAL_ENTRY;
228    Evas_Callback_Type type = (Evas_Callback_Type)(long) data;
229    Evas_Event_Flags *event_flags = NULL;
230
231    switch (type)
232      {
233      case EVAS_CALLBACK_KEY_DOWN:
234           {
235              Evas_Event_Key_Down *ev = event_info;
236              event_flags = &(ev->event_flags);
237              break;
238           }
239      case EVAS_CALLBACK_KEY_UP:
240           {
241              Evas_Event_Key_Up *ev = event_info;
242              event_flags = &(ev->event_flags);
243              break;
244           }
245      case EVAS_CALLBACK_MOUSE_WHEEL:
246           {
247              Evas_Event_Mouse_Wheel *ev = event_info;
248              event_flags = &(ev->event_flags);
249              break;
250           }
251      default:
252         break;
253      }
254
255    elm_widget_event_propagate(obj, type, event_info, event_flags);
256 }
257
258 static void
259 _parent_focus(Evas_Object *obj)
260 {
261    API_ENTRY return;
262
263    Evas_Object *o = elm_widget_parent_get(obj);
264    sd->focus_order_on_calc = EINA_TRUE;
265
266    if (sd->focused) return;
267    if (o)
268      {
269         unsigned int i = 0;
270         Evas_Object *ret;
271
272         ret = _newest_focus_order_get(o, &i, EINA_TRUE);
273
274         /* we don't want to bump a common widget ancestor's
275            focus_order *twice* while parent focusing */
276         if (!ret || (!i) || (i != focus_order))
277           _parent_focus(o);
278      }
279
280    if (!sd->focus_order_on_calc)
281      return; /* we don't want to override it if by means of any of the
282                 callbacks below one gets to calculate our order
283                 first. */
284
285    focus_order++;
286    sd->focus_order = focus_order;
287    sd->focused = EINA_TRUE;
288    if (sd->on_focus_func) sd->on_focus_func(sd->on_focus_data, obj);
289    if (sd->focus_func) sd->focus_func(obj);
290
291    _elm_widget_focus_region_show(obj);
292
293    sd->focus_order_on_calc = EINA_FALSE;
294 }
295
296 static void
297 _elm_object_focus_chain_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
298 {
299    Smart_Data *sd = data;
300
301    sd->focus_chain = eina_list_remove(sd->focus_chain, obj);
302 }
303
304 // exposed util funcs to elm
305 void
306 _elm_widget_type_clear(void)
307 {
308    const char **ptr;
309    
310    EINA_LIST_FREE(widtypes, ptr)
311      {
312         eina_stringshare_del(*ptr);
313         *ptr = NULL;
314      }
315 }
316
317 void
318 _elm_widget_focus_region_show(const Evas_Object *obj)
319 {
320    Evas_Coord x, y, w, h, ox, oy;
321    Smart_Data *sd2;
322    Evas_Object *o;
323
324    API_ENTRY return;
325
326    o = elm_widget_parent_get(obj);
327    if (!o) return;
328
329    elm_widget_focus_region_get(obj, &x, &y, &w, &h);
330    evas_object_geometry_get(obj, &ox, &oy, NULL, NULL);
331    while (o)
332      {
333         Evas_Coord px, py;
334         sd2 = evas_object_smart_data_get(o);
335         if (sd2->focus_region_func)
336           {
337              sd2->focus_region_func(o, x, y, w, h);
338              elm_widget_focus_region_get(o, &x, &y, &w, &h);
339           }
340         else
341           {
342              evas_object_geometry_get(o, &px, &py, NULL, NULL);
343              x += ox - px;
344              y += oy - py;
345              ox = px;
346              oy = py;
347           }
348         o = elm_widget_parent_get(o);
349      }
350 }
351
352 /**
353  * @defgroup Widget Widget
354  *
355  * @internal
356  * Exposed api for making widgets
357  */
358 EAPI void
359 elm_widget_type_register(const char **ptr)
360 {
361    widtypes = eina_list_append(widtypes, (void *)ptr);
362 }
363
364 EAPI Eina_Bool
365 elm_widget_api_check(int ver)
366 {
367    if (ver != ELM_INTERNAL_API_VERSION)
368      {
369         CRITICAL("Elementary widget api versions do not match");
370         return EINA_FALSE;
371      }
372    return EINA_TRUE;
373 }
374
375 EAPI Evas_Object *
376 elm_widget_add(Evas *evas)
377 {
378    Evas_Object *obj;
379    _smart_init();
380    obj = evas_object_smart_add(evas, _e_smart);
381    elm_widget_mirrored_set(obj, elm_mirrored_get());
382    return obj;
383 }
384
385 EAPI void
386 elm_widget_del_hook_set(Evas_Object *obj, void (*func) (Evas_Object *obj))
387 {
388    API_ENTRY return;
389    sd->del_func = func;
390 }
391
392 EAPI void
393 elm_widget_del_pre_hook_set(Evas_Object *obj, void (*func) (Evas_Object *obj))
394 {
395    API_ENTRY return;
396    sd->del_pre_func = func;
397 }
398
399 EAPI void
400 elm_widget_focus_hook_set(Evas_Object *obj, void (*func) (Evas_Object *obj))
401 {
402    API_ENTRY return;
403    sd->focus_func = func;
404 }
405
406 EAPI void
407 elm_widget_activate_hook_set(Evas_Object *obj, void (*func) (Evas_Object *obj))
408 {
409    API_ENTRY return;
410    sd->activate_func = func;
411 }
412
413 EAPI void
414 elm_widget_disable_hook_set(Evas_Object *obj, void (*func) (Evas_Object *obj))
415 {
416    API_ENTRY return;
417    sd->disable_func = func;
418 }
419
420 EAPI void
421 elm_widget_theme_hook_set(Evas_Object *obj, void (*func) (Evas_Object *obj))
422 {
423    API_ENTRY return;
424    sd->theme_func = func;
425 }
426
427 EAPI void
428 elm_widget_event_hook_set(Evas_Object *obj, Eina_Bool (*func) (Evas_Object *obj, Evas_Object *source, Evas_Callback_Type type, void *event_info))
429 {
430    API_ENTRY return;
431    sd->event_func = func;
432 }
433
434 EAPI void
435 elm_widget_changed_hook_set(Evas_Object *obj, void (*func) (Evas_Object *obj))
436 {
437    API_ENTRY return;
438    sd->changed_func = func;
439 }
440
441 EAPI void
442 elm_widget_signal_emit_hook_set(Evas_Object *obj, void (*func) (Evas_Object *obj, const char *emission, const char *source))
443 {
444    API_ENTRY return;
445    sd->signal_func = func;
446 }
447
448 EAPI void
449 elm_widget_signal_callback_add_hook_set(Evas_Object *obj, void (*func) (Evas_Object *obj, const char *emission, const char *source, void (*func_cb) (void *data, Evas_Object *o, const char *emission, const char *source), void *data))
450 {
451    API_ENTRY return;
452    sd->callback_add_func = func;
453 }
454
455 EAPI void
456 elm_widget_signal_callback_del_hook_set(Evas_Object *obj, void (*func) (Evas_Object *obj, const char *emission, const char *source, void (*func_cb) (void *data, Evas_Object *o, const char *emission, const char *source), void *data))
457 {
458    API_ENTRY return;
459    sd->callback_del_func = func;
460 }
461
462 EAPI void
463 elm_widget_theme(Evas_Object *obj)
464 {
465    const Eina_List *l;
466    Evas_Object *child;
467    Elm_Tooltip *tt;
468    Elm_Cursor *cur;
469
470    API_ENTRY return;
471    EINA_LIST_FOREACH(sd->subobjs, l, child) elm_widget_theme(child);
472    if (sd->resize_obj) elm_widget_theme(sd->resize_obj);
473    if (sd->hover_obj) elm_widget_theme(sd->hover_obj);
474    EINA_LIST_FOREACH(sd->tooltips, l, tt) elm_tooltip_theme(tt);
475    EINA_LIST_FOREACH(sd->cursors, l, cur) elm_cursor_theme(cur);
476    if (sd->theme_func) sd->theme_func(obj);
477 }
478
479 EAPI void
480 elm_widget_theme_specific(Evas_Object *obj, Elm_Theme *th, Eina_Bool force)
481 {
482    const Eina_List *l;
483    Evas_Object *child;
484    Elm_Tooltip *tt;
485    Elm_Cursor *cur;
486    Elm_Theme *th2, *thdef;
487
488    API_ENTRY return;
489    thdef = elm_theme_default_get();
490    if (!th) th = thdef;
491    if (!force)
492      {
493         th2 = sd->theme;
494         if (!th2) th2 = thdef;
495         while (th2)
496           {
497              if (th2 == th)
498                {
499                   force = EINA_TRUE;
500                   break;
501                }
502              if (th2 == thdef) break;
503              th2 = th2->ref_theme;
504              if (!th2) th2 = thdef;
505           }
506      }
507    if (!force) return;
508    EINA_LIST_FOREACH(sd->subobjs, l, child)
509      elm_widget_theme_specific(child, th, force);
510    if (sd->resize_obj) elm_widget_theme(sd->resize_obj);
511    if (sd->hover_obj) elm_widget_theme(sd->hover_obj);
512    EINA_LIST_FOREACH(sd->tooltips, l, tt) elm_tooltip_theme(tt);
513    EINA_LIST_FOREACH(sd->cursors, l, cur) elm_cursor_theme(cur);
514    if (sd->theme_func) sd->theme_func(obj);
515 }
516
517 /**
518  * @internal
519  *
520  * Set hook to get next object in object focus chain.
521  *
522  * @param obj The widget object.
523  * @param func The hook to be used with this widget.
524  *
525  * @ingroup Widget
526  */
527 EAPI void
528 elm_widget_focus_next_hook_set(Evas_Object *obj, Eina_Bool (*func) (const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next))
529 {
530    API_ENTRY return;
531    sd->focus_next_func = func;
532 }
533
534 /**
535  * Returns the widget's mirrored mode.
536  *
537  * @param obj The widget.
538  * @return mirrored mode of the object.
539  *
540  **/
541 EAPI Eina_Bool
542 elm_widget_mirrored_get(const Evas_Object *obj)
543 {
544    API_ENTRY return EINA_FALSE;
545    return sd->is_mirrored;
546 }
547
548 /**
549  * Sets the widget's mirrored mode.
550  *
551  * @param obj The widget.
552  * @param mirrored EINA_TRUE to set mirrored mode. EINA_FALSE to unset.
553  */
554 EAPI void
555 elm_widget_mirrored_set(Evas_Object *obj, Eina_Bool mirrored)
556 {
557    API_ENTRY return;
558    if (sd->is_mirrored != mirrored)
559      {
560         sd->is_mirrored = mirrored;
561         elm_widget_theme(obj);
562      }
563 }
564
565 EAPI void
566 elm_widget_on_focus_hook_set(Evas_Object *obj, void (*func) (void *data, Evas_Object *obj), void *data)
567 {
568    API_ENTRY return;
569    sd->on_focus_func = func;
570    sd->on_focus_data = data;
571 }
572
573 EAPI void
574 elm_widget_on_change_hook_set(Evas_Object *obj, void (*func) (void *data, Evas_Object *obj), void *data)
575 {
576    API_ENTRY return;
577    sd->on_change_func = func;
578    sd->on_change_data = data;
579 }
580
581 EAPI void
582 elm_widget_on_show_region_hook_set(Evas_Object *obj, void (*func) (void *data, Evas_Object *obj), void *data)
583 {
584    API_ENTRY return;
585    sd->on_show_region_func = func;
586    sd->on_show_region_data = data;
587 }
588
589 /**
590  * @internal
591  *
592  * Set the hook to use to show the focused region.
593  *
594  * Whenever a new widget gets focused or it's needed to show the focused
595  * area of the current one, this hook will be called on objects that may
596  * want to move their children into their visible area.
597  * The area given in the hook function is relative to the @p obj widget.
598  *
599  * @param obj The widget object
600  * @param func The function to call to show the specified area.
601  *
602  * @ingroup Widget
603  */
604 EAPI void
605 elm_widget_focus_region_hook_set(Evas_Object *obj, void (*func) (Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h))
606 {
607    API_ENTRY return;
608    sd->focus_region_func = func;
609 }
610
611 /**
612  * @internal
613  *
614  * Set the hook to retrieve the focused region of a widget.
615  *
616  * This hook will be called by elm_widget_focus_region_get() whenever
617  * it's needed to get the focused area of a widget. The area must be relative
618  * to the widget itself and if no hook is set, it will default to the entire
619  * object.
620  *
621  * @param obj The widget object
622  * @param func The function used to retrieve the focus region.
623  *
624  * @ingroup Widget
625  */
626 EAPI void
627 elm_widget_on_focus_region_hook_set(Evas_Object *obj, void (*func) (const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h))
628 {
629    API_ENTRY return;
630    sd->on_focus_region_func = func;
631 }
632
633 EAPI void
634 elm_widget_data_set(Evas_Object *obj, void *data)
635 {
636    API_ENTRY return;
637    sd->data = data;
638 }
639
640 EAPI void *
641 elm_widget_data_get(const Evas_Object *obj)
642 {
643    API_ENTRY return NULL;
644    return sd->data;
645 }
646
647 EAPI void
648 elm_widget_sub_object_add(Evas_Object *obj, Evas_Object *sobj)
649 {
650    API_ENTRY return;
651    double scale, pscale = elm_widget_scale_get(sobj);
652    Elm_Theme *th, *pth = elm_widget_theme_get(sobj);
653    Eina_Bool mirrored, pmirrored = elm_widget_mirrored_get(obj);
654
655    if (_elm_widget_is(sobj))
656      {
657         Smart_Data *sd2 = evas_object_smart_data_get(sobj);
658         if (sd2)
659           {
660              if (sd2->parent_obj == obj)
661                return;
662              elm_widget_sub_object_del(sd2->parent_obj, sobj);
663              sd2->parent_obj = obj;
664              if (!sd->child_can_focus && (_is_focusable(sobj)))
665                sd->child_can_focus = EINA_TRUE;
666           }
667      }
668    else
669      {
670         void *data = evas_object_data_get(sobj, "elm-parent");
671         if (data)
672           {
673              if (data == obj) return;
674              evas_object_event_callback_del(sobj, EVAS_CALLBACK_DEL, 
675                                             _sub_obj_del);
676           }
677      }
678
679    sd->subobjs = eina_list_append(sd->subobjs, sobj);
680    evas_object_data_set(sobj, "elm-parent", obj);
681    evas_object_event_callback_add(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
682    evas_object_smart_callback_call(obj, "sub-object-add", sobj);
683    scale = elm_widget_scale_get(sobj);
684    th = elm_widget_theme_get(sobj);
685    mirrored = elm_widget_mirrored_get(sobj);
686    if ((scale != pscale) || (th != pth) || (pmirrored != mirrored)) elm_widget_theme(sobj);
687    if (elm_widget_focus_get(sobj)) _focus_parents(obj);
688 }
689
690 EAPI void
691 elm_widget_sub_object_del(Evas_Object *obj, Evas_Object *sobj)
692 {
693    Evas_Object *sobj_parent;
694    API_ENTRY return;
695    if (!sobj) return;
696
697    sobj_parent = evas_object_data_del(sobj, "elm-parent");
698    if (sobj_parent != obj)
699      {
700         static int abort_on_warn = -1;
701         ERR("removing sub object %p from parent %p, "
702             "but elm-parent is different %p!",
703             sobj, obj, sobj_parent);
704         if (EINA_UNLIKELY(abort_on_warn == -1))
705           {
706              if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
707              else abort_on_warn = 0;
708           }
709         if (abort_on_warn == 1) abort();
710      }
711    if (!sd->child_can_focus)
712      {
713         if (_is_focusable(sobj)) sd->child_can_focus = 0;
714      }
715    if (_elm_widget_is(sobj))
716      {
717         Smart_Data *sd2 = evas_object_smart_data_get(sobj);
718         if (sd2)
719           {
720              sd2->parent_obj = NULL;
721              if (sd2->resize_obj == sobj)
722                sd2->resize_obj = NULL;
723              else
724                sd->subobjs = eina_list_remove(sd->subobjs, sobj);
725           }
726         else
727           sd->subobjs = eina_list_remove(sd->subobjs, sobj);
728         if (elm_widget_focus_get(sobj)) _unfocus_parents(obj);
729      }
730    else
731      sd->subobjs = eina_list_remove(sd->subobjs, sobj);
732    evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL, 
733                                        _sub_obj_del, sd);
734    evas_object_smart_callback_call(obj, "sub-object-del", sobj);
735 }
736
737 EAPI void
738 elm_widget_resize_object_set(Evas_Object *obj, Evas_Object *sobj)
739 {
740    API_ENTRY return;
741    // orphan previous resize obj
742    if (sd->resize_obj)
743      {
744         evas_object_clip_unset(sd->resize_obj);
745         evas_object_data_del(sd->resize_obj, "elm-parent");
746         if (_elm_widget_is(sd->resize_obj))
747           {
748              Smart_Data *sd2 = evas_object_smart_data_get(sd->resize_obj);
749              if (sd2) sd2->parent_obj = NULL;
750           }
751         evas_object_event_callback_del_full(sd->resize_obj, EVAS_CALLBACK_DEL,
752                                             _sub_obj_del, sd);
753         evas_object_event_callback_del_full(sd->resize_obj, EVAS_CALLBACK_MOUSE_DOWN,
754                                             _sub_obj_mouse_down, sd);
755         evas_object_smart_member_del(sd->resize_obj);
756         if (_elm_widget_is(sd->resize_obj))
757           {
758              if (elm_widget_focus_get(sd->resize_obj)) _unfocus_parents(obj);
759           }
760      }
761    // orphan new resize obj
762    if (sobj)
763      {
764         evas_object_data_del(sobj, "elm-parent");
765         if (_elm_widget_is(sobj))
766           {
767              Smart_Data *sd2 = evas_object_smart_data_get(sobj);
768              if (sd2) sd2->parent_obj = NULL;
769           }
770         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL,
771                                             _sub_obj_del, sd);
772         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_MOUSE_DOWN,
773                                             _sub_obj_mouse_down, sd);
774         evas_object_smart_member_del(sobj);
775         if (_elm_widget_is(sobj))
776           {
777              if (elm_widget_focus_get(sobj)) _unfocus_parents(obj);
778           }
779      }
780    // set the resize obj up
781    sd->resize_obj = sobj;
782    if (sd->resize_obj)
783      {
784         if (_elm_widget_is(sd->resize_obj))
785           {
786              Smart_Data *sd2 = evas_object_smart_data_get(sd->resize_obj);
787              if (sd2) sd2->parent_obj = obj;
788           }
789         evas_object_clip_set(sobj, evas_object_clip_get(obj));
790         evas_object_smart_member_add(sobj, obj);
791         evas_object_event_callback_add(sobj, EVAS_CALLBACK_DEL,
792                                        _sub_obj_del, sd);
793         evas_object_event_callback_add(sobj, EVAS_CALLBACK_MOUSE_DOWN,
794                                        _sub_obj_mouse_down, sd);
795         _smart_reconfigure(sd);
796         evas_object_data_set(sobj, "elm-parent", obj);
797         evas_object_smart_callback_call(obj, "sub-object-add", sobj);
798         if (_elm_widget_is(sobj))
799           {
800              if (elm_widget_focus_get(sobj)) _focus_parents(obj);
801           }
802      }
803 }
804
805 EAPI void
806 elm_widget_hover_object_set(Evas_Object *obj, Evas_Object *sobj)
807 {
808    API_ENTRY return;
809    if (sd->hover_obj)
810      {
811         evas_object_event_callback_del_full(sd->hover_obj, EVAS_CALLBACK_DEL,
812            _sub_obj_del, sd);
813      }
814    sd->hover_obj = sobj;
815    if (sd->hover_obj)
816      {
817         evas_object_event_callback_add(sobj, EVAS_CALLBACK_DEL,
818                                        _sub_obj_del, sd);
819         _smart_reconfigure(sd);
820      }
821 }
822
823 EAPI void
824 elm_widget_can_focus_set(Evas_Object *obj, Eina_Bool can_focus)
825 {
826    API_ENTRY return;
827    sd->can_focus = can_focus;
828    if (can_focus)
829      {
830         evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_DOWN,
831                                        _propagate_event,
832                                        (void *)(long) EVAS_CALLBACK_KEY_DOWN);
833         evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_UP,
834                                        _propagate_event,
835                                        (void *)(long) EVAS_CALLBACK_KEY_UP);
836         evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_WHEEL,
837                                        _propagate_event,
838                                        (void *)(long)EVAS_CALLBACK_MOUSE_WHEEL);
839      }
840    else
841      {
842         evas_object_event_callback_del(obj, EVAS_CALLBACK_KEY_DOWN,
843                                        _propagate_event);
844         evas_object_event_callback_del(obj, EVAS_CALLBACK_KEY_UP,
845                                        _propagate_event);
846         evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_WHEEL,
847                                        _propagate_event);
848      }
849 }
850
851 EAPI Eina_Bool
852 elm_widget_can_focus_get(const Evas_Object *obj)
853 {
854    API_ENTRY return EINA_FALSE;
855    return sd->can_focus;
856 }
857
858 EAPI Eina_Bool
859 elm_widget_child_can_focus_get(const Evas_Object *obj)
860 {
861    API_ENTRY return EINA_FALSE;
862    return sd->child_can_focus;
863 }
864
865 EAPI void
866 elm_widget_highlight_ignore_set(Evas_Object *obj, Eina_Bool ignore)
867 {
868    API_ENTRY return;
869    sd->highlight_ignore = !!ignore;
870 }
871
872 EAPI Eina_Bool
873 elm_widget_highlight_ignore_get(const Evas_Object *obj)
874 {
875    API_ENTRY return EINA_FALSE;
876    return sd->highlight_ignore;
877 }
878
879 EAPI void
880 elm_widget_highlight_in_theme_set(Evas_Object *obj, Eina_Bool highlight)
881 {
882    API_ENTRY return;
883    sd->highlight_in_theme = !!highlight;
884    /* FIXME: if focused, it should switch from one mode to the other */
885 }
886
887 EAPI Eina_Bool
888 elm_widget_highlight_in_theme_get(const Evas_Object *obj)
889 {
890    API_ENTRY return EINA_FALSE;
891    return sd->highlight_in_theme;
892 }
893
894 EAPI Eina_Bool
895 elm_widget_focus_get(const Evas_Object *obj)
896 {
897    API_ENTRY return EINA_FALSE;
898    return sd->focused;
899 }
900
901 EAPI Evas_Object *
902 elm_widget_focused_object_get(const Evas_Object *obj)
903 {
904    const Evas_Object *subobj;
905    const Eina_List *l;
906    API_ENTRY return NULL;
907
908    if (!sd->focused) return NULL;
909    EINA_LIST_FOREACH(sd->subobjs, l, subobj)
910      {
911         Evas_Object *fobj = elm_widget_focused_object_get(subobj);
912         if (fobj) return fobj;
913      }
914    return (Evas_Object *)obj;
915 }
916
917 EAPI Evas_Object *
918 elm_widget_top_get(const Evas_Object *obj)
919 {
920    API_ENTRY return NULL;
921    if (sd->parent_obj) return elm_widget_top_get(sd->parent_obj);
922    return (Evas_Object *)obj;
923 }
924
925 EAPI Eina_Bool
926 elm_widget_is(const Evas_Object *obj)
927 {
928    return _elm_widget_is(obj);
929 }
930
931 EAPI Evas_Object *
932 elm_widget_parent_widget_get(const Evas_Object *obj)
933 {
934    Evas_Object *parent;
935
936    if (_elm_widget_is(obj))
937      {
938         Smart_Data *sd = evas_object_smart_data_get(obj);
939         if (!sd) return NULL;
940         parent = sd->parent_obj;
941      }
942    else
943      {
944         parent = evas_object_data_get(obj, "elm-parent");
945         if (!parent) parent = evas_object_smart_parent_get(obj);
946      }
947
948    while (parent)
949      {
950         Evas_Object *elm_parent;
951         if (_elm_widget_is(parent)) break;
952         elm_parent = evas_object_data_get(parent, "elm-parent");
953         if (elm_parent) parent = elm_parent;
954         else parent = evas_object_smart_parent_get(parent);
955      }
956    return parent;
957 }
958
959 EAPI void
960 elm_widget_event_callback_add(Evas_Object *obj, Elm_Event_Cb func, const void *data)
961 {
962    API_ENTRY return;
963    EINA_SAFETY_ON_NULL_RETURN(func);
964    Elm_Event_Cb_Data *ecb = ELM_NEW(Elm_Event_Cb_Data);
965    ecb->func = func;
966    ecb->data = data;
967    sd->event_cb = eina_list_append(sd->event_cb, ecb);
968 }
969
970 EAPI void *
971 elm_widget_event_callback_del(Evas_Object *obj, Elm_Event_Cb func, const void *data)
972 {
973    API_ENTRY return NULL;
974    EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL);
975    Eina_List *l;
976    Elm_Event_Cb_Data *ecd;
977    EINA_LIST_FOREACH(sd->event_cb, l, ecd)
978       if ((ecd->func == func) && (ecd->data == data))
979         {
980            free(ecd);
981            sd->event_cb = eina_list_remove_list(sd->event_cb, l);
982            return (void *)data;
983         }
984    return NULL;
985 }
986
987 EAPI Eina_Bool
988 elm_widget_event_propagate(Evas_Object *obj, Evas_Callback_Type type, void *event_info, Evas_Event_Flags *event_flags)
989 {
990    API_ENTRY return EINA_FALSE; //TODO reduce.
991    if (!_elm_widget_is(obj)) return EINA_FALSE;
992    Evas_Object *parent = obj;
993    Elm_Event_Cb_Data *ecd;
994    Eina_List *l, *l_prev;
995
996    while (parent &&
997           (!(event_flags && ((*event_flags) & EVAS_EVENT_FLAG_ON_HOLD))))
998      {
999         sd = evas_object_smart_data_get(parent);
1000         if ((!sd) || (!_elm_widget_is(obj)))
1001           return EINA_FALSE; //Not Elm Widget
1002
1003         if (sd->event_func && (sd->event_func(parent, obj, type, event_info)))
1004           return EINA_TRUE;
1005
1006         EINA_LIST_FOREACH_SAFE(sd->event_cb, l, l_prev, ecd)
1007           {
1008              if (ecd->func((void *)ecd->data, parent, obj, type, event_info) ||
1009                  (event_flags && ((*event_flags) & EVAS_EVENT_FLAG_ON_HOLD)))
1010                  return EINA_TRUE;
1011           }
1012         parent = sd->parent_obj;
1013      }
1014
1015    return EINA_FALSE;
1016 }
1017
1018 /**
1019  * @internal
1020  *
1021  * Set custom focus chain.
1022  *
1023  * This function i set one new and overwrite any previous custom focus chain
1024  * with the list of objects. The previous list will be deleted and this list
1025  * will be managed. After setted, don't modity it.
1026  *
1027  * @note On focus cycle, only will be evaluated children of this container.
1028  *
1029  * @param obj The container widget
1030  * @param objs Chain of objects to pass focus
1031  * @ingroup Widget
1032  */
1033 EAPI void
1034 elm_widget_focus_custom_chain_set(Evas_Object *obj, Eina_List *objs)
1035 {
1036    API_ENTRY return;
1037    if (!sd->focus_next_func)
1038      return;
1039
1040    elm_widget_focus_custom_chain_unset(obj);
1041
1042    Eina_List *l;
1043    Evas_Object *o;
1044
1045    EINA_LIST_FOREACH(objs, l, o)
1046      {
1047         evas_object_event_callback_add(o, EVAS_CALLBACK_DEL,
1048                                        _elm_object_focus_chain_del_cb, sd);
1049      }
1050
1051    sd->focus_chain = objs;
1052 }
1053
1054 /**
1055  * @internal
1056  *
1057  * Get custom focus chain
1058  *
1059  * @param obj The container widget
1060  * @ingroup Widget
1061  */
1062 EAPI const Eina_List *
1063 elm_widget_focus_custom_chain_get(const Evas_Object *obj)
1064 {
1065    API_ENTRY return NULL;
1066    return (const Eina_List *) sd->focus_chain;
1067 }
1068
1069 /**
1070  * @internal
1071  *
1072  * Unset custom focus chain
1073  *
1074  * @param obj The container widget
1075  * @ingroup Widget
1076  */
1077 EAPI void
1078 elm_widget_focus_custom_chain_unset(Evas_Object *obj)
1079 {
1080    API_ENTRY return;
1081    Eina_List *l, *l_next;
1082    Evas_Object *o;
1083
1084    EINA_LIST_FOREACH_SAFE(sd->focus_chain, l, l_next, o)
1085      {
1086         evas_object_event_callback_del_full(o, EVAS_CALLBACK_DEL,
1087                                             _elm_object_focus_chain_del_cb, sd);
1088         sd->focus_chain = eina_list_remove_list(sd->focus_chain, l);
1089      }
1090 }
1091
1092 /**
1093  * @internal
1094  *
1095  * Append object to custom focus chain.
1096  *
1097  * @note If relative_child equal to NULL or not in custom chain, the object
1098  * will be added in end.
1099  *
1100  * @note On focus cycle, only will be evaluated children of this container.
1101  *
1102  * @param obj The container widget
1103  * @param child The child to be added in custom chain
1104  * @param relative_child The relative object to position the child
1105  * @ingroup Widget
1106  */
1107 EAPI void
1108 elm_widget_focus_custom_chain_append(Evas_Object *obj, Evas_Object *child, Evas_Object *relative_child)
1109 {
1110    API_ENTRY return;
1111    EINA_SAFETY_ON_NULL_RETURN(child);
1112    if (!sd->focus_next_func)
1113      return;
1114
1115    evas_object_event_callback_del_full(child, EVAS_CALLBACK_DEL,
1116                                        _elm_object_focus_chain_del_cb, sd);
1117
1118    if (!relative_child)
1119      {
1120         sd->focus_chain = eina_list_append(sd->focus_chain, child);
1121         return;
1122      }
1123
1124    sd->focus_chain = eina_list_append_relative(sd->focus_chain, child, relative_child);
1125    return;
1126 }
1127
1128 /**
1129  * @internal
1130  *
1131  * Prepend object to custom focus chain.
1132  *
1133  * @note If relative_child equal to NULL or not in custom chain, the object
1134  * will be added in begin.
1135  *
1136  * @note On focus cycle, only will be evaluated children of this container.
1137  *
1138  * @param obj The container widget
1139  * @param child The child to be added in custom chain
1140  * @param relative_child The relative object to position the child
1141  * @ingroup Widget
1142  */
1143 EAPI void
1144 elm_widget_focus_custom_chain_prepend(Evas_Object *obj, Evas_Object *child, Evas_Object *relative_child)
1145 {
1146    API_ENTRY return;
1147    EINA_SAFETY_ON_NULL_RETURN(child);
1148    if (!sd->focus_next_func)
1149      return;
1150
1151    evas_object_event_callback_del_full(child, EVAS_CALLBACK_DEL,
1152                                        _elm_object_focus_chain_del_cb, sd);
1153
1154    if (!relative_child)
1155      {
1156         sd->focus_chain = eina_list_prepend(sd->focus_chain, child);
1157         return;
1158      }
1159
1160    sd->focus_chain = eina_list_prepend_relative(sd->focus_chain, child, relative_child);
1161    return;
1162 }
1163
1164 /**
1165  * @internal
1166  *
1167  * Give focus to next object in object tree.
1168  *
1169  * Give focus to next object in focus chain of one object sub-tree.
1170  * If the last object of chain already have focus, the focus will go to the
1171  * first object of chain.
1172  *
1173  * @param obj The widget root of sub-tree
1174  * @param dir Direction to cycle the focus
1175  *
1176  * @ingroup Widget
1177  */
1178 EAPI void
1179 elm_widget_focus_cycle(Evas_Object *obj, Elm_Focus_Direction dir)
1180 {
1181    Evas_Object *target = NULL;
1182    if (!_elm_widget_is(obj))
1183      return;
1184    elm_widget_focus_next_get(obj, dir, &target);
1185    if (target)
1186      elm_widget_focus_steal(target);
1187 }
1188
1189 /**
1190  * @internal
1191  *
1192  * Give focus to near object in one direction.
1193  *
1194  * Give focus to near object in direction of one object.
1195  * If none focusable object in given direction, the focus will not change.
1196  *
1197  * @param obj The reference widget
1198  * @param x Horizontal component of direction to focus
1199  * @param y Vertical component of direction to focus
1200  *
1201  * @ingroup Widget
1202  */
1203 EAPI void
1204 elm_widget_focus_direction_go(Evas_Object *obj __UNUSED__, int x __UNUSED__, int y __UNUSED__)
1205 {
1206    return; /* TODO */
1207 }
1208
1209 /**
1210  * @internal
1211  *
1212  * Get next object in focus chain of object tree.
1213  *
1214  * Get next object in focus chain of one object sub-tree.
1215  * Return the next object by reference. If don't have any candidate to receive
1216  * focus before chain end, the first candidate will be returned.
1217  *
1218  * @param obj The widget root of sub-tree
1219  * @param dir Direction os focus chain
1220  * @param next The next object in focus chain
1221  * @return EINA_TRUE if don't need focus chain restart/loop back
1222  *         to use 'next' obj.
1223  *
1224  * @ingroup Widget
1225  */
1226 EAPI Eina_Bool
1227 elm_widget_focus_next_get(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next)
1228 {
1229    if (!next)
1230      return EINA_FALSE;
1231    *next = NULL;
1232
1233    API_ENTRY return EINA_FALSE;
1234
1235    /* Ignore if disabled */
1236    if ((!evas_object_visible_get(obj)) || (elm_widget_disabled_get(obj)))
1237      return EINA_FALSE;
1238
1239    /* Try use hook */
1240    if (sd->focus_next_func)
1241      return sd->focus_next_func(obj, dir, next);
1242
1243    if (!elm_widget_can_focus_get(obj))
1244      return EINA_FALSE;
1245
1246    /* Return */
1247    *next = (Evas_Object *)obj;
1248    return !elm_widget_focus_get(obj);
1249 }
1250
1251
1252 /**
1253  * @internal
1254  *
1255  * Get next object in focus chain of object tree in list.
1256  *
1257  * Get next object in focus chain of one object sub-tree ordered by one list.
1258  * Return the next object by reference. If don't have any candidate to receive
1259  * focus before list end, the first candidate will be returned.
1260  *
1261  * @param obj The widget root of sub-tree
1262  * @param dir Direction os focus chain
1263  * @param items list with ordered objects
1264  * @param list_data_get function to get the object from one item of list
1265  * @param next The next object in focus chain
1266  * @return EINA_TRUE if don't need focus chain restart/loop back
1267  *         to use 'next' obj.
1268  *
1269  * @ingroup Widget
1270  */
1271 EAPI Eina_Bool
1272 elm_widget_focus_list_next_get(const Evas_Object *obj, const Eina_List *items, void *(*list_data_get) (const Eina_List *list), Elm_Focus_Direction dir, Evas_Object **next)
1273 {
1274    Eina_List *(*list_next) (const Eina_List *list);
1275
1276    if (!next)
1277      return EINA_FALSE;
1278    *next = NULL;
1279
1280    if (!_elm_widget_is(obj))
1281      return EINA_FALSE;
1282
1283    if (!items)
1284      return EINA_FALSE;
1285
1286    /* Direction */
1287    if (dir == ELM_FOCUS_PREVIOUS)
1288      {
1289         items = eina_list_last(items);
1290         list_next = eina_list_prev;
1291      }
1292    else if (dir == ELM_FOCUS_NEXT)
1293      list_next = eina_list_next;
1294    else
1295      return EINA_FALSE;
1296
1297    const Eina_List *l = items;
1298
1299    /* Recovery last focused sub item */
1300    if (elm_widget_focus_get(obj))
1301      for (; l; l = list_next(l))
1302        {
1303           Evas_Object *cur = list_data_get(l);
1304           if (elm_widget_focus_get(cur)) break;
1305        }
1306
1307    const Eina_List *start = l;
1308    Evas_Object *to_focus = NULL;
1309
1310    /* Interate sub items */
1311    /* Go to end of list */
1312    for (; l; l = list_next(l))
1313      {
1314         Evas_Object *tmp = NULL;
1315         Evas_Object *cur = list_data_get(l);
1316
1317         if (elm_widget_parent_get(cur) != obj)
1318           continue;
1319
1320         /* Try Focus cycle in subitem */
1321         if (elm_widget_focus_next_get(cur, dir, &tmp))
1322           {
1323              *next = tmp;
1324              return EINA_TRUE;
1325           }
1326         else if ((tmp) && (!to_focus))
1327           to_focus = tmp;
1328      }
1329
1330    l = items;
1331
1332    /* Get First possible */
1333    for (;l != start; l = list_next(l))
1334      {
1335         Evas_Object *tmp = NULL;
1336         Evas_Object *cur = list_data_get(l);
1337
1338         if (elm_widget_parent_get(cur) != obj)
1339           continue;
1340
1341         /* Try Focus cycle in subitem */
1342         elm_widget_focus_next_get(cur, dir, &tmp);
1343         if (tmp)
1344           {
1345              *next = tmp;
1346              return EINA_FALSE;
1347           }
1348      }
1349
1350    *next = to_focus;
1351    return EINA_FALSE;
1352 }
1353
1354 EAPI void
1355 elm_widget_signal_emit(Evas_Object *obj, const char *emission, const char *source)
1356 {
1357    API_ENTRY return;
1358    if (!sd->signal_func) return;
1359    sd->signal_func(obj, emission, source);
1360 }
1361
1362 static void
1363 _edje_signal_callback(void *data, Evas_Object *obj __UNUSED__, const char *emission, const char *source)
1364 {
1365    Edje_Signal_Data *esd = data;
1366    esd->func(esd->data, esd->obj, emission, source);
1367 }
1368
1369 EAPI void
1370 elm_widget_signal_callback_add(Evas_Object *obj, const char *emission, const char *source, void (*func) (void *data, Evas_Object *o, const char *emission, const char *source), void *data)
1371 {
1372    Edje_Signal_Data *esd;
1373    API_ENTRY return;
1374    if (!sd->callback_add_func) return;
1375    EINA_SAFETY_ON_NULL_RETURN(func);
1376
1377    esd = ELM_NEW(Edje_Signal_Data);
1378    if (!esd) return;
1379
1380    esd->obj = obj;
1381    esd->func = func;
1382    esd->emission = eina_stringshare_add(emission);
1383    esd->source = eina_stringshare_add(source);
1384    esd->data = data;
1385    sd->edje_signals = eina_list_append(sd->edje_signals, esd);
1386    sd->callback_add_func(obj, emission, source, _edje_signal_callback, esd);
1387 }
1388
1389 EAPI void *
1390 elm_widget_signal_callback_del(Evas_Object *obj, const char *emission, const char *source, void (*func) (void *data, Evas_Object *o, const char *emission, const char *source))
1391 {
1392    Edje_Signal_Data *esd;
1393    Eina_List *l;
1394    void *data = NULL;
1395    API_ENTRY return NULL;
1396    if (!sd->callback_del_func) return NULL;
1397
1398    EINA_LIST_FOREACH(sd->edje_signals, l, esd)
1399      {
1400         if ((esd->func == func) && (!strcmp(esd->emission, emission)) &&
1401             (!strcmp(esd->source, source)))
1402           {
1403              sd->edje_signals = eina_list_remove_list(sd->edje_signals, l);
1404              eina_stringshare_del(esd->emission);
1405              eina_stringshare_del(esd->source);
1406              data = esd->data;
1407              free(esd);
1408              break;
1409           }
1410      }
1411    sd->callback_del_func(obj, emission, source, _edje_signal_callback, esd);
1412    return data;
1413 }
1414
1415 EAPI void
1416 elm_widget_focus_set(Evas_Object *obj, int first)
1417 {
1418    API_ENTRY return;
1419    if (!sd->focused)
1420      {
1421         focus_order++;
1422         sd->focus_order = focus_order;
1423         sd->focused = EINA_TRUE;
1424         if (sd->on_focus_func) sd->on_focus_func(sd->on_focus_data, obj);
1425      }
1426    if (sd->focus_func)
1427      {
1428         sd->focus_func(obj);
1429         return;
1430      }
1431    else
1432      {
1433         if (first)
1434           {
1435              if ((_is_focusable(sd->resize_obj)) &&
1436                  (!elm_widget_disabled_get(sd->resize_obj)))
1437                {
1438                   elm_widget_focus_set(sd->resize_obj, first);
1439                }
1440              else
1441                {
1442                   const Eina_List *l;
1443                   Evas_Object *child;
1444                   EINA_LIST_FOREACH(sd->subobjs, l, child)
1445                     {
1446                        if ((_is_focusable(child)) &&
1447                            (!elm_widget_disabled_get(child)))
1448                          {
1449                             elm_widget_focus_set(child, first);
1450                             break;
1451                          }
1452                     }
1453                }
1454           }
1455         else
1456           {
1457              const Eina_List *l;
1458              Evas_Object *child;
1459              EINA_LIST_REVERSE_FOREACH(sd->subobjs, l, child)
1460                {
1461                   if ((_is_focusable(child)) &&
1462                       (!elm_widget_disabled_get(child)))
1463                     {
1464                        elm_widget_focus_set(child, first);
1465                        break;
1466                     }
1467                }
1468              if (!l)
1469                {
1470                   if ((_is_focusable(sd->resize_obj)) &&
1471                       (!elm_widget_disabled_get(sd->resize_obj)))
1472                     {
1473                        elm_widget_focus_set(sd->resize_obj, first);
1474                     }
1475                }
1476           }
1477      }
1478 }
1479
1480 EAPI Evas_Object *
1481 elm_widget_parent_get(const Evas_Object *obj)
1482 {
1483    API_ENTRY return NULL;
1484    return sd->parent_obj;
1485 }
1486
1487 EAPI void
1488 elm_widget_focused_object_clear(Evas_Object *obj)
1489 {
1490    API_ENTRY return;
1491    if (!sd->focused) return;
1492    if (elm_widget_focus_get(sd->resize_obj))
1493       elm_widget_focused_object_clear(sd->resize_obj);
1494    else
1495      {
1496         const Eina_List *l;
1497         Evas_Object *child;
1498         EINA_LIST_FOREACH(sd->subobjs, l, child)
1499           {
1500              if (elm_widget_focus_get(child))
1501                {
1502                   elm_widget_focused_object_clear(child);
1503                   break;
1504                }
1505           }
1506      }
1507    sd->focused = EINA_FALSE;
1508    if (sd->on_focus_func) sd->on_focus_func(sd->on_focus_data, obj);
1509    if (sd->focus_func) sd->focus_func(obj);
1510 }
1511
1512 EAPI void
1513 elm_widget_focus_steal(Evas_Object *obj)
1514 {
1515    Evas_Object *parent, *o;
1516    API_ENTRY return;
1517
1518    if (sd->focused) return;
1519    if (sd->disabled) return;
1520    parent = obj;
1521    for (;;)
1522      {
1523         o = elm_widget_parent_get(parent);
1524         if (!o) break;
1525         sd = evas_object_smart_data_get(o);
1526         if (sd->focused) break;
1527         parent = o;
1528      }
1529    if (!elm_widget_parent_get(parent))
1530      elm_widget_focused_object_clear(parent);
1531    else
1532      {
1533         parent = elm_widget_parent_get(parent);
1534         sd = evas_object_smart_data_get(parent);
1535         if (elm_widget_focus_get(sd->resize_obj))
1536           {
1537              elm_widget_focused_object_clear(sd->resize_obj);
1538           }
1539         else
1540           {
1541              const Eina_List *l;
1542              Evas_Object *child;
1543              EINA_LIST_FOREACH(sd->subobjs, l, child)
1544                {
1545                   if (elm_widget_focus_get(child))
1546                     {
1547                        elm_widget_focused_object_clear(child);
1548                        break;
1549                     }
1550                }
1551           }
1552      }
1553    _parent_focus(obj);
1554    return;
1555 }
1556
1557 EAPI void
1558 elm_widget_activate(Evas_Object *obj)
1559 {
1560    API_ENTRY return;
1561    elm_widget_change(obj);
1562    if (sd->activate_func) sd->activate_func(obj);
1563 }
1564
1565 EAPI void
1566 elm_widget_change(Evas_Object *obj)
1567 {
1568    API_ENTRY return;
1569    elm_widget_change(elm_widget_parent_get(obj));
1570    if (sd->on_change_func) sd->on_change_func(sd->on_change_data, obj);
1571 }
1572
1573 EAPI void
1574 elm_widget_disabled_set(Evas_Object *obj, int disabled)
1575 {
1576    API_ENTRY return;
1577
1578    if (sd->disabled == disabled) return;
1579    sd->disabled = disabled;
1580    if (sd->focused)
1581      {
1582         Evas_Object *o, *parent;
1583
1584         parent = obj;
1585         for (;;)
1586           {
1587              o = elm_widget_parent_get(parent);
1588              if (!o) break;
1589              parent = o;
1590           }
1591         if (elm_widget_focus_get(obj))
1592           elm_widget_focus_cycle(parent, ELM_FOCUS_NEXT);
1593      }
1594    if (sd->disable_func) sd->disable_func(obj);
1595 }
1596
1597 EAPI int
1598 elm_widget_disabled_get(const Evas_Object *obj)
1599 {
1600    API_ENTRY return 0;
1601    return sd->disabled;
1602 }
1603
1604 EAPI void
1605 elm_widget_show_region_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
1606 {
1607    Evas_Object *parent_obj, *child_obj;
1608    Evas_Coord px, py, cx, cy;
1609
1610    API_ENTRY return;
1611    if ((x == sd->rx) && (y == sd->ry) && (w == sd->rw) && (h == sd->rh)) return;
1612    sd->rx = x;
1613    sd->ry = y;
1614    sd->rw = w;
1615    sd->rh = h;
1616    if (sd->on_show_region_func)
1617       sd->on_show_region_func(sd->on_show_region_data, obj);
1618
1619    do
1620      {
1621         parent_obj = sd->parent_obj; 
1622         child_obj = sd->obj;
1623         sd = evas_object_smart_data_get(parent_obj);
1624
1625         if ((!parent_obj) || (!sd) || (!_elm_widget_is(parent_obj))) break;
1626
1627         evas_object_geometry_get(parent_obj, &px, &py, NULL, NULL);
1628         evas_object_geometry_get(child_obj, &cx, &cy, NULL, NULL);
1629
1630         x += (cx - px);
1631         y += (cy - py);
1632         sd->rx = x;
1633         sd->ry = y;
1634         sd->rw = w;
1635         sd->rh = h;
1636
1637         if (sd->on_show_region_func)
1638           {
1639              sd->on_show_region_func(sd->on_show_region_data, parent_obj);
1640           }
1641      }
1642    while (parent_obj);
1643 }
1644
1645 EAPI void
1646 elm_widget_show_region_get(const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
1647 {
1648    API_ENTRY return;
1649    if (x) *x = sd->rx;
1650    if (y) *y = sd->ry;
1651    if (w) *w = sd->rw;
1652    if (h) *h = sd->rh;
1653 }
1654
1655 /**
1656  * @internal
1657  *
1658  * Get the focus region of the given widget.
1659  *
1660  * The focus region is the area of a widget that should brought into the
1661  * visible area when the widget is focused. Mostly used to show the part of
1662  * an entry where the cursor is, for example. The area returned is relative
1663  * to the object @p obj.
1664  * If the @p obj doesn't have the proper on_focus_region_hook set, this
1665  * function will return the full size of the object.
1666  *
1667  * @param obj The widget object
1668  * @param x Where to store the x coordinate of the area
1669  * @param y Where to store the y coordinate of the area
1670  * @param w Where to store the width of the area
1671  * @param h Where to store the height of the area
1672  *
1673  * @ingroup Widget
1674  */
1675 EAPI void
1676 elm_widget_focus_region_get(const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
1677 {
1678    Smart_Data *sd;
1679
1680    if (!obj) return;
1681
1682    sd = evas_object_smart_data_get(obj);
1683    if (!sd || !_elm_widget_is(obj) || !sd->on_focus_region_func)
1684      {
1685         evas_object_geometry_get(obj, NULL, NULL, w, h);
1686         if (x) *x = 0;
1687         if (y) *y = 0;
1688         return;
1689      }
1690    sd->on_focus_region_func(obj, x, y, w, h);
1691 }
1692
1693 EAPI void
1694 elm_widget_scroll_hold_push(Evas_Object *obj)
1695 {
1696    API_ENTRY return;
1697    sd->scroll_hold++;
1698    if (sd->scroll_hold == 1)
1699       evas_object_smart_callback_call(obj, "scroll-hold-on", obj);
1700    if (sd->parent_obj) elm_widget_scroll_hold_push(sd->parent_obj);
1701    // FIXME: on delete/reparent hold pop
1702 }
1703
1704 EAPI void
1705 elm_widget_scroll_hold_pop(Evas_Object *obj)
1706 {
1707    API_ENTRY return;
1708    sd->scroll_hold--;
1709    if (sd->scroll_hold < 0) sd->scroll_hold = 0;
1710    if (!sd->scroll_hold)
1711       evas_object_smart_callback_call(obj, "scroll-hold-off", obj);
1712    if (sd->parent_obj) elm_widget_scroll_hold_pop(sd->parent_obj);
1713 }
1714
1715 EAPI int
1716 elm_widget_scroll_hold_get(const Evas_Object *obj)
1717 {
1718    API_ENTRY return 0;
1719    return sd->scroll_hold;
1720 }
1721
1722 EAPI void
1723 elm_widget_scroll_freeze_push(Evas_Object *obj)
1724 {
1725    API_ENTRY return;
1726    sd->scroll_freeze++;
1727    if (sd->scroll_freeze == 1)
1728       evas_object_smart_callback_call(obj, "scroll-freeze-on", obj);
1729    if (sd->parent_obj) elm_widget_scroll_freeze_push(sd->parent_obj);
1730    // FIXME: on delete/reparent freeze pop
1731 }
1732
1733 EAPI void
1734 elm_widget_scroll_freeze_pop(Evas_Object *obj)
1735 {
1736    API_ENTRY return;
1737    sd->scroll_freeze--;
1738    if (sd->scroll_freeze < 0) sd->scroll_freeze = 0;
1739    if (!sd->scroll_freeze)
1740       evas_object_smart_callback_call(obj, "scroll-freeze-off", obj);
1741    if (sd->parent_obj) elm_widget_scroll_freeze_pop(sd->parent_obj);
1742 }
1743
1744 EAPI int
1745 elm_widget_scroll_freeze_get(const Evas_Object *obj)
1746 {
1747    API_ENTRY return 0;
1748    return sd->scroll_freeze;
1749 }
1750
1751 EAPI void
1752 elm_widget_scale_set(Evas_Object *obj, double scale)
1753 {
1754    API_ENTRY return;
1755    if (scale <= 0.0) scale = 0.0;
1756    if (sd->scale != scale)
1757      {
1758         sd->scale = scale;
1759         elm_widget_theme(obj);
1760      }
1761 }
1762
1763 EAPI double
1764 elm_widget_scale_get(const Evas_Object *obj)
1765 {
1766    API_ENTRY return 1.0;
1767    // FIXME: save walking up the tree by storing/caching parent scale
1768    if (sd->scale == 0.0)
1769      {
1770         if (sd->parent_obj)
1771            return elm_widget_scale_get(sd->parent_obj);
1772         else
1773            return 1.0;
1774      }
1775    return sd->scale;
1776 }
1777
1778 EAPI void
1779 elm_widget_theme_set(Evas_Object *obj, Elm_Theme *th)
1780 {
1781    API_ENTRY return;
1782    if (sd->theme != th)
1783      {
1784         if (sd->theme) elm_theme_free(sd->theme);
1785         sd->theme = th;
1786         if (th) th->ref++;
1787         elm_widget_theme(obj);
1788      }
1789 }
1790
1791 EAPI Elm_Theme *
1792 elm_widget_theme_get(const Evas_Object *obj)
1793 {
1794    API_ENTRY return NULL;
1795    if (!sd->theme)
1796      {
1797         if (sd->parent_obj)
1798            return elm_widget_theme_get(sd->parent_obj);
1799         else
1800            return NULL;
1801      }
1802    return sd->theme;
1803 }
1804
1805 EAPI void
1806 elm_widget_style_set(Evas_Object *obj, const char *style)
1807 {
1808    API_ENTRY return;
1809    
1810    if (eina_stringshare_replace(&sd->style, style))
1811       elm_widget_theme(obj);
1812 }
1813
1814 EAPI const char *
1815 elm_widget_style_get(const Evas_Object *obj)
1816 {
1817    API_ENTRY return NULL;
1818    if (sd->style) return sd->style;
1819    return "default";
1820 }
1821
1822 EAPI void
1823 elm_widget_type_set(Evas_Object *obj, const char *type)
1824 {
1825    API_ENTRY return;
1826    eina_stringshare_replace(&sd->type, type);
1827 }
1828
1829 EAPI const char *
1830 elm_widget_type_get(const Evas_Object *obj)
1831 {
1832    API_ENTRY return NULL;
1833    if (sd->type) return sd->type;
1834    return "";
1835 }
1836
1837 EAPI void
1838 elm_widget_tooltip_add(Evas_Object *obj, Elm_Tooltip *tt)
1839 {
1840    API_ENTRY return;
1841    sd->tooltips = eina_list_append(sd->tooltips, tt);
1842 }
1843
1844 EAPI void
1845 elm_widget_tooltip_del(Evas_Object *obj, Elm_Tooltip *tt)
1846 {
1847    API_ENTRY return;
1848    sd->tooltips = eina_list_remove(sd->tooltips, tt);
1849 }
1850
1851 EAPI void
1852 elm_widget_cursor_add(Evas_Object *obj, Elm_Cursor *cur)
1853 {
1854    API_ENTRY return;
1855    sd->cursors = eina_list_append(sd->cursors, cur);
1856 }
1857
1858 EAPI void
1859 elm_widget_cursor_del(Evas_Object *obj, Elm_Cursor *cur)
1860 {
1861    API_ENTRY return;
1862    sd->cursors = eina_list_remove(sd->cursors, cur);
1863 }
1864
1865 EAPI void
1866 elm_widget_drag_lock_x_set(Evas_Object *obj, Eina_Bool lock)
1867 {
1868    API_ENTRY return;
1869    if (sd->drag_x_locked == lock) return;
1870    sd->drag_x_locked = lock;
1871    if (sd->drag_x_locked) _propagate_x_drag_lock(obj, 1);
1872    else _propagate_x_drag_lock(obj, -1);
1873 }
1874
1875 EAPI void
1876 elm_widget_drag_lock_y_set(Evas_Object *obj, Eina_Bool lock)
1877 {
1878    API_ENTRY return;
1879    if (sd->drag_y_locked == lock) return;
1880    sd->drag_y_locked = lock;
1881    if (sd->drag_y_locked) _propagate_y_drag_lock(obj, 1);
1882    else _propagate_y_drag_lock(obj, -1);
1883 }
1884
1885 EAPI Eina_Bool
1886 elm_widget_drag_lock_x_get(const Evas_Object *obj)
1887 {
1888    API_ENTRY return EINA_FALSE;
1889    return sd->drag_x_locked;
1890 }
1891
1892 EAPI Eina_Bool
1893 elm_widget_drag_lock_y_get(const Evas_Object *obj)
1894 {
1895    API_ENTRY return EINA_FALSE;
1896    return sd->drag_y_locked;
1897 }
1898
1899 EAPI int
1900 elm_widget_drag_child_locked_x_get(const Evas_Object *obj)
1901 {
1902    API_ENTRY return 0;
1903    return sd->child_drag_x_locked;
1904 }
1905
1906 EAPI int
1907 elm_widget_drag_child_locked_y_get(const Evas_Object *obj)
1908 {
1909    API_ENTRY return 0;
1910    return sd->child_drag_y_locked;
1911 }
1912
1913 EAPI Eina_Bool
1914 elm_widget_theme_object_set(Evas_Object *obj, Evas_Object *edj, const char *wname, const char *welement, const char *wstyle)
1915 {
1916    API_ENTRY return EINA_FALSE;
1917    return _elm_theme_object_set(obj, edj, wname, welement, wstyle);
1918 }
1919
1920 EAPI Eina_Bool
1921 elm_widget_type_check(const Evas_Object *obj, const char *type)
1922 {
1923    const char *provided, *expected = "(unknown)";
1924    static int abort_on_warn = -1;
1925    provided = elm_widget_type_get(obj);
1926    if (EINA_LIKELY(provided == type)) return EINA_TRUE;
1927    if (type) expected = type;
1928    if ((!provided) || (!provided[0]))
1929      {
1930         provided = evas_object_type_get(obj);
1931         if ((!provided) || (!provided[0]))
1932            provided = "(unknown)";
1933      }
1934    ERR("Passing Object: %p, of type: '%s' when expecting type: '%s'", obj, provided, expected);
1935    if (abort_on_warn == -1)
1936      {
1937         if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
1938         else abort_on_warn = 0;
1939      }
1940    if (abort_on_warn == 1) abort();
1941    return EINA_FALSE;
1942 }
1943
1944 /**
1945  * @internal
1946  *
1947  * Split string in words
1948  *
1949  * @param str Source string
1950  * @return List of const words
1951  *
1952  * @see elm_widget_stringlist_free()
1953  * @ingroup Widget
1954  */
1955 EAPI Eina_List *
1956 elm_widget_stringlist_get(const char *str)
1957 {
1958    Eina_List *list = NULL;
1959    const char *s, *b;
1960    if (!str) return NULL;
1961    for (b = s = str; 1; s++)
1962      {
1963         if ((*s == ' ') || (!*s))
1964           {
1965              char *t = malloc(s - b + 1);
1966              if (t)
1967                {
1968                   strncpy(t, b, s - b);
1969                   t[s - b] = 0;
1970                   list = eina_list_append(list, eina_stringshare_add(t));
1971                   free(t);
1972                }
1973              b = s + 1;
1974           }
1975         if (!*s) break;
1976      }
1977    return list;
1978 }
1979
1980 EAPI void
1981 elm_widget_stringlist_free(Eina_List *list)
1982 {
1983    const char *s;
1984    EINA_LIST_FREE(list, s) eina_stringshare_del(s);
1985 }
1986
1987 /**
1988  * @internal
1989  *
1990  * Allocate a new Elm_Widget_Item-derived structure.
1991  *
1992  * The goal of this structure is to provide common ground for actions
1993  * that a widget item have, such as the owner widget, callback to
1994  * notify deletion, data pointer and maybe more.
1995  *
1996  * @param widget the owner widget that holds this item, must be an elm_widget!
1997  * @param alloc_size any number greater than sizeof(Elm_Widget_Item) that will
1998  *        be used to allocate memory.
1999  *
2000  * @return allocated memory that is already zeroed out, or NULL on errors.
2001  *
2002  * @see elm_widget_item_new() convenience macro.
2003  * @see elm_widget_item_del() to release memory.
2004  * @ingroup Widget
2005  */
2006 EAPI Elm_Widget_Item *
2007 _elm_widget_item_new(Evas_Object *widget, size_t alloc_size)
2008 {
2009    if (!_elm_widget_is(widget))
2010      return NULL;
2011
2012    Elm_Widget_Item *item;
2013
2014    EINA_SAFETY_ON_TRUE_RETURN_VAL(alloc_size < sizeof(Elm_Widget_Item), NULL);
2015    EINA_SAFETY_ON_TRUE_RETURN_VAL(!_elm_widget_is(widget), NULL);
2016
2017    item = calloc(1, alloc_size);
2018    EINA_SAFETY_ON_NULL_RETURN_VAL(item, NULL);
2019
2020    EINA_MAGIC_SET(item, ELM_WIDGET_ITEM_MAGIC);
2021    item->widget = widget;
2022    return item;
2023 }
2024
2025 /**
2026  * @internal
2027  *
2028  * Releases widget item memory, calling back del_cb() if it exists.
2029  *
2030  * If there is a Elm_Widget_Item::del_cb, then it will be called prior
2031  * to memory release. Note that elm_widget_item_pre_notify_del() calls
2032  * this function and then unset it, thus being useful for 2 step
2033  * cleanup whenever the del_cb may use any of the data that must be
2034  * deleted from item.
2035  *
2036  * The Elm_Widget_Item::view will be deleted (evas_object_del()) if it
2037  * is presented!
2038  *
2039  * @param item a valid #Elm_Widget_Item to be deleted.
2040  * @see elm_widget_item_del() convenience macro.
2041  * @ingroup Widget
2042  */
2043 EAPI void
2044 _elm_widget_item_del(Elm_Widget_Item *item)
2045 {
2046    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2047
2048    if (item->del_cb)
2049      item->del_cb((void *)item->data, item->widget, item);
2050
2051    if (item->view)
2052      evas_object_del(item->view);
2053
2054    EINA_MAGIC_SET(item, EINA_MAGIC_NONE);
2055    free(item);
2056 }
2057
2058 /**
2059  * @internal
2060  *
2061  * Notify object will be deleted without actually deleting it.
2062  *
2063  * This function will callback Elm_Widget_Item::del_cb if it is set
2064  * and then unset it so it is not called twice (ie: from
2065  * elm_widget_item_del()).
2066  *
2067  * @param item a valid #Elm_Widget_Item to be notified
2068  * @see elm_widget_item_pre_notify_del() convenience macro.
2069  * @ingroup Widget
2070  */
2071 EAPI void
2072 _elm_widget_item_pre_notify_del(Elm_Widget_Item *item)
2073 {
2074    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2075    if (!item->del_cb) return;
2076    item->del_cb((void *)item->data, item->widget, item);
2077    item->del_cb = NULL;
2078 }
2079
2080 /**
2081  * @internal
2082  *
2083  * Set the function to notify when item is being deleted.
2084  *
2085  * This function will complain if there was a callback set already,
2086  * however it will set the new one.
2087  *
2088  * The callback will be called from elm_widget_item_pre_notify_del()
2089  * or elm_widget_item_del() will be called with:
2090  *   - data: the Elm_Widget_Item::data value.
2091  *   - obj: the Elm_Widget_Item::widget evas object.
2092  *   - event_info: the item being deleted.
2093  *
2094  * @param item a valid #Elm_Widget_Item to be notified
2095  * @see elm_widget_item_del_cb_set() convenience macro.
2096  * @ingroup Widget
2097  */
2098 EAPI void
2099 _elm_widget_item_del_cb_set(Elm_Widget_Item *item, Evas_Smart_Cb del_cb)
2100 {
2101    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2102
2103    if ((item->del_cb) && (item->del_cb != del_cb))
2104      WRN("You're replacing a previously set del_cb %p of item %p with %p",
2105          item->del_cb, item, del_cb);
2106
2107    item->del_cb = del_cb;
2108 }
2109
2110 /**
2111  * @internal
2112  *
2113  * Set user-data in this item.
2114  *
2115  * User data may be used to identify this item or just store any
2116  * application data. It is automatically given as the first parameter
2117  * of the deletion notify callback.
2118  *
2119  * @param item a valid #Elm_Widget_Item to store data in.
2120  * @param data user data to store.
2121  * @see elm_widget_item_del_cb_set() convenience macro.
2122  * @ingroup Widget
2123  */
2124 EAPI void
2125 _elm_widget_item_data_set(Elm_Widget_Item *item, const void *data)
2126 {
2127    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2128    if ((item->data) && (item->data != data))
2129      DBG("Replacing item %p data %p with %p", item, item->data, data);
2130    item->data = data;
2131 }
2132
2133 /**
2134  * @internal
2135  *
2136  * Retrieves user-data of this item.
2137  *
2138  * @param item a valid #Elm_Widget_Item to get data from.
2139  * @see elm_widget_item_data_set()
2140  * @ingroup Widget
2141  */
2142 EAPI void *
2143 _elm_widget_item_data_get(const Elm_Widget_Item *item)
2144 {
2145    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
2146    return (void *)item->data;
2147 }
2148
2149 typedef struct _Elm_Widget_Item_Tooltip Elm_Widget_Item_Tooltip;
2150
2151 struct _Elm_Widget_Item_Tooltip
2152 {
2153    Elm_Widget_Item             *item;
2154    Elm_Tooltip_Item_Content_Cb  func;
2155    Evas_Smart_Cb                del_cb;
2156    const void                  *data;
2157 };
2158
2159 static Evas_Object *
2160 _elm_widget_item_tooltip_label_create(void *data, Evas_Object *obj, void *item __UNUSED__)
2161 {
2162    Evas_Object *label = elm_label_add(obj);
2163    if (!label)
2164      return NULL;
2165    elm_object_style_set(label, "tooltip");
2166    elm_label_label_set(label, data);
2167    return label;
2168 }
2169
2170 static void
2171 _elm_widget_item_tooltip_label_del_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
2172 {
2173    eina_stringshare_del(data);
2174 }
2175
2176 /**
2177  * @internal
2178  *
2179  * Set the text to be shown in the widget item.
2180  *
2181  * @param item Target item
2182  * @param text The text to set in the content
2183  *
2184  * Setup the text as tooltip to object. The item can have only one tooltip,
2185  * so any previous tooltip data is removed.
2186  *
2187  * @ingroup Widget
2188  */
2189 EAPI void
2190 _elm_widget_item_tooltip_text_set(Elm_Widget_Item *item, const char *text)
2191 {
2192    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2193    EINA_SAFETY_ON_NULL_RETURN(text);
2194
2195    text = eina_stringshare_add(text);
2196    _elm_widget_item_tooltip_content_cb_set
2197      (item, _elm_widget_item_tooltip_label_create, text,
2198       _elm_widget_item_tooltip_label_del_cb);
2199 }
2200
2201 static Evas_Object *
2202 _elm_widget_item_tooltip_create(void *data, Evas_Object *obj)
2203 {
2204    Elm_Widget_Item_Tooltip *wit = data;
2205    return wit->func((void *)wit->data, obj, wit->item);
2206 }
2207
2208 static void
2209 _elm_widget_item_tooltip_del_cb(void *data, Evas_Object *obj, void *event_info __UNUSED__)
2210 {
2211    Elm_Widget_Item_Tooltip *wit = data;
2212    if (wit->del_cb) wit->del_cb((void *)wit->data, obj, wit->item);
2213    free(wit);
2214 }
2215
2216 /**
2217  * @internal
2218  *
2219  * Set the content to be shown in the tooltip item
2220  *
2221  * Setup the tooltip to item. The item can have only one tooltip,
2222  * so any previous tooltip data is removed. @p func(with @p data) will
2223  * be called every time that need show the tooltip and it should
2224  * return a valid Evas_Object. This object is then managed fully by
2225  * tooltip system and is deleted when the tooltip is gone.
2226  *
2227  * @param item the widget item being attached a tooltip.
2228  * @param func the function used to create the tooltip contents.
2229  * @param data what to provide to @a func as callback data/context.
2230  * @param del_cb called when data is not needed anymore, either when
2231  *        another callback replaces @func, the tooltip is unset with
2232  *        elm_widget_item_tooltip_unset() or the owner @a item
2233  *        dies. This callback receives as the first parameter the
2234  *        given @a data, and @c event_info is the item.
2235  *
2236  * @ingroup Widget
2237  */
2238 EAPI void
2239 _elm_widget_item_tooltip_content_cb_set(Elm_Widget_Item *item, Elm_Tooltip_Item_Content_Cb func, const void *data, Evas_Smart_Cb del_cb)
2240 {
2241    Elm_Widget_Item_Tooltip *wit;
2242
2243    ELM_WIDGET_ITEM_CHECK_OR_GOTO(item, error_noitem);
2244
2245    if (!func)
2246      {
2247         _elm_widget_item_tooltip_unset(item);
2248         return;
2249      }
2250
2251    wit = ELM_NEW(Elm_Widget_Item_Tooltip);
2252    if (!wit) goto error;
2253    wit->item = item;
2254    wit->func = func;
2255    wit->data = data;
2256    wit->del_cb = del_cb;
2257
2258    elm_object_sub_tooltip_content_cb_set
2259      (item->view, item->widget, _elm_widget_item_tooltip_create, wit,
2260       _elm_widget_item_tooltip_del_cb);
2261
2262    return;
2263
2264  error_noitem:
2265    if (del_cb) del_cb((void *)data, NULL, item);
2266    return;
2267  error:
2268    if (del_cb) del_cb((void *)data, item->widget, item);
2269 }
2270
2271 /**
2272  * @internal
2273  *
2274  * Unset tooltip from item
2275  *
2276  * @param item widget item to remove previously set tooltip.
2277  *
2278  * Remove tooltip from item. The callback provided as del_cb to
2279  * elm_widget_item_tooltip_content_cb_set() will be called to notify
2280  * it is not used anymore.
2281  *
2282  * @see elm_widget_item_tooltip_content_cb_set()
2283  *
2284  * @ingroup Widget
2285  */
2286 EAPI void
2287 _elm_widget_item_tooltip_unset(Elm_Widget_Item *item)
2288 {
2289    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2290    elm_object_tooltip_unset(item->view);
2291 }
2292
2293 /**
2294  * @internal
2295  *
2296  * Sets a different style for this item tooltip.
2297  *
2298  * @note before you set a style you should define a tooltip with
2299  *       elm_widget_item_tooltip_content_cb_set() or
2300  *       elm_widget_item_tooltip_text_set()
2301  *
2302  * @param item widget item with tooltip already set.
2303  * @param style the theme style to use (default, transparent, ...)
2304  *
2305  * @ingroup Widget
2306  */
2307 EAPI void
2308 _elm_widget_item_tooltip_style_set(Elm_Widget_Item *item, const char *style)
2309 {
2310    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2311    elm_object_tooltip_style_set(item->view, style);
2312 }
2313
2314 /**
2315  * @internal
2316  *
2317  * Get the style for this item tooltip.
2318  *
2319  * @param item widget item with tooltip already set.
2320  * @return style the theme style in use, defaults to "default". If the
2321  *         object does not have a tooltip set, then NULL is returned.
2322  *
2323  * @ingroup Widget
2324  */
2325 EAPI const char *
2326 _elm_widget_item_tooltip_style_get(const Elm_Widget_Item *item)
2327 {
2328    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
2329    return elm_object_tooltip_style_get(item->view);
2330 }
2331
2332 EAPI void
2333 _elm_widget_item_cursor_set(Elm_Widget_Item *item, const char *cursor)
2334 {
2335    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2336    elm_object_sub_cursor_set(item->view, item->widget, cursor);
2337 }
2338
2339 EAPI const char *
2340 _elm_widget_item_cursor_get(const Elm_Widget_Item *item)
2341 {
2342    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
2343    return elm_object_cursor_get(item->view);
2344 }
2345
2346 EAPI void
2347 _elm_widget_item_cursor_unset(Elm_Widget_Item *item)
2348 {
2349    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2350    elm_object_cursor_unset(item->view);
2351 }
2352
2353 /**
2354  * @internal
2355  *
2356  * Sets a different style for this item cursor.
2357  *
2358  * @note before you set a style you should define a cursor with
2359  *       elm_widget_item_cursor_set()
2360  *
2361  * @param item widget item with cursor already set.
2362  * @param style the theme style to use (default, transparent, ...)
2363  *
2364  * @ingroup Widget
2365  */
2366 EAPI void
2367 _elm_widget_item_cursor_style_set(Elm_Widget_Item *item, const char *style)
2368 {
2369    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2370    elm_object_cursor_style_set(item->view, style);
2371 }
2372
2373 /**
2374  * @internal
2375  *
2376  * Get the style for this item cursor.
2377  *
2378  * @param item widget item with cursor already set.
2379  * @return style the theme style in use, defaults to "default". If the
2380  *         object does not have a cursor set, then NULL is returned.
2381  *
2382  * @ingroup Widget
2383  */
2384 EAPI const char *
2385 _elm_widget_item_cursor_style_get(const Elm_Widget_Item *item)
2386 {
2387    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
2388    return elm_object_cursor_style_get(item->view);
2389 }
2390
2391 /**
2392  * @internal
2393  *
2394  * Set if the cursor set should be searched on the theme or should use
2395  * the provided by the engine, only.
2396  *
2397  * @note before you set if should look on theme you should define a cursor
2398  * with elm_object_cursor_set(). By default it will only look for cursors
2399  * provided by the engine.
2400  *
2401  * @param item widget item with cursor already set.
2402  * @param engine_only boolean to define it cursors should be looked only
2403  * between the provided by the engine or searched on widget's theme as well.
2404  *
2405  * @ingroup Widget
2406  */
2407 EAPI void
2408 _elm_widget_item_cursor_engine_only_set(Elm_Widget_Item *item, Eina_Bool engine_only)
2409 {
2410    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2411    elm_object_cursor_engine_only_set(item->view, engine_only);
2412 }
2413
2414 /**
2415  * @internal
2416  *
2417  * Get the cursor engine only usage for this item cursor.
2418  *
2419  * @param item widget item with cursor already set.
2420  * @return engine_only boolean to define it cursors should be looked only
2421  * between the provided by the engine or searched on widget's theme as well. If
2422  *         the object does not have a cursor set, then EINA_FALSE is returned.
2423  *
2424  * @ingroup Widget
2425  */
2426 EAPI Eina_Bool
2427 _elm_widget_item_cursor_engine_only_get(const Elm_Widget_Item *item)
2428 {
2429    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
2430    return elm_object_cursor_engine_only_get(item->view);
2431 }
2432
2433 // smart object funcs
2434 static void
2435 _smart_reconfigure(Smart_Data *sd)
2436 {
2437    if (sd->resize_obj)
2438      {
2439         evas_object_move(sd->resize_obj, sd->x, sd->y);
2440         evas_object_resize(sd->resize_obj, sd->w, sd->h);
2441      }
2442    if (sd->hover_obj)
2443      {
2444         evas_object_move(sd->hover_obj, sd->x, sd->y);
2445         evas_object_resize(sd->hover_obj, sd->w, sd->h);
2446      }
2447 }
2448
2449 static void
2450 _smart_add(Evas_Object *obj)
2451 {
2452    Smart_Data *sd;
2453
2454    sd = calloc(1, sizeof(Smart_Data));
2455    if (!sd) return;
2456    sd->obj = obj;
2457    sd->x = sd->y = sd->w = sd->h = 0;
2458    sd->can_focus = 1;
2459    evas_object_smart_data_set(obj, sd);
2460 }
2461
2462 static Evas_Object *
2463 _newest_focus_order_get(Evas_Object *obj, unsigned int *newest_focus_order, Eina_Bool can_focus_only)
2464 {
2465    const Eina_List *l;
2466    Evas_Object *child, *ret, *best;
2467    
2468    API_ENTRY return NULL;
2469    if (!evas_object_visible_get(obj)) return NULL;
2470    best = NULL;
2471    if (*newest_focus_order < sd->focus_order)
2472      {
2473         *newest_focus_order = sd->focus_order;
2474         best = obj;
2475      }
2476    EINA_LIST_FOREACH(sd->subobjs, l, child)
2477      {
2478         ret = _newest_focus_order_get(child, newest_focus_order, can_focus_only);
2479         if (!ret) continue;
2480         best = ret;
2481      }
2482    if ((can_focus_only) && (!elm_widget_can_focus_get(best))) return NULL;
2483    return best;
2484 }
2485
2486 static void
2487 _if_focused_revert(Evas_Object *obj, Eina_Bool can_focus_only)
2488 {
2489    Evas_Object *top;
2490    Evas_Object *newest = NULL;
2491    unsigned int newest_focus_order = 0;
2492    
2493    INTERNAL_ENTRY;
2494
2495    if (!sd->focused) return;
2496    if (!sd->parent_obj) return;
2497
2498    top = elm_widget_top_get(sd->parent_obj);
2499    if (top)
2500      {
2501         newest = _newest_focus_order_get(top, &newest_focus_order, can_focus_only);
2502         if (newest)
2503           {
2504              elm_object_unfocus(newest);
2505              elm_object_focus(newest);
2506           }
2507      }
2508 }
2509
2510 static void
2511 _smart_del(Evas_Object *obj)
2512 {
2513    Evas_Object *sobj;
2514    Edje_Signal_Data *esd;
2515
2516    INTERNAL_ENTRY;
2517
2518    if (sd->del_pre_func) sd->del_pre_func(obj);
2519    if (sd->resize_obj)
2520      {
2521         sobj = sd->resize_obj;
2522         sd->resize_obj = NULL;
2523         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
2524         evas_object_smart_callback_call(sd->obj, "sub-object-del", sobj);
2525         evas_object_del(sobj);
2526      }
2527    if (sd->hover_obj)
2528      {
2529         sobj = sd->hover_obj;
2530         sd->hover_obj = NULL;
2531         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
2532         evas_object_smart_callback_call(sd->obj, "sub-object-del", sobj);
2533         evas_object_del(sobj);
2534      }
2535    EINA_LIST_FREE(sd->subobjs, sobj)
2536      {
2537         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
2538         evas_object_smart_callback_call(sd->obj, "sub-object-del", sobj);
2539         evas_object_del(sobj);
2540      }
2541    eina_list_free(sd->tooltips); /* should be empty anyway */
2542    eina_list_free(sd->cursors); /* should be empty anyway */
2543    EINA_LIST_FREE(sd->edje_signals, esd)
2544      {
2545         eina_stringshare_del(esd->emission);
2546         eina_stringshare_del(esd->source);
2547         free(esd);
2548      }
2549    eina_list_free(sd->event_cb); /* should be empty anyway */
2550    if (sd->del_func) sd->del_func(obj);
2551    if (sd->style) eina_stringshare_del(sd->style);
2552    if (sd->type) eina_stringshare_del(sd->type);
2553    if (sd->theme) elm_theme_free(sd->theme);
2554    _if_focused_revert(obj, EINA_TRUE);
2555    free(sd);
2556 }
2557
2558 static void
2559 _smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
2560 {
2561    INTERNAL_ENTRY;
2562    sd->x = x;
2563    sd->y = y;
2564    _smart_reconfigure(sd);
2565 }
2566
2567 static void
2568 _smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
2569 {
2570    INTERNAL_ENTRY;
2571    sd->w = w;
2572    sd->h = h;
2573    _smart_reconfigure(sd);
2574 }
2575
2576 static void
2577 _smart_show(Evas_Object *obj)
2578 {
2579    Eina_List *list;
2580    Evas_Object *o;
2581    INTERNAL_ENTRY;
2582    if ((list = evas_object_smart_members_get(obj)))
2583      {
2584         EINA_LIST_FREE(list, o)
2585           {
2586              if (evas_object_data_get(o, "_elm_leaveme")) continue;
2587              evas_object_show(o);
2588           }
2589      }
2590 }
2591
2592 static void
2593 _smart_hide(Evas_Object *obj)
2594 {
2595    Eina_List *list;
2596    Evas_Object *o;
2597    INTERNAL_ENTRY;
2598    list = evas_object_smart_members_get(obj);
2599    EINA_LIST_FREE(list, o)
2600      {
2601         if (evas_object_data_get(o, "_elm_leaveme")) continue;
2602         evas_object_hide(o);
2603      }
2604    _if_focused_revert(obj, EINA_TRUE);
2605 }
2606
2607 static void
2608 _smart_color_set(Evas_Object *obj, int r, int g, int b, int a)
2609 {
2610    Eina_List *list;
2611    Evas_Object *o;
2612    INTERNAL_ENTRY;
2613    if ((list = evas_object_smart_members_get(obj)))
2614      {
2615         EINA_LIST_FREE(list, o)
2616           {
2617              if (evas_object_data_get(o, "_elm_leaveme")) continue;
2618              evas_object_color_set(o, r, g, b, a);
2619           }
2620      }
2621 }
2622
2623 static void
2624 _smart_clip_set(Evas_Object *obj, Evas_Object *clip)
2625 {
2626    Eina_List *list;
2627    Evas_Object *o;
2628    INTERNAL_ENTRY;
2629    if ((list = evas_object_smart_members_get(obj)))
2630      {
2631         EINA_LIST_FREE(list, o)
2632           {
2633              if (evas_object_data_get(o, "_elm_leaveme")) continue;
2634              evas_object_clip_set(o, clip);
2635           }
2636      }
2637 }
2638
2639 static void
2640 _smart_clip_unset(Evas_Object *obj)
2641 {
2642    Eina_List *list;
2643    Evas_Object *o;
2644    INTERNAL_ENTRY;
2645    if ((list = evas_object_smart_members_get(obj)))
2646      {
2647         EINA_LIST_FREE(list, o)
2648           {
2649              if (evas_object_data_get(o, "_elm_leaveme")) continue;
2650              evas_object_clip_unset(o);
2651           }
2652      }
2653 }
2654
2655 static void
2656 _smart_calculate(Evas_Object *obj)
2657 {
2658    INTERNAL_ENTRY;
2659    if (sd->changed_func) sd->changed_func(obj);
2660 }
2661
2662 /* never need to touch this */
2663 static void
2664 _smart_init(void)
2665 {
2666    if (_e_smart) return;
2667      {
2668         static const Evas_Smart_Class sc =
2669           {
2670              SMART_NAME,
2671              EVAS_SMART_CLASS_VERSION,
2672              _smart_add,
2673              _smart_del,
2674              _smart_move,
2675              _smart_resize,
2676              _smart_show,
2677              _smart_hide,
2678              _smart_color_set,
2679              _smart_clip_set,
2680              _smart_clip_unset,
2681              _smart_calculate,
2682              NULL,
2683              NULL,
2684              NULL,
2685              NULL,
2686              NULL,
2687              NULL
2688           };
2689         _e_smart = evas_smart_class_new(&sc);
2690      }
2691 }
2692
2693 /* happy debug functions */
2694 #ifdef ELM_DEBUG
2695 static void
2696 _sub_obj_tree_dump(const Evas_Object *o, int lvl)
2697 {
2698    int i;
2699
2700    for (i = 0; i < lvl*3; i++)
2701      putchar(' ');
2702
2703    if (_elm_widget_is(o))
2704      {
2705         Eina_List *l;
2706         Smart_Data *sd = evas_object_smart_data_get(o);
2707         printf("+ %s(%p)\n", sd->type, o);
2708         if (sd->resize_obj)
2709           _sub_obj_tree_dump(sd->resize_obj, lvl + 1);
2710         EINA_LIST_FOREACH(sd->subobjs, l, o)
2711           {
2712              if (o != sd->resize_obj)
2713                _sub_obj_tree_dump(o, lvl + 1);
2714           }
2715      }
2716    else
2717      printf("+ %s(%p)\n", evas_object_type_get(o), o);
2718 }
2719
2720 static void
2721 _sub_obj_tree_dot_dump(const Evas_Object *obj, FILE *output)
2722 {
2723    if (!_elm_widget_is(obj))
2724      return;
2725
2726    Smart_Data *sd = evas_object_smart_data_get(obj);
2727
2728    Eina_Bool visible = evas_object_visible_get(obj);
2729    Eina_Bool disabled = elm_widget_disabled_get(obj);
2730    Eina_Bool focused = elm_widget_focus_get(obj);
2731    Eina_Bool can_focus = elm_widget_can_focus_get(obj);
2732
2733    if (sd->parent_obj)
2734      {
2735         fprintf(output, "\"%p\" -- \"%p\" [ color=black", sd->parent_obj, obj);
2736
2737         if (focused)
2738           fprintf(output, ", style=bold");
2739
2740         if (!visible)
2741           fprintf(output, ", color=gray28");
2742
2743         fprintf(output, " ];\n");
2744      }
2745
2746    fprintf(output, "\"%p\" [ label = \"{%p|%s|%s|visible: %d|"
2747            "disabled: %d|focused: %d/%d|focus order:%d}\"", obj, obj, sd->type,
2748            evas_object_name_get(obj), visible, disabled, focused, can_focus,
2749            sd->focus_order);
2750
2751    if (focused)
2752         fprintf(output, ", style=bold");
2753
2754    if (!visible)
2755         fprintf(output, ", fontcolor=gray28");
2756
2757    if ((disabled) || (!visible))
2758         fprintf(output, ", color=gray");
2759
2760
2761    fprintf(output, " ];\n");
2762
2763    Eina_List *l;
2764    Evas_Object *o;
2765    EINA_LIST_FOREACH(sd->subobjs, l, o)
2766       _sub_obj_tree_dot_dump(o, output);
2767 }
2768 #endif
2769
2770 EAPI void
2771 elm_widget_tree_dump(const Evas_Object *top)
2772 {
2773 #ifdef ELM_DEBUG
2774    _sub_obj_tree_dump(top, 0);
2775 #else
2776    return;
2777    (void)top;
2778 #endif
2779 }
2780
2781 EAPI void
2782 elm_widget_tree_dot_dump(const Evas_Object *top, FILE *output)
2783 {
2784 #ifdef ELM_DEBUG
2785    if (!_elm_widget_is(top))
2786      return;
2787    fprintf(output, "graph "" { node [shape=record];\n");
2788    _sub_obj_tree_dot_dump(top, output);
2789    fprintf(output, "}\n");
2790 #else
2791    return;
2792    (void)top;
2793    (void)output;
2794 #endif
2795 }