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