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 Deactivate event handler
107 * @param data data passed to callback
108 * @param obj Evas_Object instance that raised event
109 * @param event_info additional event info
112 eail_window_on_deactivate(void *data, Evas *e, Evas_Object *obj, void *event_info)
114 g_return_if_fail(ATK_IS_OBJECT(data));
116 eail_emit_atk_signal(ATK_OBJECT(data), "deactivate", EAIL_TYPE_WINDOW);
120 * @brief Activate event handler
122 * @param data data passed to callback
123 * @param obj Evas_Object instance that raised event
124 * @param event_info additional event info
127 eail_window_on_activate(void *data, Evas *e, Evas_Object *obj, void *event_info)
129 g_return_if_fail(ATK_IS_OBJECT(data));
131 eail_emit_atk_signal(ATK_OBJECT(data), "activate", EAIL_TYPE_WINDOW);
137 * @brief Callback used for tracking resize-changes for window
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
145 eail_window_on_resize(void *data, Evas *e, Evas_Object *obj, void *event_info)
147 g_return_if_fail(ATK_IS_OBJECT(data));
149 eail_emit_atk_signal(ATK_OBJECT(data), "resize", EAIL_TYPE_WINDOW);
153 * @brief Destroyed event handler for window
155 * @param data passed to callback
156 * @param obj object that raised event
157 * @param event_info additional event info
160 _eail_window_handle_delete_event(void *data, Evas *e, Evas_Object *obj, void *event_info)
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);
168 * @brief Restore event handler
170 * @param data passed to callback
171 * @param obj object that raised event
172 * @param event_info additional event info
175 _eail_window_handle_restore_event(void *data,
179 eail_emit_atk_signal(ATK_OBJECT(data), "restore", EAIL_TYPE_WINDOW);
183 * @brief Create event handler
185 * @param data passed to callback
186 * @param obj object that raised event
187 * @param event_info additional event info
190 _eail_window_handle_create_event(void *data, Evas *e, Evas_Object *obj, void *event_info)
192 eail_emit_atk_signal(ATK_OBJECT(data), "create", EAIL_TYPE_WINDOW);
196 * @brief Initializes window focus handler
198 * @param obj AtkObject instance
201 eail_window_init_focus_handler(AtkObject *obj)
203 Evas_Object *nested_widget = NULL;
204 g_return_if_fail(EAIL_IS_WIDGET(obj));
206 nested_widget = eail_widget_get_widget(EAIL_WIDGET(obj));
209 ERR("No evas object inside EailWidget was found");
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);
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);
238 * @brief EailWindow initializer
240 * @param obj AtkObject instance
241 * @param data initialization data
244 eail_window_initialize(AtkObject *obj, gpointer data)
246 EailWindow *eail_win = NULL;
247 ATK_OBJECT_CLASS(eail_window_parent_class)->initialize(obj, data);
248 EAIL_WIDGET(obj)->layer = ATK_LAYER_WINDOW;
250 if (!elm_object_widget_check((Evas_Object *) data)) return;
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();
256 eail_window_init_focus_handler(obj);
257 eail_window_actions_init(EAIL_ACTION_WIDGET(obj));
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);
266 * @brief Gets the children list from given edje
268 * @param edje lowest (stacked) Evas object
269 * @return Eina_List representing the children list
272 _parse_edje(const Evas_Object *edje)
274 const Evas_Object *content_part = NULL;
275 const Evas_Object *menu_part = NULL;
276 Eina_List *list = NULL;
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");
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")))
289 list = eina_list_merge(list,
290 evas_object_box_children_get(content_part));
292 list = evas_object_box_children_get(content_part);
299 * @brief Gets widget's children
301 * @param widget EailWidget instance
302 * @return Eina_List representing the list of widget's children
305 eail_window_get_widget_children(EailWidget *widget)
307 Evas_Object *o, *obj = eail_widget_get_widget(widget);
308 Eina_List *win_childs = NULL;
309 Eina_List *widgets = NULL;
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
318 e = evas_object_evas_get(obj);
319 o = evas_object_bottom_get(e);
320 if (!g_strcmp0(evas_object_type_get(o), "edje"))
322 widgets = _parse_edje(o);
323 EINA_LIST_FOREACH(widgets, l, item)
325 if(!elm_object_widget_check(item))
326 widgets = eina_list_remove(widgets, item);
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 */
333 while ((o = evas_object_below_get(o)))
335 if (elm_object_widget_check(o))
337 /*be sure that object belongs to window and not to other
339 if (obj == elm_object_parent_widget_get(o))
340 win_childs = eina_list_append(win_childs, o);
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*/
350 widgets = eina_list_merge(widgets, win_childs);
352 widgets = win_childs;
359 * @brief Gets the state set of the accessible
361 * @param obj AtkObject instance
362 * @return AtkStateSet representing the state set of the accessible
365 eail_window_ref_state_set(AtkObject *obj)
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));
373 if (!widget) return NULL;
375 state_set= ATK_OBJECT_CLASS(eail_window_parent_class)->ref_state_set(obj);
377 if (elm_win_focus_get(widget))
379 atk_state_set_add_state(state_set, ATK_STATE_ACTIVE);
382 if (elm_win_iconified_get(widget))
384 atk_state_set_add_state(state_set, ATK_STATE_ICONIFIED);
387 if (elm_win_modal_get(widget))
389 atk_state_set_add_state(state_set, ATK_STATE_MODAL);
392 children = eail_widget_get_widget_children(EAIL_WIDGET(obj));
393 EINA_LIST_FOREACH(children, l, child)
395 evas_object_size_hint_weight_get(child, &x, &y);
396 if (!float_equal(x, EVAS_HINT_EXPAND) || !float_equal(y, EVAS_HINT_EXPAND))
398 resizable = EINA_FALSE;
402 eina_list_free(children);
406 atk_state_set_add_state(state_set, ATK_STATE_RESIZABLE);
413 * @brief Get the index in parent of the accessible
415 * @param obj AtkObject instance
416 * @return Integer representing the index of the object in parent
419 eail_window_get_index_in_parent(AtkObject *obj)
421 AtkObject *parent = atk_object_get_parent(obj);
423 if(atk_object_get_n_accessible_children(parent) == 1)
430 for(i = 0; i < atk_object_get_n_accessible_children(parent); i++)
432 AtkObject *child = atk_object_ref_accessible_child(parent, i);
435 g_object_unref(child);
438 g_object_unref(child);
446 * @brief EailWindow instance initializer
448 * @param window EailWindow instance
451 eail_window_init(EailWindow *window)
456 * @brief EailWindow class initializer
458 * @param klass EailWindowClass instance
461 eail_window_class_init(EailWindowClass *klass)
463 AtkObjectClass *atk_class = ATK_OBJECT_CLASS(klass);
464 EailWidgetClass *widget_class = EAIL_WIDGET_CLASS(klass);
466 widget_class->get_widget_children = eail_window_get_widget_children;
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;
474 * @brief Handle for minimize action
476 * @param action AtkAction instance
477 * @param data additional action data (not used here)
479 * @return TRUE if action was triggered successfully, FALSE otherwise
482 eail_action_minimize(AtkAction *action, void *data)
487 g_return_val_if_fail(EAIL_IS_WINDOW(action), FALSE);
489 widget = eail_widget_get_widget(EAIL_WIDGET(action));
491 elm_win_iconified_set(widget, EINA_TRUE);
493 obj = ATK_OBJECT(action);
495 eail_emit_atk_signal(obj, "minimize", EAIL_TYPE_WINDOW);
501 * @brief Handle for maximize action
503 * @param action AtkAction instance
504 * @param data additional action data (not used here)
506 * @return TRUE if action was triggered successfully, FALSE otherwise
509 eail_action_maximize(AtkAction *action, void *data)
514 g_return_val_if_fail(EAIL_IS_WINDOW(action), FALSE);
516 widget = eail_widget_get_widget(EAIL_WIDGET(action));
518 elm_win_maximized_set(widget, EINA_TRUE);
520 obj = ATK_OBJECT(action);
522 eail_emit_atk_signal(obj, "maximize", EAIL_TYPE_WINDOW);
527 * @brief Handle for action restore
529 * @param action an AtkAction
530 * @param data additional action data (not used here)
532 * @return TRUE if action was triggered successfully, FALSE otherwise
535 eail_action_restore(AtkAction *action, void *data)
540 g_return_val_if_fail(EAIL_IS_WINDOW(action), FALSE);
542 widget = eail_widget_get_widget(EAIL_WIDGET(action));
544 if(elm_win_maximized_get(widget))
546 elm_win_maximized_set(widget, EINA_FALSE);
549 if(elm_win_iconified_get(widget))
551 elm_win_activate(widget);
554 obj = ATK_OBJECT(action);
556 eail_emit_atk_signal(obj, "restore", EAIL_TYPE_WINDOW);
561 * @brief Adds window actions to the actions table
563 * @param action_widget widget that implements EailActionWidget interface
566 eail_window_actions_init(EailActionWidget *action_widget)
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);
580 * @brief AtkWindow interface initializer
582 * It is empty because at the moment
583 * AtkWindow is just about signals
585 * @param iface AtkWindowIface instance
588 atk_window_interface_init(AtkWindowIface *iface)
593 * @brief Returns the first found widget from EvasObjectBox
595 * @param evas_obj EvasObjectBox instance to search in
597 * @returns Evas_Object that represents the found widget
598 * or NULL if none has been found
601 _eail_get_first_widget_from_evas_box(Evas_Object *evas_obj)
603 Eina_List *children = NULL, *l;
604 Evas_Object *it_evas_obj = NULL;
606 children = evas_object_box_children_get(evas_obj);
608 EINA_LIST_FOREACH(children, l, it_evas_obj)
610 if (elm_object_widget_check (it_evas_obj))
612 DBG("Widget has been found %s", evas_object_type_get(it_evas_obj));
621 * @brief Returns the first found widget from given edje object
623 * @param evas_obj edje object to search in
625 * @returns Evas_Object that represents the found widget
626 * or NULL if none has been found
629 _eail_get_first_widget_from_edje(Evas_Object *evas_obj)
631 Eina_List *members = NULL, *l;
632 Evas_Object *it_evas_obj = NULL;
634 members = evas_object_smart_members_get(evas_obj);
635 EINA_LIST_FOREACH(members, l, it_evas_obj)
637 const char *type_name = evas_object_type_get(it_evas_obj);
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))
643 else if (0 == g_strcmp0(type_name, "Evas_Object_Box") )
645 Evas_Object *widget_from_box = _eail_get_first_widget_from_evas_box(it_evas_obj);
647 return widget_from_box;
655 * @brief Gets a reference to the accessible child, if one exists, at the
656 * coordinate point specified by x and y
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
664 * @returns AtkObject representing the accessible child, if one exists
667 eail_window_ref_accessible_at_point(AtkComponent *component,
670 AtkCoordType coord_type)
672 Evas_Object *widget = NULL, *evas_obj_at_coords = NULL;
673 Evas *wdgt_evas = NULL;
674 const char * found_obj_type = NULL;
676 widget = eail_widget_get_widget(EAIL_WIDGET(component));
678 if (!widget) return NULL;
680 if (coord_type == ATK_XY_SCREEN) {
682 Ecore_Evas *ee= ecore_evas_ecore_evas_get(evas_object_evas_get(widget));
684 ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
689 /* NOTE: it is crucial to get object from evas, NOT Evas_Object*/
690 wdgt_evas = evas_object_evas_get(widget);
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)
696 DBG("Not found any object at coords %d,%d", x, y);
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"))
704 DBG("Edje object found...");
705 evas_obj_at_coords = _eail_get_first_widget_from_edje(evas_obj_at_coords);
708 return eail_factory_get_accessible(evas_obj_at_coords);
712 * @brief AtkComponent interface initialization
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.
718 * @param iface EailWindow instance
721 atk_component_interface_init(AtkComponentIface *iface)
723 iface->ref_accessible_at_point = eail_window_ref_accessible_at_point;
727 * @param dynamic_content_holder an EailDynamicContent object (EailWindow)
730 eail_window_update_descendants(EailDynamicContent *dynamic_content_holder)
733 EailWindow *window = NULL;
735 if (!EAIL_IS_WINDOW(dynamic_content_holder))
737 DBG("No EailWindow found. Returning");
741 window = EAIL_WINDOW(dynamic_content_holder);
743 n_children = atk_object_get_n_accessible_children(ATK_OBJECT(window));
744 if (n_children && n_children > window->child_count_last)
746 eail_emit_children_changed(TRUE, ATK_OBJECT(window), n_children - 1);
749 else if (n_children < window->child_count_last)
751 eail_emit_children_changed
752 (FALSE, ATK_OBJECT(window), window->child_count_last);
755 window->child_count_last = n_children;
759 * @brief Initializer for dynamic content interface, used for handling objects
760 * children hierarchy changes
762 * @param iface an EailDynamicContentIface
765 eail_dynamic_content_interface_init(EailDynamicContentIface *iface)
767 iface->update_hierarchy = eail_window_update_descendants;