Implement get alpha to eail_widget in EAIL lib
[platform/core/uifw/eail.git] / eail / eail / eail_widget.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_widget.c
22  * @brief EailWidget implementation
23  */
24
25 #include <Ecore.h>
26 #include <Ecore_Evas.h>
27 #include <Elementary.h>
28
29 #include "eail_widget.h"
30 #include "eail_factory.h"
31 #include "eail_utils.h"
32 #include "eail_priv.h"
33
34 static void atk_component_interface_init(AtkComponentIface *iface);
35
36 /**
37  * @brief EailWidget type definition
38  */
39 G_DEFINE_TYPE_WITH_CODE(EailWidget, eail_widget, ATK_TYPE_OBJECT,
40                         G_IMPLEMENT_INTERFACE(ATK_TYPE_COMPONENT,
41                                               atk_component_interface_init));
42
43 /**
44  * @brief Gets Evas_Object from EailWidget
45  *
46  * @param widget EailWidget instance
47  * @return Evas_Object widget representing the EailWidget
48  */
49 Evas_Object *
50 eail_widget_get_widget(EailWidget *widget)
51 {
52     g_return_val_if_fail(EAIL_IS_WIDGET(widget), NULL);
53
54     return widget->widget;
55 }
56
57 /**
58  * @brief Gets EailWidget's children
59  *
60  * @param widget EailWidget instance
61  * @return Eina_List representing the EailWidget's children list
62  */
63 Eina_List *
64 eail_widget_get_widget_children(EailWidget *widget)
65 {
66     EailWidgetClass *klass;
67
68     g_return_val_if_fail(EAIL_IS_WIDGET(widget), NULL);
69
70     klass = EAIL_WIDGET_GET_CLASS(widget);
71     return klass->get_widget_children(widget);
72 }
73
74 /**
75  * @brief Callback used for tracking focus-in changes for widgets
76  *
77  * @param data data passed to callback
78  * @param e Evas instance that has been focused in
79  * @param obj Evas_Object instance that has been focused in
80  * @param event_info additional event info
81  */
82 void
83 eail_widget_on_focused_in(void *data, Evas *e, Evas_Object *obj, void *event_info)
84 {
85    g_return_if_fail(ATK_IS_OBJECT(data));
86
87    atk_object_notify_state_change(ATK_OBJECT(data), ATK_STATE_FOCUSED, TRUE);
88    atk_focus_tracker_notify(ATK_OBJECT(data));
89 }
90
91 /**
92  * @brief Callback used for tracking show-changes for widgets
93  *
94  * @param data data passed to callback
95  * @param e Evas instance that has been shown
96  * @param obj Evas_Object instance that has been shown
97  * @param event_info additional event info
98  */
99 void
100 eail_widget_on_show(void *data, Evas *e, Evas_Object *obj, void *event_info)
101 {
102    g_return_if_fail(ATK_IS_OBJECT(data));
103
104    atk_object_notify_state_change(ATK_OBJECT(data), ATK_STATE_SHOWING, TRUE);
105 }
106
107 /**
108  * @brief Callback used for tracking hide-changes for widgets
109  *
110  * @param data data passed to callback
111  * @param e Evas instance that has been shown
112  * @param obj Evas_Object instance that has been shown
113  * @param event_info additional event info
114  */
115 void
116 eail_widget_on_hide(void *data, Evas *e, Evas_Object *obj, void *event_info)
117 {
118    g_return_if_fail(ATK_IS_OBJECT(data));
119
120    atk_object_notify_state_change(ATK_OBJECT(data), ATK_STATE_SHOWING, FALSE);
121 }
122
123 /**
124  * @brief Callback used for tracking focus-out changes for widgets
125  *
126  * @param data data passed to callback
127  * @param e Evas instance that has been focused out
128  * @param obj Evas_Object instance that has been focused out
129  * @param event_info additional event info
130  */
131 void
132 eail_widget_on_focused_out(void *data, Evas *e, Evas_Object *obj, void *event_info)
133 {
134    g_return_if_fail(ATK_IS_OBJECT(data));
135
136    DBG("><");
137    atk_object_notify_state_change(ATK_OBJECT(data), ATK_STATE_FOCUSED, FALSE);
138    atk_focus_tracker_notify(ATK_OBJECT(data));
139    eail_notify_child_focus_changes();
140 }
141
142 /**
143  * @brief Callback used to tracking bounds-change changes for widgets
144  *
145  * @param data data passed to callback
146  * @param e an Evas that has been focused out
147  * @param obj an Evas_Object that has been focused out
148  * @param event_info additional event info
149  */
150 void
151 eail_widget_on_bounds_change(void *data, Evas *e, Evas_Object *obj, void *event_info)
152 {
153    g_return_if_fail(ATK_IS_COMPONENT(data));
154
155    AtkRectangle rect;
156    evas_object_geometry_get(obj, &rect.x, &rect.y, &rect.width, &rect.height);
157    g_signal_emit_by_name (ATK_OBJECT(data), "bounds_changed", &rect);
158 }
159
160
161 /**
162  * @brief Default callback for on_focused used for tracking focus changes of
163  * smart widgets
164  *
165  * @param data data passed to callback
166  * @param obj Evas_Object instance that has been shown
167  * @param event_info additional event info
168  */
169 void eail_widget_on_focused_smart(void *data,
170                                   Evas_Object *obj,
171                                   void *event_info)
172 {
173    g_return_if_fail(ATK_IS_OBJECT(data));
174
175    DBG("><");
176    atk_object_notify_state_change(ATK_OBJECT(data), ATK_STATE_FOCUSED, TRUE);
177    atk_focus_tracker_notify(ATK_OBJECT(data));
178    eail_notify_child_focus_changes();
179 }
180
181 /**
182  * @brief on_focused default callback used to tracking focus changes of
183  * smart widgets
184  *
185  * @param data data passed to callback
186  * @param obj an Evas_Object that has been shown
187  * @param event_info additional event info
188  */
189 void eail_widget_on_focused_out_smart(void *data,
190                                       Evas_Object *obj,
191                                       void *event_info)
192 {
193    g_return_if_fail(ATK_IS_OBJECT(data));
194
195    DBG("><");
196    /* Not propagating further, using only for internal eail focus changes*/
197    eail_notify_child_focus_changes();
198 }
199
200 /**
201  * @brief EailWidget initializer
202  *
203  * @param obj AtkObject instance
204  * @param data initialization data
205  */
206 static void
207 eail_widget_initialize(AtkObject *obj, gpointer data)
208 {
209     EailWidget *widget = EAIL_WIDGET(obj);
210
211     ATK_OBJECT_CLASS(eail_widget_parent_class)->initialize(obj, data);
212
213     widget->widget = (Evas_Object *)data;
214     widget->layer = ATK_LAYER_WIDGET;
215
216     obj->name = g_strdup(evas_object_name_get(widget->widget));
217     obj->role = ATK_ROLE_UNKNOWN;
218
219     if (!widget->widget) {
220         ERR("No evas object inside EailWidget was found");
221         return;
222     }
223
224     evas_object_event_callback_add(widget->widget, EVAS_CALLBACK_FOCUS_IN,
225                                        eail_widget_on_focused_in, widget);
226     evas_object_event_callback_add(widget->widget, EVAS_CALLBACK_FOCUS_OUT,
227                                    eail_widget_on_focused_out, widget);
228
229     evas_object_event_callback_add(widget->widget, EVAS_CALLBACK_SHOW,
230                                    eail_widget_on_show, widget);
231     evas_object_event_callback_add(widget->widget, EVAS_CALLBACK_HIDE,
232                                    eail_widget_on_hide, widget);
233
234     evas_object_event_callback_add(widget->widget, EVAS_CALLBACK_RESIZE,
235                                    eail_widget_on_bounds_change, widget);
236     evas_object_event_callback_add(widget->widget, EVAS_CALLBACK_MOVE,
237                                    eail_widget_on_bounds_change, widget);
238     /* for window don't need that event, it would result double generating
239      * focus-in event*/
240     if (!ATK_IS_WINDOW(obj))
241       evas_object_smart_callback_add
242             (widget->widget, "focused", eail_widget_on_focused_smart, widget);
243
244     evas_object_smart_callback_add
245           (widget->widget, "unfocused", eail_widget_on_focused_out_smart, widget);
246
247 }
248
249 /**
250  * @brief Default get_widget_children callback
251  *
252  * @param widget EailWidget instance
253  * @return NULL
254  */
255 static Eina_List *
256 eail_widget_get_real_widget_children(EailWidget *widget)
257 {
258     return NULL;
259 }
260
261 /**
262  * @brief Gets the number of children of obj
263  *
264  * @param obj AtkObject instance
265  *
266  * @returns integer representing the number of widget's children
267  */
268 static gint
269 eail_widget_get_n_children(AtkObject *obj)
270 {
271     gint n_children;
272     Eina_List *children;
273
274     children = eail_widget_get_widget_children(EAIL_WIDGET(obj));
275     n_children = eina_list_count(children);
276
277     eina_list_free(children);
278
279     return n_children;
280 }
281
282 /**
283  * @brief Gets reference to specified child of obj
284  *
285  * The caller must unreference it when it is no longer needed.
286  *
287  * @param obj AtkObject instance
288  * @param i child index
289  * @return AtkObject representing the specified child of obj
290  */
291 static AtkObject *
292 eail_widget_ref_child(AtkObject *obj, gint i)
293 {
294     Eina_List *children;
295     AtkObject *child = NULL;
296
297     children = eail_widget_get_widget_children(EAIL_WIDGET(obj));
298     if (eina_list_count(children) > i) {
299         child = eail_factory_get_accessible(eina_list_nth(children, i));
300         g_object_ref(child);
301     }
302
303     eina_list_free(children);
304
305     return child;
306 }
307
308 /**
309  * @brief Gets the parent of obj
310  *
311  * @param obj AtkObject instance
312  * @return AtkObject representing the parent of obj
313  */
314 static AtkObject *
315 eail_widget_get_parent(AtkObject *obj)
316 {
317     Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(obj));
318
319     if (!widget) {
320         return NULL;
321     }
322
323     if (obj->accessible_parent) {
324         return obj->accessible_parent;
325     }
326
327     return eail_factory_get_accessible(elm_object_parent_widget_get(widget));
328 }
329
330 /**
331  * @brief Gets the 0-based index of this accessible in its parent
332  *
333  * Returns -1 if the accessible does not have an accessible parent.
334  *
335  * @param obj AtkObject instance
336  * @return integer representing obj's index in its parent
337  */
338 static gint
339 eail_widget_get_index_in_parent(AtkObject *obj)
340 {
341     gint index;
342     Eina_List *l, *children;
343     AtkObject *parent;
344     Evas_Object *child;
345     Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(obj));
346
347     if (!widget) {
348         return -1;
349     }
350
351     if (obj->accessible_parent)
352     {
353         parent = obj->accessible_parent;
354     } else {
355         parent = atk_object_get_parent(obj);
356     }
357
358     if (!parent) {
359         return -1;
360     }
361
362     index = -1;
363     children = eail_widget_get_widget_children(EAIL_WIDGET(parent));
364     EINA_LIST_FOREACH(children, l, child) {
365         ++index;
366         if (child == widget) {
367             break;
368         }
369     }
370
371     eina_list_free(children);
372
373     return index;
374 }
375
376 /**
377  * @brief Gets the state set of obj
378  *
379  * @param obj AtkObject instance
380  * @return AtkState representing the state set of obj
381  */
382 static AtkStateSet *
383 eail_widget_ref_state_set(AtkObject *obj)
384 {
385     AtkStateSet *state_set;
386     Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(obj));
387
388     state_set= ATK_OBJECT_CLASS(eail_widget_parent_class)->ref_state_set(obj);
389
390     return eail_evas_obj_ref_state_set(widget, state_set);
391 }
392
393 /**
394  * @brief Gets the attribute set of obj
395  *
396  * @param obj AtkObject instance
397  * @return AtkAttributeSet representing obj's attribute set
398  */
399 static AtkAttributeSet *
400 eail_widget_get_attributes(AtkObject *obj)
401 {
402     AtkAttribute *attr;
403     AtkAttributeSet *attributes;
404     Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(obj));
405
406     if (!widget) {
407         return NULL;
408     }
409
410     attr = g_new(AtkAttribute, 1);
411     attr->name = g_strdup("type");
412     attr->value = g_strdup(elm_object_widget_type_get(widget));
413
414     attributes = g_slist_append(NULL, attr);
415
416     return attributes;
417 }
418
419 /**
420  * @brief EailWidget instance initializer
421  *
422  * @param widget EailWidget instance
423  */
424 static void
425 eail_widget_init(EailWidget *widget)
426 {
427 }
428
429 /**
430  * @brief EailWidget finalizer
431  *
432  * Frees memory assigned to object.
433  *
434  * @param obj GObject instance
435  */
436 static void
437 eail_widget_class_finalize(GObject *obj)
438 {
439    EailWidget *eail_widget = EAIL_WIDGET(obj);
440    Evas_Object *evas_widget = eail_widget_get_widget(eail_widget);
441
442    if (evas_widget)
443      eail_factory_unregister_wdgt_from_cache(evas_widget);
444
445    G_OBJECT_CLASS(eail_widget_parent_class)->finalize(obj);
446 }
447
448 /**
449  * @brief EailWidget class initializer
450  *
451  * Function called upon instance creation. It initializes AtkObject class
452  * callbacks for EailWidget.
453  *
454  * @param klass EailWidgetClass instance
455  */
456 static void
457 eail_widget_class_init(EailWidgetClass *klass)
458 {
459     AtkObjectClass *atk_class = ATK_OBJECT_CLASS(klass);
460     GObjectClass *g_object_class = G_OBJECT_CLASS(klass);
461
462     klass->get_widget_children = eail_widget_get_real_widget_children;
463
464     atk_class->initialize = eail_widget_initialize;
465     atk_class->get_n_children = eail_widget_get_n_children;
466     atk_class->ref_child = eail_widget_ref_child;
467     atk_class->get_parent = eail_widget_get_parent;
468     atk_class->get_index_in_parent = eail_widget_get_index_in_parent;
469     atk_class->ref_state_set = eail_widget_ref_state_set;
470     atk_class->get_attributes = eail_widget_get_attributes;
471
472     g_object_class->finalize = eail_widget_class_finalize;
473 }
474
475 /**
476  * @brief Grabs focus of a component
477  *
478  * @param component AtkComponent instance
479  * @return TRUE on success, FALSE otherwise
480  */
481 static gboolean
482 eail_widget_grab_focus(AtkComponent *component)
483 {
484     Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(component));
485
486     return eail_evas_obj_grab_focus(widget);
487 }
488
489 /**
490  * @brief Gets component's layer
491  *
492  * @param component AtkComponent instance
493  * @return AtkLayer representing the component's layer
494  */
495 static AtkLayer
496 eail_widget_get_layer(AtkComponent *component)
497 {
498     return EAIL_WIDGET(component)->layer;
499 }
500
501 /**
502  * @brief Gets the rectangle which gives the extent of the component
503  *
504  * @param component AtkComponent instance
505  * @param [out] x upper left x coordinate of the rectangle
506  * @param [out] y upper left y coordinate of the rectangle
507  * @param [out] width width of the rectangle
508  * @param [out] height height of the rectangle
509  * @param coord_type coordinates type
510  */
511 static void
512 eail_widget_get_extents(AtkComponent  *component,
513                         gint          *x,
514                         gint          *y,
515                         gint          *width,
516                         gint          *height,
517                         AtkCoordType   coord_type)
518 {
519     Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(component));
520
521     *x = *y = G_MININT;
522     *width = *height = -1;
523     if (!widget) {
524         return;
525     }
526
527     evas_object_geometry_get(widget, x, y, width, height);
528
529     if (coord_type == ATK_XY_SCREEN) {
530         int ee_x, ee_y;
531         Ecore_Evas *ee= ecore_evas_ecore_evas_get(evas_object_evas_get(widget));
532
533         ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
534         *x += ee_x;
535         *y += ee_y;
536     }
537 }
538
539 /**
540  * @brief Sets component position
541  *
542  * @param component AtkComponent instance
543  * @param x upper left x coordinate
544  * @param y upper left y coordinate
545  * @param coord_type coordinates type
546  * @return TRUE on success, FALSE otherwise
547  */
548 static gboolean
549 eail_widget_set_position(AtkComponent *component,
550                          gint         x,
551                          gint         y,
552                          AtkCoordType coord_type)
553 {
554     Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(component));
555
556     if (!widget) return FALSE;
557
558     if (x < 0 || y < 0) return FALSE;
559
560     if (coord_type == ATK_XY_SCREEN) {
561         int ee_x, ee_y;
562         Ecore_Evas *ee= ecore_evas_ecore_evas_get(evas_object_evas_get(widget));
563
564         ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
565         x -= ee_x;
566         y -= ee_y;
567     }
568
569     evas_object_move(widget, x, y);
570
571     return TRUE;
572 }
573
574 /**
575  * @brief Sets component size
576  *
577  * @param component AtkComponent instance
578  * @param width new width of component
579  * @param height new height of component
580  * @return TRUE on success, FALSE otherwise
581  */
582 static gboolean
583 eail_widget_set_size(AtkComponent *component,
584                      gint          width,
585                      gint          height)
586 {
587     Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(component));
588
589     if (!widget) return FALSE;
590
591     if (width <= 0 || height <= 0) return FALSE;
592
593     evas_object_resize(widget, width, height);
594
595     return TRUE;
596 }
597
598 /**
599  * @brief Sets component extents
600  *
601  * @param component AtkComponent instance
602  * @param x new upper left x coordinate
603  * @param y new upper left y coordinate
604  * @param width new width of component
605  * @param height new height of component
606  * @param coord_type coordinates type
607  * @return TRUE on success, FALSE otherwise
608  */
609 static gboolean
610 eail_widget_set_extents(AtkComponent  *component,
611                         gint           x,
612                         gint           y,
613                         gint           width,
614                         gint           height,
615                         AtkCoordType   coord_type)
616 {
617     Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(component));
618
619     if (!widget) {
620         return FALSE;
621     }
622
623     if (coord_type == ATK_XY_SCREEN) {
624         int ee_x, ee_y;
625         Ecore_Evas *ee= ecore_evas_ecore_evas_get(evas_object_evas_get(widget));
626
627         ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
628         x -= ee_x;
629         y -= ee_y;
630     }
631
632     if (x < 0 || y < 0) {
633         return FALSE;
634     }
635
636     evas_object_move(widget, x, y);
637     evas_object_resize(widget, width, height);
638
639     return TRUE;
640 }
641
642 /**
643  * @brief Sets function to execute whenever component gets focus
644  *
645  * @param component AtkComponent instance
646  * @param handler AtkFocusHandler instance
647  * @returns integer representing the handler's id
648  */
649 static guint
650 eail_widget_add_focus_handler(AtkComponent *component,
651                               AtkFocusHandler handler)
652 {
653    GSignalMatchType match_type;
654    gulong ret;
655    guint signal_id;
656
657    match_type = G_SIGNAL_MATCH_ID;
658    signal_id = g_signal_lookup("focus-event", ATK_TYPE_OBJECT);
659
660    ret = g_signal_handler_find(component, match_type, signal_id, 0, NULL,
661                                (gpointer)handler, NULL);
662    if (!ret)
663      {
664         return g_signal_connect_closure_by_id(component,
665                                               signal_id, 0,
666                                               g_cclosure_new(
667                                                   G_CALLBACK(handler), NULL,
668                                                   (GClosureNotify)NULL),
669                                               FALSE);
670      }
671    else
672      {
673         return 0;
674      }
675 }
676
677 /**
678  * @brief Gets alpha value
679  *
680  * @param component an AtkComponent
681  * @return alpha value
682  */
683 static gdouble
684 eail_widget_get_alpha(AtkComponent *component)
685 {
686     Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(component));
687
688     int alpha;
689     evas_object_color_get(widget, NULL, NULL, NULL, &alpha);
690
691     return (gdouble)alpha/255.0;
692 }
693
694 /**
695  * @brief AtkComponent interface initialization
696  *
697  * @param iface EailNaviframPage instance
698  */
699 static void
700 atk_component_interface_init(AtkComponentIface *iface)
701 {
702    iface->grab_focus = eail_widget_grab_focus;
703    iface->get_layer = eail_widget_get_layer;
704    iface->get_extents = eail_widget_get_extents;
705    iface->set_position = eail_widget_set_position;
706    iface->set_size = eail_widget_set_size;
707    iface->set_extents = eail_widget_set_extents;
708    iface->add_focus_handler = eail_widget_add_focus_handler;
709    iface->get_alpha = eail_widget_get_alpha;
710 }