Merge "custom eail widget implementation" into tizen
[platform/core/uifw/eail.git] / eail / eail_window.c
1 /*
2  * Copyright (c) 2013 Samsung Electronics Co., Ltd.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 /**
21  * @file eail_window.c
22  * @brief EailWindow Implementation
23  */
24
25 #include <Elementary.h>
26 #include "eail_window.h"
27 #include "eail_factory.h"
28 #include "eail_utils.h"
29 #include "eail_dynamic_content.h"
30 #include "eail_priv.h"
31
32 static void eail_window_actions_init(EailActionWidget *widget);
33 static void atk_window_interface_init (AtkWindowIface *iface);
34 static void atk_component_interface_init(AtkComponentIface *iface);
35 static void eail_dynamic_content_interface_init(EailDynamicContentIface *iface);
36
37 /**
38  * @brief Focus signal name
39  */
40 #define EAIL_WINDOW_FOCUS_NAME "focus,in"
41
42 #define EAIL_WIN_ACTION_MAXIMIZE "maximize" /**< 'maximize' action name */
43 #define EAIL_WIN_ACTION_MINIMIZE "minimize" /**< 'minimize' action name */
44 #define EAIL_WIN_ACTION_RESTORE "restore" /**< 'restore' action name */
45
46 /**
47  * @brief EailWindow type definition
48  */
49 G_DEFINE_TYPE_WITH_CODE(EailWindow,
50                         eail_window,
51                         EAIL_TYPE_ACTION_WIDGET,
52                         G_IMPLEMENT_INTERFACE(ATK_TYPE_WINDOW,
53                                               atk_window_interface_init)
54                         G_IMPLEMENT_INTERFACE(ATK_TYPE_COMPONENT,
55                                             atk_component_interface_init)
56                         G_IMPLEMENT_INTERFACE(EAIL_TYPE_DYNAMIC_CONTENT,
57                                           eail_dynamic_content_interface_init));
58
59 /**
60  * @brief Maximizes event handler
61  *
62  * @param data data passed to callback
63  * @param obj Evas_Object instance that raised event
64  * @param event_info additional event info
65  */
66 void
67 _eail_window_handle_maximize_event(void *data,
68                                    Evas_Object *obj,
69                                    void *event_info)
70 {
71    eail_emit_atk_signal(ATK_OBJECT(data), "maximize", EAIL_TYPE_WINDOW);
72 }
73
74 /**
75  * @brief Minimizes event handler
76  *
77  * @param data data passed to callback
78  * @param obj Evas_Object instance that raised event
79  * @param event_info additional event info
80  */
81 void
82 _eail_window_handle_minimize_event(void *data,
83                                    Evas_Object *obj,
84                                    void *event_info)
85 {
86    eail_emit_atk_signal(ATK_OBJECT(data), "minimize", EAIL_TYPE_WINDOW);
87 }
88
89 /**
90  * @brief Moves event handler
91  *
92  * @param data data passed to callback
93  * @param obj Evas_Object instance that raised event
94  * @param event_info additional event info
95  */
96 void
97 eail_window_on_move(void *data, Evas *e, Evas_Object *obj, void *event_info)
98 {
99    g_return_if_fail(ATK_IS_OBJECT(data));
100
101    eail_emit_atk_signal(ATK_OBJECT(data), "move", EAIL_TYPE_WINDOW);
102 }
103
104 /**
105  * @brief Deactivate event handler
106  *
107  * @param data data passed to callback
108  * @param obj Evas_Object instance that raised event
109  * @param event_info additional event info
110  */
111 void
112 eail_window_on_deactivate(void *data, Evas *e, Evas_Object *obj, void *event_info)
113 {
114    g_return_if_fail(ATK_IS_OBJECT(data));
115
116    eail_emit_atk_signal(ATK_OBJECT(data), "deactivate", EAIL_TYPE_WINDOW);
117 }
118
119 /**
120  * @brief Activate event handler
121  *
122  * @param data data passed to callback
123  * @param obj Evas_Object instance that raised event
124  * @param event_info additional event info
125  */
126 void
127 eail_window_on_activate(void *data, Evas *e, Evas_Object *obj, void *event_info)
128 {
129    g_return_if_fail(ATK_IS_OBJECT(data));
130
131    eail_emit_atk_signal(ATK_OBJECT(data), "activate", EAIL_TYPE_WINDOW);
132 }
133
134
135
136 /**
137  * @brief Callback used for tracking resize-changes for window
138  *
139  * @param data data passed to callback
140  * @param e Evas instance that has been shown
141  * @param obj Evas_Object instance that has been shown
142  * @param event_info additional event info
143  */
144 void
145 eail_window_on_resize(void *data, Evas *e, Evas_Object *obj, void *event_info)
146 {
147    g_return_if_fail(ATK_IS_OBJECT(data));
148
149    eail_emit_atk_signal(ATK_OBJECT(data), "resize", EAIL_TYPE_WINDOW);
150 }
151
152 /**
153  * @brief Destroyed event handler for window
154  *
155  * @param data passed to callback
156  * @param obj object that raised event
157  * @param event_info additional event info
158  */
159 void
160 _eail_window_handle_delete_event(void *data, Evas *e, Evas_Object *obj, void *event_info)
161 {
162    atk_object_notify_state_change(ATK_OBJECT(data), ATK_STATE_DEFUNCT, TRUE);
163    eail_emit_atk_signal(ATK_OBJECT(data), "destroy", EAIL_TYPE_WINDOW);
164    eail_factory_unregister_wdgt_from_cache(obj);
165 }
166
167 /**
168  * @brief Restore event handler
169  *
170  * @param data passed to callback
171  * @param obj object that raised event
172  * @param event_info additional event info
173  */
174 void
175 _eail_window_handle_restore_event(void *data,
176                                    Evas_Object *obj,
177                                    void *event_info)
178 {
179    eail_emit_atk_signal(ATK_OBJECT(data), "restore", EAIL_TYPE_WINDOW);
180 }
181
182 /**
183  * @brief Create event handler
184  *
185  * @param data passed to callback
186  * @param obj object that raised event
187  * @param event_info additional event info
188  */
189 void
190 _eail_window_handle_create_event(void *data, Evas *e, Evas_Object *obj, void *event_info)
191 {
192    eail_emit_atk_signal(ATK_OBJECT(data), "create", EAIL_TYPE_WINDOW);
193 }
194
195 /**
196  * @brief Initializes window focus handler
197  *
198  * @param obj AtkObject instance
199  */
200 static void
201 eail_window_init_focus_handler(AtkObject *obj)
202 {
203    Evas_Object *nested_widget = NULL;
204    g_return_if_fail(EAIL_IS_WIDGET(obj));
205
206    nested_widget = eail_widget_get_widget(EAIL_WIDGET(obj));
207    if (!nested_widget)
208      {
209         ERR("No evas object inside EailWidget was found");
210         return;
211      }
212
213    evas_object_smart_callback_add(nested_widget, "maximized",
214                                   _eail_window_handle_maximize_event, obj);
215    evas_object_smart_callback_add(nested_widget, "iconified",
216                                   _eail_window_handle_minimize_event, obj);
217    evas_object_smart_callback_add(nested_widget, "unmaximized",
218                                   _eail_window_handle_restore_event, obj);
219    evas_object_smart_callback_add(nested_widget, "normal",
220                                   _eail_window_handle_restore_event, obj);
221
222    /* evas object events (not smart callbacks) */
223    evas_object_event_callback_add(nested_widget, EVAS_CALLBACK_RESIZE,
224                                   eail_window_on_resize, obj);
225    evas_object_event_callback_add(nested_widget, EVAS_CALLBACK_MOVE,
226                                   eail_window_on_move, obj);
227    evas_object_event_callback_add(nested_widget, EVAS_CALLBACK_FOCUS_OUT,
228                                   eail_window_on_deactivate, obj);
229    evas_object_event_callback_add(nested_widget, EVAS_CALLBACK_FOCUS_IN,
230                                   eail_window_on_activate, obj);
231    evas_object_event_callback_add(nested_widget, EVAS_CALLBACK_DEL,
232                                   _eail_window_handle_delete_event, obj);
233    evas_object_event_callback_add(nested_widget, EVAS_CALLBACK_SHOW,
234                                   _eail_window_handle_create_event, obj);
235 }
236
237 /**
238  * @brief EailWindow initializer
239  *
240  * @param obj AtkObject instance
241  * @param data initialization data
242  */
243 static void
244 eail_window_initialize(AtkObject *obj, gpointer data)
245 {
246    EailWindow *eail_win = NULL;
247    ATK_OBJECT_CLASS(eail_window_parent_class)->initialize(obj, data);
248    EAIL_WIDGET(obj)->layer = ATK_LAYER_WINDOW;
249
250    if (!elm_object_widget_check((Evas_Object *) data)) return;
251
252    obj->name = g_strdup(elm_win_title_get((Evas_Object *)data));
253    obj->role = ATK_ROLE_WINDOW;
254    obj->accessible_parent = atk_get_root();
255
256    eail_window_init_focus_handler(obj);
257    eail_window_actions_init(EAIL_ACTION_WIDGET(obj));
258
259    eail_win = EAIL_WINDOW(obj);
260    /* storing last numbers of children to be for checking if children-changed
261     * signal has to be propagated */
262    eail_win->child_count_last = atk_object_get_n_accessible_children(obj);
263 }
264
265 /**
266  * @brief Gets the children list from given edje
267  *
268  * @param edje lowest (stacked) Evas object
269  * @return Eina_List representing the children list
270  */
271 static Eina_List *
272 _parse_edje(const Evas_Object *edje)
273 {
274    const Evas_Object *content_part = NULL;
275    const Evas_Object *menu_part = NULL;
276    Eina_List *list = NULL;
277
278    if (edje_object_part_exists(edje, "elm.swallow.menu"))
279      menu_part = edje_object_part_swallow_get(edje, "elm.swallow.menu");
280    if (edje_object_part_exists(edje, "elm.swallow.contents"))
281      content_part = edje_object_part_swallow_get(edje, "elm.swallow.contents");
282    if ((menu_part) &&
283        (!strcmp(evas_object_type_get(menu_part), "Evas_Object_Box")))
284         list = evas_object_box_children_get(menu_part);
285    if ((content_part) &&
286        (!strcmp(evas_object_type_get(content_part), "Evas_Object_Box")))
287      {
288         if (list)
289           list = eina_list_merge(list,
290                                  evas_object_box_children_get(content_part));
291         else
292           list = evas_object_box_children_get(content_part);
293      }
294
295    return list;
296 }
297
298 /**
299  * @brief Gets widget's children
300  *
301  * @param widget EailWidget instance
302  * @return Eina_List representing the list of widget's children
303  */
304 static Eina_List *
305 eail_window_get_widget_children(EailWidget *widget)
306 {
307    Evas_Object *o, *obj = eail_widget_get_widget(widget);
308    Eina_List *win_childs = NULL;
309    Eina_List *widgets = NULL;
310    Evas *e;
311    Eina_List *l;
312    Evas_Object *item;
313
314    /*in elementary >= 1.7.99 we get edje object if object are stacked
315      in containers like box, grid etc we need to get children from this
316      edje*/
317
318    e = evas_object_evas_get(obj);
319    o = evas_object_bottom_get(e);
320    if (!g_strcmp0(evas_object_type_get(o), "edje"))
321      {
322         widgets = _parse_edje(o);
323         EINA_LIST_FOREACH(widgets, l, item)
324           {
325              if(!elm_object_widget_check(item))
326                widgets = eina_list_remove(widgets, item);
327           }
328      }
329    /* Sometimes we have a mix of widgets grouped in containters with
330     * those directly on elm_win objct. So list evas objects laying on
331     * window to be sure we get everything */
332    o = obj;
333    while ((o = evas_object_below_get(o)))
334      {
335         if (elm_object_widget_check(o))
336           {
337              /*be sure that object belongs to window and not to other
338               * container*/
339              if (obj == elm_object_parent_widget_get(o))
340                win_childs = eina_list_append(win_childs, o);
341           }
342      }
343
344    if (win_childs)
345      {
346         /*reverse list to get correct order of widgets tree*/
347         win_childs = eina_list_reverse(win_childs);
348         /*merge window childs together with containers*/
349         if (widgets)
350           widgets = eina_list_merge(widgets, win_childs);
351         else
352           widgets = win_childs;
353      }
354
355    return widgets;
356 }
357
358 /**
359  * @brief Gets the state set of the accessible
360  *
361  * @param obj AtkObject instance
362  * @return AtkStateSet representing the state set of the accessible
363  */
364 static AtkStateSet *
365 eail_window_ref_state_set(AtkObject *obj)
366 {
367    double x, y;
368    AtkStateSet *state_set;
369    Eina_List *l, *children;
370    Eina_Bool resizable = EINA_TRUE;
371    Evas_Object *child, *widget = eail_widget_get_widget(EAIL_WIDGET(obj));
372
373    if (!widget) return NULL;
374
375    state_set= ATK_OBJECT_CLASS(eail_window_parent_class)->ref_state_set(obj);
376
377    if (elm_win_focus_get(widget))
378      {
379         atk_state_set_add_state(state_set, ATK_STATE_ACTIVE);
380      }
381
382    if (elm_win_iconified_get(widget))
383      {
384         atk_state_set_add_state(state_set, ATK_STATE_ICONIFIED);
385      }
386
387    if (elm_win_modal_get(widget))
388      {
389         atk_state_set_add_state(state_set, ATK_STATE_MODAL);
390      }
391
392    children = eail_widget_get_widget_children(EAIL_WIDGET(obj));
393    EINA_LIST_FOREACH(children, l, child)
394      {
395         evas_object_size_hint_weight_get(child, &x, &y);
396         if (!float_equal(x, EVAS_HINT_EXPAND) || !float_equal(y, EVAS_HINT_EXPAND))
397           {
398              resizable = EINA_FALSE;
399              break;
400           }
401      }
402    eina_list_free(children);
403
404    if (resizable)
405      {
406         atk_state_set_add_state(state_set, ATK_STATE_RESIZABLE);
407      }
408
409    return state_set;
410 }
411
412 /**
413  * @brief Get the index in parent of the accessible
414  *
415  * @param obj AtkObject instance
416  * @return Integer representing the index of the object in parent
417  */
418 static int
419 eail_window_get_index_in_parent(AtkObject *obj)
420 {
421     AtkObject *parent = atk_object_get_parent(obj);
422
423     if(atk_object_get_n_accessible_children(parent) == 1)
424       {
425         return 0;
426       }
427     else
428       {
429         int i;
430         for(i = 0; i < atk_object_get_n_accessible_children(parent); i++)
431           {
432             AtkObject *child = atk_object_ref_accessible_child(parent, i);
433             if(child == obj)
434               {
435                 g_object_unref(child);
436                 return i;
437               }
438             g_object_unref(child);
439           }
440       }
441
442     return -1;
443 }
444
445 /**
446  * @brief EailWindow instance initializer
447  *
448  * @param window EailWindow instance
449  */
450 static void
451 eail_window_init(EailWindow *window)
452 {
453 }
454
455 /**
456  * @brief EailWindow class initializer
457  *
458  * @param klass EailWindowClass instance
459  */
460 static void
461 eail_window_class_init(EailWindowClass *klass)
462 {
463    AtkObjectClass *atk_class = ATK_OBJECT_CLASS(klass);
464    EailWidgetClass *widget_class = EAIL_WIDGET_CLASS(klass);
465
466    widget_class->get_widget_children = eail_window_get_widget_children;
467
468    atk_class->initialize = eail_window_initialize;
469    atk_class->ref_state_set = eail_window_ref_state_set;
470    atk_class->get_index_in_parent = eail_window_get_index_in_parent;
471 }
472
473 /**
474  * @brief Handle for minimize action
475  *
476  * @param action AtkAction instance
477  * @param data additional action data (not used here)
478  *
479  * @return TRUE if action was triggered successfully, FALSE otherwise
480  */
481 static gboolean
482 eail_action_minimize(AtkAction *action, void *data)
483 {
484    Evas_Object *widget;
485    AtkObject *obj;
486
487    g_return_val_if_fail(EAIL_IS_WINDOW(action), FALSE);
488
489    widget = eail_widget_get_widget(EAIL_WIDGET(action));
490
491    elm_win_iconified_set(widget, EINA_TRUE);
492
493    obj = ATK_OBJECT(action);
494
495    eail_emit_atk_signal(obj, "minimize", EAIL_TYPE_WINDOW);
496
497    return TRUE;
498 }
499
500 /**
501  * @brief Handle for maximize action
502  *
503  * @param action AtkAction instance
504  * @param data additional action data (not used here)
505  *
506  * @return TRUE if action was triggered successfully, FALSE otherwise
507  */
508 static gboolean
509 eail_action_maximize(AtkAction *action, void *data)
510 {
511    Evas_Object *widget;
512    AtkObject *obj;
513
514    g_return_val_if_fail(EAIL_IS_WINDOW(action), FALSE);
515
516    widget = eail_widget_get_widget(EAIL_WIDGET(action));
517
518    elm_win_maximized_set(widget, EINA_TRUE);
519
520    obj = ATK_OBJECT(action);
521
522    eail_emit_atk_signal(obj, "maximize", EAIL_TYPE_WINDOW);
523    return TRUE;
524 }
525
526 /**
527  * @brief Handle for action restore
528  *
529  * @param action an AtkAction
530  * @param data additional action data (not used here)
531  *
532  * @return TRUE if action was triggered successfully, FALSE otherwise
533  */
534 static gboolean
535 eail_action_restore(AtkAction *action, void *data)
536 {
537    Evas_Object *widget;
538    AtkObject *obj;
539
540    g_return_val_if_fail(EAIL_IS_WINDOW(action), FALSE);
541
542    widget = eail_widget_get_widget(EAIL_WIDGET(action));
543
544    if(elm_win_maximized_get(widget))
545      {
546         elm_win_maximized_set(widget, EINA_FALSE);
547      }
548
549    if(elm_win_iconified_get(widget))
550      {
551         elm_win_activate(widget);
552      }
553
554    obj = ATK_OBJECT(action);
555
556    eail_emit_atk_signal(obj, "restore", EAIL_TYPE_WINDOW);
557    return TRUE;
558 }
559
560 /**
561  * @brief Adds window actions to the actions table
562  *
563  * @param action_widget widget that implements EailActionWidget interface
564  */
565 static void
566 eail_window_actions_init(EailActionWidget *action_widget)
567 {
568    eail_action_widget_action_append(action_widget,
569                                     EAIL_WIN_ACTION_MAXIMIZE, NULL,
570                                     eail_action_maximize);
571    eail_action_widget_action_append(action_widget,
572                                     EAIL_WIN_ACTION_MINIMIZE, NULL,
573                                     eail_action_minimize);
574    eail_action_widget_action_append(action_widget,
575                                     EAIL_WIN_ACTION_RESTORE, NULL,
576                                     eail_action_restore);
577 }
578
579 /**
580  * @brief AtkWindow interface initializer
581  *
582  * It is empty because at the moment
583  * AtkWindow is just about signals
584  *
585  * @param iface AtkWindowIface instance
586  */
587 static void
588 atk_window_interface_init(AtkWindowIface *iface)
589 {
590 }
591
592 /**
593  * @brief Returns the first found widget from EvasObjectBox
594  *
595  * @param evas_obj EvasObjectBox instance to search in
596  *
597  * @returns Evas_Object that represents the found widget
598  * or NULL if none has been found
599  */
600 static Evas_Object*
601 _eail_get_first_widget_from_evas_box(Evas_Object *evas_obj)
602 {
603    Eina_List *children = NULL, *l;
604    Evas_Object *it_evas_obj = NULL;
605
606    children = evas_object_box_children_get(evas_obj);
607
608    EINA_LIST_FOREACH(children, l, it_evas_obj)
609      {
610       if (elm_object_widget_check (it_evas_obj))
611          {
612             DBG("Widget has been found %s", evas_object_type_get(it_evas_obj));
613             return it_evas_obj;
614          }
615      }
616
617    return NULL;
618 }
619
620 /**
621  * @brief Returns the first found widget from given edje object
622  *
623  * @param evas_obj edje object to search in
624  *
625  * @returns Evas_Object that represents the found widget
626  * or NULL if none has been found
627  */
628 static Evas_Object *
629 _eail_get_first_widget_from_edje(Evas_Object *evas_obj)
630 {
631    Eina_List *members = NULL, *l;
632    Evas_Object *it_evas_obj = NULL;
633
634    members = evas_object_smart_members_get(evas_obj);
635    EINA_LIST_FOREACH(members, l, it_evas_obj)
636    {
637       const char *type_name = evas_object_type_get(it_evas_obj);
638
639       /* if widget found, then returning immediately. If not widget, then
640        * looking for nested box*/
641       if (elm_object_widget_check (it_evas_obj))
642         return it_evas_obj;
643       else if (0 == g_strcmp0(type_name, "Evas_Object_Box") )
644         {
645             Evas_Object *widget_from_box = _eail_get_first_widget_from_evas_box(it_evas_obj);
646             if (widget_from_box)
647               return widget_from_box;
648         }
649    }
650
651    return NULL;
652 }
653
654 /**
655  * @brief Gets a reference to the accessible child, if one exists, at the
656  * coordinate point specified by x and y
657  *
658  * @param component AtkComponent instance
659  * @param x x coordinate
660  * @param y y coordinate
661  * @param coord_type specifies whether the coordinates are relative to the
662  * screen or to the components top level window
663  *
664  * @returns AtkObject representing the accessible child, if one exists
665  */
666 static AtkObject *
667 eail_window_ref_accessible_at_point(AtkComponent *component,
668                                     gint x,
669                                     gint y,
670                                     AtkCoordType coord_type)
671 {
672    Evas_Object *widget = NULL, *evas_obj_at_coords = NULL;
673    Evas *wdgt_evas = NULL;
674    const char * found_obj_type = NULL;
675
676    widget = eail_widget_get_widget(EAIL_WIDGET(component));
677
678    if (!widget) return NULL;
679
680    if (coord_type == ATK_XY_SCREEN) {
681            int ee_x, ee_y;
682            Ecore_Evas *ee= ecore_evas_ecore_evas_get(evas_object_evas_get(widget));
683
684            ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
685            x -= ee_x;
686            y -= ee_y;
687        }
688
689    /* NOTE: it is crucial to get object from evas, NOT Evas_Object*/
690    wdgt_evas = evas_object_evas_get(widget);
691
692    evas_obj_at_coords = evas_object_top_at_xy_get
693                               (wdgt_evas, x, y, EINA_FALSE, EINA_FALSE);
694    if (!evas_obj_at_coords)
695      {
696        DBG("Not found any object at coords %d,%d", x, y);
697        return NULL;
698      }
699
700    /* if edje object, then we have to parse that and extract widget from it*/
701    found_obj_type = evas_object_type_get(evas_obj_at_coords);
702    if (0 == g_strcmp0(found_obj_type, "edje"))
703      {
704          DBG("Edje object found...");
705          evas_obj_at_coords = _eail_get_first_widget_from_edje(evas_obj_at_coords);
706      }
707
708    return eail_factory_get_accessible(evas_obj_at_coords);
709 }
710
711 /**
712  * @brief AtkComponent interface initialization
713  *
714  * Initialization for ref_accessible_at_point callback used by clients to
715  * reference object at given coordinates. Rest of implementation is default
716  * so no overriding-callbacks is needed.
717  *
718  * @param iface EailWindow instance
719  */
720 static void
721 atk_component_interface_init(AtkComponentIface *iface)
722 {
723    iface->ref_accessible_at_point = eail_window_ref_accessible_at_point;
724 }
725
726 /**
727  * @param dynamic_content_holder an EailDynamicContent object (EailWindow)
728  */
729 void
730 eail_window_update_descendants(EailDynamicContent *dynamic_content_holder)
731 {
732    gint n_children = 0;
733    EailWindow *window = NULL;
734
735    if (!EAIL_IS_WINDOW(dynamic_content_holder))
736      {
737         DBG("No EailWindow found. Returning");
738         return;
739      }
740
741    window = EAIL_WINDOW(dynamic_content_holder);
742
743    n_children = atk_object_get_n_accessible_children(ATK_OBJECT(window));
744    if (n_children && n_children > window->child_count_last)
745      {
746         eail_emit_children_changed(TRUE, ATK_OBJECT(window), n_children - 1);
747
748      }
749    else if (n_children < window->child_count_last)
750      {
751          eail_emit_children_changed
752                      (FALSE, ATK_OBJECT(window), window->child_count_last);
753      }
754
755    window->child_count_last = n_children;
756 }
757
758 /**
759  * @brief Initializer for dynamic content interface, used for handling objects
760  * children hierarchy changes
761  *
762  * @param iface an EailDynamicContentIface
763  */
764 static void
765 eail_dynamic_content_interface_init(EailDynamicContentIface *iface)
766 {
767    iface->update_hierarchy = eail_window_update_descendants;
768 }