2008-05-28 Mark Doffman <mark.doffman@codethink.co.uk>
[platform/core/uifw/at-spi2-atk.git] / tests / dummyatk / my-atk-component.c
1 #include <stdio.h>
2 #include <atk/atk.h>
3 #include <limits.h>
4
5 #include "my-atk-object.h"
6 #include "my-atk-component.h"
7
8 //*************************implementation***********************
9 static MyAtkObjectClass *component_parent_class = NULL;
10 //current focus object
11 static AtkComponent* focus_object = NULL;
12
13 static guint focus_signal_id = 0;
14 /*
15  * Because of implementation of AtkUtils, we need to ensure that list of focus_trackers 
16  * is not empty. Otherwise function atk_focus_tracker_notify will not change focus.
17  */
18 static guint focus_tracker_id = 0;
19 static void my_event_listener(AtkObject* obj)
20 {
21     //simply exist for register as focus_tracker
22 }
23 /*
24  * If this flag is TRUE, then focus cannot be changed until someone clears the flag
25  * via my_atk_component_set_modal(FALSE).
26  */
27 static gboolean is_modal = FALSE;
28 //for debug
29 void print_extent(AtkRectangle *extent)
30 {
31     printf("{%d,%d,%d,%d}", extent->x, extent->y, extent->width, extent->height);
32 }
33 //for internal use
34 static void emit_bounds_changed(MyAtkComponent *component)
35 {
36     static guint bounds_changed_id = 0;
37     if(bounds_changed_id == 0)
38     {
39         bounds_changed_id = g_signal_lookup("bounds-changed", ATK_TYPE_COMPONENT);
40     }
41     AtkRectangle *param = g_boxed_copy(ATK_TYPE_RECTANGLE, &(component->extent));
42     g_signal_emit(component, bounds_changed_id, 0, param);
43 }
44 static void change_focus(AtkComponent* component, gboolean is_gain)
45 {
46     const gchar* state_name = atk_state_type_get_name(ATK_STATE_FOCUSED);
47     
48     g_signal_emit_by_name(component, "focus-event", is_gain);
49     g_signal_emit_by_name(component, "state-change::focused",
50         state_name, is_gain);
51     
52     AtkObject* parent = atk_object_get_parent((AtkObject*)component);
53     if(parent != NULL)
54     {
55         AtkStateSet* stateSet = atk_object_ref_state_set(parent);
56         if(atk_state_set_contains_state(stateSet, ATK_STATE_MANAGES_DESCENDANTS))
57             g_signal_emit_by_name(parent, "active-descendant-changed",
58                 atk_get_focus_object());
59         g_object_unref(stateSet);
60     }
61 }
62 //implementation of virtual functions
63 //******************ref_state_set(AtkObject)*****************************
64 static AtkStateSet* my_atk_component_ref_state_set(AtkObject *object)
65 {
66     MyAtkComponent *self = (MyAtkComponent*)object;
67     
68     AtkStateSet* result = ((AtkObjectClass*)component_parent_class)->
69         ref_state_set(object);
70     if(self->is_manage_descendants) 
71         atk_state_set_add_state(result, ATK_STATE_MANAGES_DESCENDANTS);
72     return result;
73 }
74 //******************get_size*******************
75 static void my_atk_component_get_size(AtkComponent *component, gint *width, gint *height)
76 {
77     g_return_if_fail(MY_IS_ATK_COMPONENT(component));
78     
79     MyAtkComponent *self = MY_ATK_COMPONENT(component);
80     *width = self->extent.width;
81     *height = self->extent.height;
82 }
83 //*********************get_position*******************
84 static void my_atk_component_get_position(AtkComponent *component, gint *x, gint *y, AtkCoordType coord_type)
85 {
86     g_return_if_fail(MY_IS_ATK_COMPONENT(component));
87     
88     MyAtkComponent *self = MY_ATK_COMPONENT(component);
89     *x = self->extent.x;
90     *y = self->extent.y;
91     
92 //**********************get_extents*******************
93 }
94 static void my_atk_component_get_extents(AtkComponent *component, gint *x, gint *y,
95     gint *width, gint *height, AtkCoordType coord_type)
96 {
97     g_return_if_fail(MY_IS_ATK_COMPONENT(component));
98     
99     MyAtkComponent *self = MY_ATK_COMPONENT(component);
100     *x = self->extent.x;
101     *y = self->extent.y;
102     *width = self->extent.width;
103     *height = self->extent.height;
104 }
105
106 //**************************set_size*******************
107 static gboolean my_atk_component_set_size(AtkComponent *component, gint width, gint height)
108 {
109     g_return_val_if_fail(MY_IS_ATK_COMPONENT(component), FALSE);
110     
111     MyAtkComponent *self = MY_ATK_COMPONENT(component);
112     if(self->is_extent_may_changed)
113     {
114         self->extent.width = width;
115         self->extent.height = height;
116     
117         emit_bounds_changed(self);
118         
119         return TRUE;
120     }
121     return FALSE;
122 }
123 //**************************set_position********************
124 static gboolean my_atk_component_set_position(AtkComponent *component,
125     gint x, gint y, AtkCoordType coord_type)
126 {
127     g_return_val_if_fail(MY_IS_ATK_COMPONENT(component), FALSE);
128     
129     MyAtkComponent *self = MY_ATK_COMPONENT(component);
130     if(self->is_extent_may_changed)
131     {
132         self->extent.x = x;
133         self->extent.y = y;
134         
135         emit_bounds_changed(self);
136
137         return TRUE;
138     }
139     return FALSE;
140 }
141 //*************************************set_extents***************
142 static gboolean my_atk_component_set_extents(AtkComponent *component,
143     gint x, gint y, gint width, gint height, AtkCoordType coord_type)
144 {
145     g_return_val_if_fail(MY_IS_ATK_COMPONENT(component), FALSE);
146     
147     MyAtkComponent *self = MY_ATK_COMPONENT(component);
148     
149     if(self->is_extent_may_changed)
150     {
151         self->extent.x = x;
152         self->extent.y = y;
153         self->extent.width = width;
154         self->extent.height = height;
155         
156         emit_bounds_changed(self);
157         
158         return TRUE;
159     }
160     return FALSE;
161 }
162 //**************************get_layer****************
163 static AtkLayer my_atk_component_get_layer(AtkComponent *component)
164 {
165     g_return_val_if_fail(MY_IS_ATK_COMPONENT(component), ATK_LAYER_INVALID);
166     
167     MyAtkComponent *self = MY_ATK_COMPONENT(component);
168     return self->layer;
169 }
170 //**************************get_mdi_zorder****************
171 static gint my_atk_component_get_mdi_zorder(AtkComponent *component)
172 {
173     g_return_val_if_fail(MY_IS_ATK_COMPONENT(component), G_MININT);
174     
175     MyAtkComponent *self = MY_ATK_COMPONENT(component);
176     return self->zorder;
177 }
178 //***********************contains**********************
179 static gboolean my_atk_component_contains(AtkComponent *component,
180     gint x, gint y, AtkCoordType coord_type)
181 {
182     g_return_val_if_fail(MY_IS_ATK_COMPONENT(component), FALSE);
183     //for extract extent
184     gint x_tmp, y_tmp, width_tmp, height_tmp;
185     my_atk_component_get_extents(component, &x_tmp, &y_tmp, &width_tmp, &height_tmp, coord_type);
186     
187     if( (x >= x_tmp) &&(y >= y_tmp) &&(x < x_tmp + width_tmp) && (y < y_tmp + height_tmp) )
188     {
189         return TRUE;
190     }
191     else
192     {
193         return FALSE;
194     }
195 }
196 //**********************ref_accessible_at_point***********************
197 /*
198  * Retuns accessible child that implements AtkCOmponent and contains the given point.
199  */
200 static AtkObject* my_atk_component_ref_accessible_at_point(AtkComponent* component,
201     gint x, gint y, AtkCoordType coord_type)
202 {
203     g_return_val_if_fail(MY_IS_ATK_COMPONENT(component), NULL);
204     gint i;
205     
206     gint n_children = atk_object_get_n_accessible_children((AtkObject*)component);
207     for(i = 0; i < n_children; i++)
208     {
209         AtkObject *child = atk_object_ref_accessible_child((AtkObject*)component, i);
210         if(ATK_IS_COMPONENT(child)
211             && atk_component_contains((AtkComponent*)child, x, y, coord_type))
212         {
213             return child;
214         }
215         g_object_unref(child);
216     }
217     return NULL;
218 }
219 //*************************************grab_focus*********************************
220 static gboolean my_atk_component_grab_focus(AtkComponent* component)
221 {
222     if(component == focus_object)
223     { 
224         //Already has focus
225         return TRUE;
226     }
227     if(is_modal)
228     {
229         //cannot grab focus
230         return FALSE;
231     }
232     AtkComponent *focus_object_old = focus_object;
233     focus_object = component;
234     
235     atk_focus_tracker_notify((AtkObject*)component);
236     
237     if(focus_object_old != NULL)
238     {
239         //signals for object which lost focus
240         change_focus(focus_object_old, FALSE);
241     }
242     if(component != NULL)
243     {
244         //signals for object which grab focus
245         change_focus(component, TRUE);
246     }
247     return TRUE;
248 }
249 //***********************my_atk_component_add_focus_handler*********************
250 static guint my_atk_component_add_focus_handler(AtkComponent *component, AtkFocusHandler handler)
251 {
252     g_return_val_if_fail(MY_IS_ATK_COMPONENT(component),0);
253     //verify whether handler already connect to object
254     gulong found_handler_id = g_signal_handler_find(component,
255         G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC,
256         focus_signal_id,
257         0,
258         NULL,
259         (gpointer)handler,
260         NULL);
261     if(found_handler_id == 0)
262     {
263         //handler hasn't been connected yet
264         return g_signal_connect_closure_by_id(component,
265             focus_signal_id,
266             0,
267             g_cclosure_new( (GCallback)handler,
268                 NULL,
269                 NULL),
270             FALSE);
271     }
272     else/* found_handler_id != 0*/
273     {
274         //handler has already been connected
275         return 0;
276     }
277
278 }
279 //***********************my_atk_component_remove_focus_handler*********************
280 static void my_atk_component_remove_focus_handler(AtkComponent *component, guint handler_id)
281 {
282     g_signal_handler_disconnect(component, handler_id);
283 }
284 //***********************my_atk_component_set_modal(my function)***************
285 void my_atk_component_set_modal(gboolean value)
286 {
287     is_modal = value;
288 }
289 //******************my_atk_component_set_manage_descendants(my_function)*******
290 void my_atk_component_set_manage_descendants(MyAtkComponent* component, gboolean value)
291 {
292     if(component->is_manage_descendants == value)return;
293     component->is_manage_descendants = value;
294     g_signal_emit_by_name(component, "state-change::manages-descendants",
295         "manages-descendants", value);
296 }
297 //Others funtions
298 static void my_atk_component_instance_init(GTypeInstance *obj, gpointer g_class)
299 {
300     MyAtkComponent *self = (MyAtkComponent*)obj;
301     //set defaults values
302     self->extent.x = 0;
303     self->extent.y = 0;
304     self->extent.width = 10;
305     self->extent.height = 10;
306     self->is_extent_may_changed = TRUE;
307     self->layer = ATK_LAYER_INVALID;
308     self->zorder = -2147;
309 }
310 static void my_atk_component_instance_finalize(GObject* obj)
311 {
312     MyAtkComponent* component = (MyAtkComponent*)obj;
313
314     if(((AtkObject*)component) == atk_get_focus_object())
315     {
316         atk_focus_tracker_notify(NULL);
317     }
318 }
319
320 static void my_atk_component_class_init(gpointer g_class, gpointer class_data)
321 {
322     GObjectClass* g_object_class = (GObjectClass*)g_class;
323     AtkObjectClass* atkObject_class = (AtkObjectClass*)g_class;
324     //GObject virtual table
325     g_object_class->finalize = my_atk_component_instance_finalize;
326     //AtkObject virtual table
327     atkObject_class->ref_state_set = my_atk_component_ref_state_set;
328     //parent_class
329     component_parent_class = g_type_class_peek_parent(g_class);
330     //make focus_tracker's table not empty.
331     focus_tracker_id = atk_add_focus_tracker(my_event_listener);
332     //store "focus-event"-signal id
333     focus_signal_id = g_signal_lookup("focus-event",MY_TYPE_ATK_COMPONENT);
334 }
335 /*
336  * Though, according to the documentation, this function will never called for 
337  * static-registred types.
338  * Base_init function doesn't suite for this work,
339  * because it will called in every derived classes.
340  */
341 /*static void my_atk_component_class_finalize(gpointer g_class, gpointer class_data)
342 {
343     
344     if(focus_tracker_id != 0)
345     {
346         atk_remove_focus_tracker(focus_tracker_id);
347         focus_tracker_id = 0;
348     }
349 }*/
350 static void my_atk_component_interface_init(gpointer g_iface, gpointer iface_data)
351 {
352     AtkComponentIface *klass = (AtkComponentIface*)g_iface;
353     
354     klass->get_extents = my_atk_component_get_extents;
355     klass->get_position = my_atk_component_get_position;
356     klass->get_size = my_atk_component_get_size;
357     
358     klass->set_extents = my_atk_component_set_extents;
359     klass->set_position = my_atk_component_set_position;
360     klass->set_size = my_atk_component_set_size;
361     
362     klass->contains = my_atk_component_contains;
363     klass->ref_accessible_at_point = my_atk_component_ref_accessible_at_point;
364     
365     klass->get_layer = my_atk_component_get_layer;
366     klass->get_mdi_zorder = my_atk_component_get_mdi_zorder;
367     
368     klass->grab_focus = my_atk_component_grab_focus;
369     klass->add_focus_handler = my_atk_component_add_focus_handler;
370     klass->remove_focus_handler = my_atk_component_remove_focus_handler;
371 }
372
373 GType my_atk_component_get_type()
374 {
375     static GType type = 0;
376     if(type == 0)
377     {
378         static const GTypeInfo typeInfo = 
379         {
380             sizeof(MyAtkComponentClass),
381             NULL, //base_init
382             NULL, //base_finalize
383             my_atk_component_class_init, //class_init
384             NULL, //class_finalize
385             NULL, //class_data
386             sizeof(MyAtkComponent),
387             0, //n_preallocs
388             my_atk_component_instance_init //instance_init
389         };
390
391         static const GInterfaceInfo iface_info = 
392         {
393             my_atk_component_interface_init,    /* interface_init*/
394             NULL,                               /* interface_finalize*/
395             NULL                                /* interface_data */
396         };
397         type = g_type_register_static(MY_TYPE_ATK_OBJECT, "MyAtkComponent", &typeInfo, 0);
398         g_type_add_interface_static(type,
399             ATK_TYPE_COMPONENT,
400             &iface_info);
401     }
402     return type;    
403 }