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