Do not do notification if previously notified object is the same as this
[platform/upstream/atk.git] / atk / atkutil.c
1 /* ATK -  Accessibility Toolkit
2  * Copyright 2001 Sun Microsystems Inc.
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
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "atkutil.h"
21 #include "atkmarshal.c"
22
23
24 static void atk_util_class_init (AtkUtilClass *klass);
25
26 GType
27 atk_util_get_type (void)
28 {
29   static GType type = 0;
30
31   if (!type)
32     {
33       static const GTypeInfo typeInfo =
34       {
35         sizeof (AtkUtilClass),
36         (GBaseInitFunc) NULL,
37         (GBaseFinalizeFunc) NULL,
38         (GClassInitFunc) atk_util_class_init,
39         (GClassFinalizeFunc) NULL,
40         NULL,
41         sizeof (AtkUtil),
42         0,
43         (GInstanceInitFunc) NULL,
44       } ;
45       type = g_type_register_static (G_TYPE_OBJECT, "AtkUtil", &typeInfo, 0) ;
46     }
47   return type;
48 }
49
50 static void
51 atk_util_class_init (AtkUtilClass *klass)
52 {
53   klass->add_global_event_listener = NULL;
54   klass->remove_global_event_listener = NULL;
55   klass->get_root = NULL;
56   klass->get_toolkit_name = NULL;
57   klass->get_toolkit_version = NULL;
58 }
59
60 /*
61  * This file supports the addition and removal of multiple focus handlers
62  * as long as they are all called in the same thread.
63  */
64 static AtkEventListenerInit  focus_tracker_init = (AtkEventListenerInit) NULL;
65
66 static gboolean init_done = FALSE;
67
68 /*
69  * Array of FocusTracker structs
70  */
71 static GArray *trackers = NULL;
72 static guint  index = 0;
73
74 typedef struct _FocusTracker FocusTracker;
75
76 struct _FocusTracker {
77   guint index;
78   AtkEventListener func;
79 };
80
81 /**
82  * atk_focus_tracker_init:
83  * @add_function: Function to be called for focus tracker initialization
84  *
85  * Specifies the function to be called for focus tracker initialization.
86  * This function should be called by an implementation of the
87  * ATK interface if any specific work needs to be done to enable
88  * focus tracking.
89  **/
90 void
91 atk_focus_tracker_init (AtkEventListenerInit    init)
92 {
93   if (!focus_tracker_init)
94     focus_tracker_init = init;
95 }
96
97 /**
98  * atk_add_focus_tracker:
99  * @focus_tracker: Function to be added to the list of functions to be called
100  * when an object receives focus.
101  *
102  * Adds the specified function to the list of functions to be called
103  * when an object receives focus.
104  *
105  * Returns: added focus tracker id, or 0 on failure.
106  **/
107 guint
108 atk_add_focus_tracker (AtkEventListener   focus_tracker)
109 {
110   g_return_val_if_fail (focus_tracker, 0);
111
112   if (!init_done)
113   {
114     if (focus_tracker_init)
115     {
116       focus_tracker_init ();
117     }
118     trackers = g_array_sized_new (FALSE, TRUE, sizeof (FocusTracker), 0);
119     init_done = TRUE;
120   }
121   if (init_done)
122   {
123     FocusTracker item;
124
125     item.index = ++index;
126     item.func = focus_tracker;
127     trackers = g_array_append_val (trackers, item);
128     return index;
129   }
130   else
131   {
132     return 0;
133   }
134 }
135
136 /**
137  * atk_remove_focus_tracker:
138  * @tracker_id: the id of the focus tracker to remove
139  *
140  * Removes the specified focus tracker from the list of functions
141  * to be called when any object receives focus.
142  **/
143 void
144 atk_remove_focus_tracker (guint            tracker_id)
145 {
146   FocusTracker *item;
147   guint i;
148
149   if (trackers == NULL)
150     return;
151
152   if (tracker_id == 0)
153     return;
154
155   for (i = 0; i < trackers->len; i++)
156   {
157     item = &g_array_index (trackers, FocusTracker, i);
158     if (item->index == tracker_id)
159     {
160       trackers = g_array_remove_index (trackers, i);
161       break;
162     }
163   }
164 }
165
166 /**
167  * atk_focus_tracker_notify:
168  * @object: an #AtkObject
169  *
170  * Cause the focus tracker functions which have been specified to be
171  * executed for the object.
172  **/
173 void
174 atk_focus_tracker_notify (AtkObject       *object)
175 {
176   FocusTracker *item;
177   static AtkObject *previous_focus_object = NULL;
178   guint i;
179
180   if (trackers == NULL)
181     return;
182
183   if (object == previous_focus_object)
184     return;
185   else
186     {
187       if (previous_focus_object)
188         g_object_unref (previous_focus_object);
189       previous_focus_object = g_object_ref (object);
190     }
191   
192   for (i = 0; i < trackers->len; i++)
193   {
194     item = &g_array_index (trackers, FocusTracker, i);
195     g_return_if_fail (item != NULL);
196     item->func (object);
197   }
198 }
199
200 /**
201  * atk_add_global_event_listener:
202  * @listener: the listener to notify
203  * @event_type: the type of event for which notification is requested
204  *
205  * Adds the specified function to the list of functions to be called
206  * when an event of type event_type occurs.
207  *
208  * Returns: added event listener id, or 0 on failure.
209  **/
210 guint
211 atk_add_global_event_listener (GSignalEmissionHook listener,
212                                const gchar        *event_type)
213 {
214   guint retval;
215   AtkUtilClass *klass = g_type_class_ref (ATK_TYPE_UTIL);
216
217   if (klass->add_global_event_listener)
218     {
219       retval = klass->add_global_event_listener (listener, event_type);
220     }
221   else
222     {
223       retval = -1;
224     }
225   g_type_class_unref (klass);
226
227   return retval;
228 }
229
230 /**
231  * atk_remove_global_event_listener:
232  * @listener_id: the id of the event listener to remove
233  *
234  * Removes the specified event listener
235  **/
236 void
237 atk_remove_global_event_listener (guint listener_id)
238 {
239   AtkUtilClass *klass = g_type_class_peek (ATK_TYPE_UTIL);
240
241   if (klass && klass->remove_global_event_listener)
242     klass->remove_global_event_listener (listener_id);
243 }
244
245 /**
246  * atk_add_key_event_listener:
247  * @listener: the listener to notify
248  * @data: a #gpointer that points to a block of data that should be sent to the registered listeners,
249  *        along with the event notification, when it occurs.  
250  *
251  * Adds the specified function to the list of functions to be called
252  *        when a key event occurs.  The @data element will be passed to the
253  *        #AtkKeySnoopFunc (@listener) as the @func_data param, on notification.
254  *
255  * Returns: added event listener id, or 0 on failure.
256  **/
257 guint
258 atk_add_key_event_listener (AtkKeySnoopFunc listener, gpointer data)
259 {
260   guint retval;
261   AtkUtilClass *klass = g_type_class_peek (ATK_TYPE_UTIL);
262   if (klass && klass->add_key_event_listener)
263     {
264       retval = klass->add_key_event_listener (listener, data);
265     }
266   else
267     {
268       retval = -1;
269     }
270
271   return retval;
272 }
273
274 /**
275  * atk_remove_key_event_listener:
276  * @listener_id: the id of the event listener to remove
277  *
278  * Removes the specified event listener
279  **/
280 void
281 atk_remove_key_event_listener (guint listener_id)
282 {
283   AtkUtilClass *klass = g_type_class_peek (ATK_TYPE_UTIL);
284
285   if (klass->remove_key_event_listener)
286     klass->remove_key_event_listener (listener_id);
287 }
288
289 /**
290  * atk_get_root:
291  *
292  * Gets the root accessible container for the current application.
293  *
294  * Returns: the root accessible container for the current application
295  **/
296 AtkObject*
297 atk_get_root (void)
298 {
299   AtkUtilClass *klass = g_type_class_ref (ATK_TYPE_UTIL);
300   AtkObject    *retval;
301   if (klass->get_root)
302     {
303       retval = klass->get_root ();
304     }
305   else
306     {
307       retval = NULL;
308     }
309   g_type_class_unref (klass);
310
311   return retval;
312 }
313
314 /**
315  * atk_get_toolkit_name:
316  *
317  * Gets name string for the GUI toolkit implementing ATK for this application.
318  *
319  * Returns: name string for the GUI toolkit implementing ATK for this application
320  **/
321 G_CONST_RETURN gchar*
322 atk_get_toolkit_name (void)
323 {
324   const gchar *retval;
325   AtkUtilClass *klass = g_type_class_ref (ATK_TYPE_UTIL);
326   if (klass->get_toolkit_name)
327     {
328       retval = klass->get_toolkit_name ();
329     }
330   else
331     {
332       retval = NULL;
333     }
334   g_type_class_unref (klass);
335
336   return retval;
337 }
338
339 /**
340  * atk_get_toolkit_version:
341  *
342  * Gets version string for the GUI toolkit implementing ATK for this application.
343  *
344  * Returns: version string for the GUI toolkit implementing ATK for this application
345  **/
346 G_CONST_RETURN gchar*
347 atk_get_toolkit_version (void)
348 {
349   const gchar *retval;
350   AtkUtilClass *klass = g_type_class_ref (ATK_TYPE_UTIL);
351   if (klass->get_toolkit_version)
352     {
353       retval = klass->get_toolkit_version ();
354     }
355   else
356     {
357       retval = NULL;
358     }
359   g_type_class_unref (klass);
360
361   return retval;
362 }