2 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
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.
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.
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.
22 * @brief EailWindow Implementation
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"
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);
38 * @brief Focus signal name
40 #define EAIL_WINDOW_FOCUS_NAME "focus,in"
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 */
47 * @brief EailWindow type definition
49 G_DEFINE_TYPE_WITH_CODE(EailWindow,
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));
60 * @brief Maximizes event handler
62 * @param data data passed to callback
63 * @param obj Evas_Object instance that raised event
64 * @param event_info additional event info
67 _eail_window_handle_maximize_event(void *data,
71 eail_emit_atk_signal(ATK_OBJECT(data), "maximize", EAIL_TYPE_WINDOW);
75 * @brief Minimizes event handler
77 * @param data data passed to callback
78 * @param obj Evas_Object instance that raised event
79 * @param event_info additional event info
82 _eail_window_handle_minimize_event(void *data,
86 eail_emit_atk_signal(ATK_OBJECT(data), "minimize", EAIL_TYPE_WINDOW);
90 * @brief Moves event handler
92 * @param data data passed to callback
93 * @param obj Evas_Object instance that raised event
94 * @param event_info additional event info
97 eail_window_on_move(void *data, Evas *e, Evas_Object *obj, void *event_info)
99 g_return_if_fail(ATK_IS_OBJECT(data));
101 eail_emit_atk_signal(ATK_OBJECT(data), "move", EAIL_TYPE_WINDOW);
105 * @brief Callback used for tracking resize-changes for window
107 * @param data data passed to callback
108 * @param e Evas instance that has been shown
109 * @param obj Evas_Object instance that has been shown
110 * @param event_info additional event info
113 eail_window_on_resize(void *data, Evas *e, Evas_Object *obj, void *event_info)
115 g_return_if_fail(ATK_IS_OBJECT(data));
117 eail_emit_atk_signal(ATK_OBJECT(data), "resize", EAIL_TYPE_WINDOW);
121 * @brief Destroyed event handler for window
123 * @param data passed to callback
124 * @param obj object that raised event
125 * @param event_info additional event info
128 _eail_window_handle_delete_event(void *data,
132 atk_object_notify_state_change(ATK_OBJECT(data), ATK_STATE_DEFUNCT, TRUE);
133 eail_emit_atk_signal(ATK_OBJECT(data), "destroy", EAIL_TYPE_WINDOW);
134 eail_factory_unregister_wdgt_from_cache(obj);
138 * @brief Restore event handler
140 * @param data passed to callback
141 * @param obj object that raised event
142 * @param event_info additional event info
145 _eail_window_handle_restore_event(void *data,
149 eail_emit_atk_signal(ATK_OBJECT(data), "restore", EAIL_TYPE_WINDOW);
153 * @brief Initializes window focus handler
155 * @param obj AtkObject instance
158 eail_window_init_focus_handler(AtkObject *obj)
160 Evas_Object *nested_widget = NULL;
161 g_return_if_fail(EAIL_IS_WIDGET(obj));
163 nested_widget = eail_widget_get_widget(EAIL_WIDGET(obj));
166 ERR("No evas object inside EailWidget was found");
170 evas_object_smart_callback_add(nested_widget, "maximized",
171 _eail_window_handle_maximize_event, obj);
172 evas_object_smart_callback_add(nested_widget, "iconified",
173 _eail_window_handle_minimize_event, obj);
174 evas_object_smart_callback_add(nested_widget, "delete,request",
175 _eail_window_handle_delete_event, obj);
176 evas_object_smart_callback_add(nested_widget, "unmaximized",
177 _eail_window_handle_restore_event, obj);
178 evas_object_smart_callback_add(nested_widget, "normal",
179 _eail_window_handle_restore_event, obj);
181 /* evas object events (not smart callbacks) */
182 evas_object_event_callback_add(nested_widget, EVAS_CALLBACK_RESIZE,
183 eail_window_on_resize, obj);
184 evas_object_event_callback_add(nested_widget, EVAS_CALLBACK_MOVE,
185 eail_window_on_move, obj);
189 * @brief EailWindow initializer
191 * @param obj AtkObject instance
192 * @param data initialization data
195 eail_window_initialize(AtkObject *obj, gpointer data)
197 EailWindow *eail_win = NULL;
198 ATK_OBJECT_CLASS(eail_window_parent_class)->initialize(obj, data);
199 EAIL_WIDGET(obj)->layer = ATK_LAYER_WINDOW;
201 if (!elm_object_widget_check((Evas_Object *) data)) return;
203 obj->name = g_strdup(elm_win_title_get((Evas_Object *)data));
204 obj->role = ATK_ROLE_WINDOW;
205 obj->accessible_parent = atk_get_root();
207 eail_window_init_focus_handler(obj);
208 eail_window_actions_init(EAIL_ACTION_WIDGET(obj));
210 eail_win = EAIL_WINDOW(obj);
211 /* storing last numbers of children to be for checking if children-changed
212 * signal has to be propagated */
213 eail_win->child_count_last = atk_object_get_n_accessible_children(obj);
217 * @brief Gets the children list from given edje
219 * @param edje lowest (stacked) Evas object
220 * @return Eina_List representing the children list
223 _parse_edje(const Evas_Object *edje)
225 const Evas_Object *content_part = NULL;
226 const Evas_Object *menu_part = NULL;
227 Eina_List *list = NULL;
229 if (edje_object_part_exists(edje, "elm.swallow.menu"))
230 menu_part = edje_object_part_swallow_get(edje, "elm.swallow.menu");
231 if (edje_object_part_exists(edje, "elm.swallow.contents"))
232 content_part = edje_object_part_swallow_get(edje, "elm.swallow.contents");
234 (!strcmp(evas_object_type_get(menu_part), "Evas_Object_Box")))
235 list = evas_object_box_children_get(menu_part);
236 if ((content_part) &&
237 (!strcmp(evas_object_type_get(content_part), "Evas_Object_Box")))
240 list = eina_list_merge(list,
241 evas_object_box_children_get(content_part));
243 list = evas_object_box_children_get(content_part);
250 * @brief Gets widget's children
252 * @param widget EailWidget instance
253 * @return Eina_List representing the list of widget's children
256 eail_window_get_widget_children(EailWidget *widget)
258 Evas_Object *o, *obj = eail_widget_get_widget(widget);
259 Eina_List *win_childs = NULL;
260 Eina_List *widgets = NULL;
265 /*in elementary >= 1.7.99 we get edje object if object are stacked
266 in containers like box, grid etc we need to get children from this
269 e = evas_object_evas_get(obj);
270 o = evas_object_bottom_get(e);
271 if (!g_strcmp0(evas_object_type_get(o), "edje"))
273 widgets = _parse_edje(o);
274 EINA_LIST_FOREACH(widgets, l, item)
276 if(!elm_object_widget_check(item))
277 widgets = eina_list_remove(widgets, item);
280 /* Sometimes we have a mix of widgets grouped in containters with
281 * those directly on elm_win objct. So list evas objects laying on
282 * window to be sure we get everything */
284 while ((o = evas_object_below_get(o)))
286 if (elm_object_widget_check(o))
288 /*be sure that object belongs to window and not to other
290 if (obj == elm_object_parent_widget_get(o))
291 win_childs = eina_list_append(win_childs, o);
297 /*reverse list to get correct order of widgets tree*/
298 win_childs = eina_list_reverse(win_childs);
299 /*merge window childs together with containers*/
301 widgets = eina_list_merge(widgets, win_childs);
303 widgets = win_childs;
310 * @brief Gets the state set of the accessible
312 * @param obj AtkObject instance
313 * @return AtkStateSet representing the state set of the accessible
316 eail_window_ref_state_set(AtkObject *obj)
319 AtkStateSet *state_set;
320 Eina_List *l, *children;
321 Eina_Bool resizable = EINA_TRUE;
322 Evas_Object *child, *widget = eail_widget_get_widget(EAIL_WIDGET(obj));
324 if (!widget) return NULL;
326 state_set= ATK_OBJECT_CLASS(eail_window_parent_class)->ref_state_set(obj);
328 if (elm_win_focus_get(widget))
330 atk_state_set_add_state(state_set, ATK_STATE_ACTIVE);
333 if (elm_win_iconified_get(widget))
335 atk_state_set_add_state(state_set, ATK_STATE_ICONIFIED);
338 if (elm_win_modal_get(widget))
340 atk_state_set_add_state(state_set, ATK_STATE_MODAL);
343 children = eail_widget_get_widget_children(EAIL_WIDGET(obj));
344 EINA_LIST_FOREACH(children, l, child)
346 evas_object_size_hint_weight_get(child, &x, &y);
347 if (!float_equal(x, EVAS_HINT_EXPAND) || !float_equal(y, EVAS_HINT_EXPAND))
349 resizable = EINA_FALSE;
353 eina_list_free(children);
357 atk_state_set_add_state(state_set, ATK_STATE_RESIZABLE);
364 * @brief Get the index in parent of the accessible
366 * @param obj AtkObject instance
367 * @return Integer representing the index of the object in parent
370 eail_window_get_index_in_parent(AtkObject *obj)
372 AtkObject *parent = atk_object_get_parent(obj);
374 if(atk_object_get_n_accessible_children(parent) == 1)
381 for(i = 0; i < atk_object_get_n_accessible_children(parent); i++)
383 AtkObject *child = atk_object_ref_accessible_child(parent, i);
386 g_object_unref(child);
389 g_object_unref(child);
397 * @brief EailWindow instance initializer
399 * @param window EailWindow instance
402 eail_window_init(EailWindow *window)
407 * @brief EailWindow class initializer
409 * @param klass EailWindowClass instance
412 eail_window_class_init(EailWindowClass *klass)
414 AtkObjectClass *atk_class = ATK_OBJECT_CLASS(klass);
415 EailWidgetClass *widget_class = EAIL_WIDGET_CLASS(klass);
417 widget_class->get_widget_children = eail_window_get_widget_children;
419 atk_class->initialize = eail_window_initialize;
420 atk_class->ref_state_set = eail_window_ref_state_set;
421 atk_class->get_index_in_parent = eail_window_get_index_in_parent;
425 * @brief Handle for minimize action
427 * @param action AtkAction instance
428 * @param data additional action data (not used here)
430 * @return TRUE if action was triggered successfully, FALSE otherwise
433 eail_action_minimize(AtkAction *action, void *data)
438 g_return_val_if_fail(EAIL_IS_WINDOW(action), FALSE);
440 widget = eail_widget_get_widget(EAIL_WIDGET(action));
442 elm_win_iconified_set(widget, EINA_TRUE);
444 obj = ATK_OBJECT(action);
446 eail_emit_atk_signal(obj, "minimize", EAIL_TYPE_WINDOW);
452 * @brief Handle for maximize action
454 * @param action AtkAction instance
455 * @param data additional action data (not used here)
457 * @return TRUE if action was triggered successfully, FALSE otherwise
460 eail_action_maximize(AtkAction *action, void *data)
465 g_return_val_if_fail(EAIL_IS_WINDOW(action), FALSE);
467 widget = eail_widget_get_widget(EAIL_WIDGET(action));
469 elm_win_maximized_set(widget, EINA_TRUE);
471 obj = ATK_OBJECT(action);
473 eail_emit_atk_signal(obj, "maximize", EAIL_TYPE_WINDOW);
478 * @brief Handle for action restore
480 * @param action an AtkAction
481 * @param data additional action data (not used here)
483 * @return TRUE if action was triggered successfully, FALSE otherwise
486 eail_action_restore(AtkAction *action, void *data)
491 g_return_val_if_fail(EAIL_IS_WINDOW(action), FALSE);
493 widget = eail_widget_get_widget(EAIL_WIDGET(action));
495 if(elm_win_maximized_get(widget))
497 elm_win_maximized_set(widget, EINA_FALSE);
500 if(elm_win_iconified_get(widget))
502 elm_win_activate(widget);
505 obj = ATK_OBJECT(action);
507 eail_emit_atk_signal(obj, "restore", EAIL_TYPE_WINDOW);
512 * @brief Adds window actions to the actions table
514 * @param action_widget widget that implements EailActionWidget interface
517 eail_window_actions_init(EailActionWidget *action_widget)
519 eail_action_widget_action_append(action_widget,
520 EAIL_WIN_ACTION_MAXIMIZE, NULL,
521 eail_action_maximize);
522 eail_action_widget_action_append(action_widget,
523 EAIL_WIN_ACTION_MINIMIZE, NULL,
524 eail_action_minimize);
525 eail_action_widget_action_append(action_widget,
526 EAIL_WIN_ACTION_RESTORE, NULL,
527 eail_action_restore);
531 * @brief AtkWindow interface initializer
533 * It is empty because at the moment
534 * AtkWindow is just about signals
536 * @param iface AtkWindowIface instance
539 atk_window_interface_init(AtkWindowIface *iface)
544 * @brief Returns the first found widget from EvasObjectBox
546 * @param evas_obj EvasObjectBox instance to search in
548 * @returns Evas_Object that represents the found widget
549 * or NULL if none has been found
552 _eail_get_first_widget_from_evas_box(Evas_Object *evas_obj)
554 Eina_List *children = NULL, *l;
555 Evas_Object *it_evas_obj = NULL;
557 children = evas_object_box_children_get(evas_obj);
559 EINA_LIST_FOREACH(children, l, it_evas_obj)
561 if (elm_object_widget_check (it_evas_obj))
563 DBG("Widget has been found %s", evas_object_type_get(it_evas_obj));
572 * @brief Returns the first found widget from given edje object
574 * @param evas_obj edje object to search in
576 * @returns Evas_Object that represents the found widget
577 * or NULL if none has been found
580 _eail_get_first_widget_from_edje(Evas_Object *evas_obj)
582 Eina_List *members = NULL, *l;
583 Evas_Object *it_evas_obj = NULL;
585 members = evas_object_smart_members_get(evas_obj);
586 EINA_LIST_FOREACH(members, l, it_evas_obj)
588 const char *type_name = evas_object_type_get(it_evas_obj);
590 /* if widget found, then returning immediately. If not widget, then
591 * looking for nested box*/
592 if (elm_object_widget_check (it_evas_obj))
594 else if (0 == g_strcmp0(type_name, "Evas_Object_Box") )
596 Evas_Object *widget_from_box = _eail_get_first_widget_from_evas_box(it_evas_obj);
598 return widget_from_box;
606 * @brief Gets a reference to the accessible child, if one exists, at the
607 * coordinate point specified by x and y
609 * @param component AtkComponent instance
610 * @param x x coordinate
611 * @param y y coordinate
612 * @param coord_type specifies whether the coordinates are relative to the
613 * screen or to the components top level window
615 * @returns AtkObject representing the accessible child, if one exists
618 eail_window_ref_accessible_at_point(AtkComponent *component,
621 AtkCoordType coord_type)
623 Evas_Object *widget = NULL, *evas_obj_at_coords = NULL;
624 Evas *wdgt_evas = NULL;
625 const char * found_obj_type = NULL;
627 widget = eail_widget_get_widget(EAIL_WIDGET(component));
629 if (!widget) return NULL;
631 if (coord_type == ATK_XY_SCREEN) {
633 Ecore_Evas *ee= ecore_evas_ecore_evas_get(evas_object_evas_get(widget));
635 ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
640 /* NOTE: it is crucial to get object from evas, NOT Evas_Object*/
641 wdgt_evas = evas_object_evas_get(widget);
643 evas_obj_at_coords = evas_object_top_at_xy_get
644 (wdgt_evas, x, y, EINA_FALSE, EINA_FALSE);
645 if (!evas_obj_at_coords)
647 DBG("Not found any object at coords %d,%d", x, y);
651 /* if edje object, then we have to parse that and extract widget from it*/
652 found_obj_type = evas_object_type_get(evas_obj_at_coords);
653 if (0 == g_strcmp0(found_obj_type, "edje"))
655 DBG("Edje object found...");
656 evas_obj_at_coords = _eail_get_first_widget_from_edje(evas_obj_at_coords);
659 return eail_factory_get_accessible(evas_obj_at_coords);
663 * @brief AtkComponent interface initialization
665 * Initialization for ref_accessible_at_point callback used by clients to
666 * reference object at given coordinates. Rest of implementation is default
667 * so no overriding-callbacks is needed.
669 * @param iface EailWindow instance
672 atk_component_interface_init(AtkComponentIface *iface)
674 iface->ref_accessible_at_point = eail_window_ref_accessible_at_point;
678 * @param dynamic_content_holder an EailDynamicContent object (EailWindow)
681 eail_window_update_descendants(EailDynamicContent *dynamic_content_holder)
684 EailWindow *window = NULL;
686 if (!EAIL_IS_WINDOW(dynamic_content_holder))
688 DBG("No EailWindow found. Returning");
692 window = EAIL_WINDOW(dynamic_content_holder);
694 n_children = atk_object_get_n_accessible_children(ATK_OBJECT(window));
695 if (n_children && n_children > window->child_count_last)
697 eail_emit_children_changed(TRUE, ATK_OBJECT(window), n_children - 1);
700 else if (n_children < window->child_count_last)
702 eail_emit_children_changed
703 (FALSE, ATK_OBJECT(window), window->child_count_last);
706 window->child_count_last = n_children;
710 * @brief Initializer for dynamic content interface, used for handling objects
711 * children hierarchy changes
713 * @param iface an EailDynamicContentIface
716 eail_dynamic_content_interface_init(EailDynamicContentIface *iface)
718 iface->update_hierarchy = eail_window_update_descendants;