Deprecate AtkObject::focus-event signal and all related methods
[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 #include "config.h"
23
24 static void atk_util_class_init (AtkUtilClass *klass);
25
26 static AtkObject *previous_focus_object = NULL;
27
28 typedef struct _AtkUtilListenerInfo AtkUtilListenerInfo;
29 struct _AtkUtilListenerInfo
30 {
31   gint key;
32   guint signal_id;
33   gulong hook_id;
34 };
35 static GHashTable *listener_list = NULL;
36
37 GType
38 atk_util_get_type (void)
39 {
40   static GType type = 0;
41
42   if (!type)
43     {
44       static const GTypeInfo typeInfo =
45       {
46         sizeof (AtkUtilClass),
47         (GBaseInitFunc) NULL,
48         (GBaseFinalizeFunc) NULL,
49         (GClassInitFunc) atk_util_class_init,
50         (GClassFinalizeFunc) NULL,
51         NULL,
52         sizeof (AtkUtil),
53         0,
54         (GInstanceInitFunc) NULL,
55       } ;
56       type = g_type_register_static (G_TYPE_OBJECT, "AtkUtil", &typeInfo, 0) ;
57     }
58   return type;
59 }
60
61 /*
62  * This file supports the addition and removal of multiple focus handlers
63  * as long as they are all called in the same thread.
64  */
65 static AtkEventListenerInit  focus_tracker_init = (AtkEventListenerInit) NULL;
66
67 static gboolean init_done = FALSE;
68
69 /*
70  * Array of FocusTracker structs
71  */
72 static GArray *trackers = NULL;
73 static guint  global_index = 0;
74
75 typedef struct _FocusTracker FocusTracker;
76
77 struct _FocusTracker {
78   guint index;
79   AtkEventListener func;
80 };
81
82 /**
83  * atk_focus_tracker_init:
84  * @init: Function to be called for focus tracker initialization
85  *
86  * Specifies the function to be called for focus tracker initialization.
87  * This function should be called by an implementation of the
88  * ATK interface if any specific work needs to be done to enable
89  * focus tracking.
90  *
91  * Deprecated: This method is deprecated since ATK version
92  * 2.9.4. Focus tracking has been dropped as a feature to be
93  * implemented by ATK itself.
94  *
95  **/
96 void
97 atk_focus_tracker_init (AtkEventListenerInit    init)
98 {
99   if (!focus_tracker_init)
100     focus_tracker_init = init;
101 }
102
103 /**
104  * atk_add_focus_tracker:
105  * @focus_tracker: Function to be added to the list of functions to be called
106  * when an object receives focus.
107  *
108  * Adds the specified function to the list of functions to be called
109  * when an object receives focus.
110  *
111  * Deprecated: This method is deprecated since ATK version
112  * 2.9.4. Focus tracking has been dropped as a feature to be
113  * implemented by ATK itself. If you need focus tracking on your
114  * implementation, subscribe to the state-changed:focused signal.
115  *
116  * Returns: added focus tracker id, or 0 on failure.
117  **/
118 guint
119 atk_add_focus_tracker (AtkEventListener   focus_tracker)
120 {
121   g_return_val_if_fail (focus_tracker, 0);
122
123   if (!init_done)
124   {
125     if (focus_tracker_init)
126     {
127       focus_tracker_init ();
128     }
129     trackers = g_array_sized_new (FALSE, TRUE, sizeof (FocusTracker), 0);
130     init_done = TRUE;
131   }
132   if (init_done)
133   {
134     FocusTracker item;
135
136     item.index = ++global_index;
137     item.func = focus_tracker;
138     trackers = g_array_append_val (trackers, item);
139     return global_index;
140   }
141   else
142   {
143     return 0;
144   }
145 }
146
147 /**
148  * atk_remove_focus_tracker:
149  * @tracker_id: the id of the focus tracker to remove
150  *
151  * Deprecated: This method is deprecated since ATK version
152  * 2.9.4. Focus tracking has been dropped as a feature to be
153  * implemented by ATK itself. If you need focus tracking on your
154  * implementation, subscribe to the state-changed:focused signal.
155  *
156  * Removes the specified focus tracker from the list of functions
157  * to be called when any object receives focus.
158  **/
159 void
160 atk_remove_focus_tracker (guint            tracker_id)
161 {
162   FocusTracker *item;
163   guint i;
164
165   if (trackers == NULL)
166     return;
167
168   if (tracker_id == 0)
169     return;
170
171   for (i = 0; i < trackers->len; i++)
172   {
173     item = &g_array_index (trackers, FocusTracker, i);
174     if (item->index == tracker_id)
175     {
176       trackers = g_array_remove_index (trackers, i);
177       break;
178     }
179   }
180 }
181
182 /**
183  * atk_focus_tracker_notify:
184  * @object: an #AtkObject
185  *
186  * Cause the focus tracker functions which have been specified to be
187  * executed for the object.
188  *
189  * Deprecated: This method is deprecated since ATK version
190  * 2.9.4. Focus tracking has been dropped as a feature to be
191  * implemented by ATK itself.
192  *
193  **/
194 void
195 atk_focus_tracker_notify (AtkObject       *object)
196 {
197   FocusTracker *item;
198   guint i;
199
200   if (trackers == NULL)
201     return;
202
203   if (object == previous_focus_object)
204     return;
205   else
206     {
207       if (previous_focus_object)
208         g_object_unref (previous_focus_object);
209
210       previous_focus_object = object;
211       if (object)
212         {
213           g_object_ref (object);
214
215           for (i = 0; i < trackers->len; i++)
216             {
217               item = &g_array_index (trackers, FocusTracker, i);
218               g_return_if_fail (item != NULL);
219               item->func (object);
220             }
221         }
222     
223     }
224 }
225
226 static guint
227 add_listener (GSignalEmissionHook listener,
228               const gchar         *object_type,
229               const gchar         *signal_name,
230               const gchar         *detail_string,
231               const gchar         *hook_data)
232 {
233   GType type;
234   guint signal_id;
235   gint  rc = 0;
236   static gint listener_idx = 1;
237   GQuark detail_quark = 0;
238
239   type = g_type_from_name (object_type);
240   if (type)
241     {
242       signal_id  = g_signal_lookup (signal_name, type);
243       detail_quark = g_quark_from_string (detail_string);
244
245       if (signal_id > 0)
246         {
247           AtkUtilListenerInfo *listener_info;
248
249           rc = listener_idx;
250
251           listener_info = g_new (AtkUtilListenerInfo, 1);
252           listener_info->key = listener_idx;
253           listener_info->hook_id =
254             g_signal_add_emission_hook (signal_id, detail_quark, listener,
255                                         g_strdup (hook_data),
256                                         (GDestroyNotify) g_free);
257           listener_info->signal_id = signal_id;
258
259           g_hash_table_insert(listener_list, &(listener_info->key), listener_info);
260           listener_idx++;
261         }
262       else
263         {
264           g_debug ("Signal type %s not supported\n", signal_name);
265         }
266     }
267   else
268     {
269       g_warning("Invalid object type %s\n", object_type);
270     }
271   return rc;
272 }
273
274 static guint
275 atk_util_real_add_global_event_listener (GSignalEmissionHook listener,
276                                          const gchar *event_type)
277 {
278   guint rc = 0;
279   gchar **split_string;
280   guint length;
281
282   split_string = g_strsplit (event_type, ":", 0);
283   length = g_strv_length (split_string);
284
285   if ((length == 3) || (length == 4))
286     rc = add_listener (listener, split_string[1], split_string[2],
287                        split_string[3], event_type);
288
289   g_strfreev (split_string);
290
291   return rc;
292 }
293
294 static void
295 atk_util_real_remove_global_event_listener (guint remove_listener)
296 {
297   if (remove_listener > 0)
298     {
299       AtkUtilListenerInfo *listener_info;
300       gint tmp_idx = remove_listener;
301
302       listener_info = (AtkUtilListenerInfo *)
303         g_hash_table_lookup(listener_list, &tmp_idx);
304
305       if (listener_info != NULL)
306         {
307           /* Hook id of 0 and signal id of 0 are invalid */
308           if (listener_info->hook_id != 0 && listener_info->signal_id != 0)
309             {
310               /* Remove the emission hook */
311               g_signal_remove_emission_hook(listener_info->signal_id,
312                                             listener_info->hook_id);
313
314               /* Remove the element from the hash */
315               g_hash_table_remove(listener_list, &tmp_idx);
316             }
317           else
318             {
319               g_warning("Invalid listener hook_id %ld or signal_id %d\n",
320                         listener_info->hook_id, listener_info->signal_id);
321             }
322         }
323       else
324         {
325           g_warning("No listener with the specified listener id %d",
326                     remove_listener);
327         }
328     }
329   else
330     {
331       g_warning("Invalid listener_id %d", remove_listener);
332     }
333 }
334
335
336 /**
337  * atk_add_global_event_listener:
338  * @listener: the listener to notify
339  * @event_type: the type of event for which notification is requested
340  *
341  * Adds the specified function to the list of functions to be called
342  * when an ATK event of type event_type occurs.
343  *
344  * The format of event_type is the following:
345  *  "ATK:<atk_type>:<atk_event>:<atk_event_detail>
346  *
347  * Where "ATK" works as the namespace, <atk_interface> is the name of
348  * the ATK type (interface or object), <atk_event> is the name of the
349  * signal defined on that interface and <atk_event_detail> is the
350  * gsignal detail of that signal. You can find more info about gsignal
351  * details here:
352  * http://developer.gnome.org/gobject/stable/gobject-Signals.html
353  *
354  * The first three parameters are mandatory. The last one is optional.
355  *
356  * For example:
357  *   ATK:AtkObject:state-change
358  *   ATK:AtkText:text-selection-changed
359  *   ATK:AtkText:text-insert:system
360  *
361  * Toolkit implementor note: Atk provides a default implementation for
362  * this virtual method, and that implementation should be enough for
363  * most of the cases. You should have a really good reason to
364  * reimplement this method.
365  *
366  * Returns: added event listener id, or 0 on failure.
367  **/
368 guint
369 atk_add_global_event_listener (GSignalEmissionHook listener,
370                                const gchar        *event_type)
371 {
372   guint retval;
373   AtkUtilClass *klass = g_type_class_ref (ATK_TYPE_UTIL);
374
375   if (klass->add_global_event_listener)
376     {
377       retval = klass->add_global_event_listener (listener, event_type);
378     }
379   else
380     {
381       retval = 0;
382     }
383   g_type_class_unref (klass);
384
385   return retval;
386 }
387
388 /**
389  * atk_remove_global_event_listener:
390  * @listener_id: the id of the event listener to remove
391  *
392  * @listener_id is the value returned by #atk_add_global_event_listener
393  * when you registered that event listener.
394  *
395  * Toolkit implementor note: Atk provides a default implementation for
396  * this virtual method, and that implementation should be enough for
397  * most of the cases. You should have a really good reason to
398  * reimplement this method.
399  *
400  * Removes the specified event listener
401  **/
402 void
403 atk_remove_global_event_listener (guint listener_id)
404 {
405   AtkUtilClass *klass = g_type_class_peek (ATK_TYPE_UTIL);
406
407   if (klass && klass->remove_global_event_listener)
408     klass->remove_global_event_listener (listener_id);
409 }
410
411 /**
412  * atk_add_key_event_listener:
413  * @listener: the listener to notify
414  * @data: a #gpointer that points to a block of data that should be sent to the registered listeners,
415  *        along with the event notification, when it occurs.  
416  *
417  * Adds the specified function to the list of functions to be called
418  *        when a key event occurs.  The @data element will be passed to the
419  *        #AtkKeySnoopFunc (@listener) as the @func_data param, on notification.
420  *
421  * Returns: added event listener id, or 0 on failure.
422  **/
423 guint
424 atk_add_key_event_listener (AtkKeySnoopFunc listener, gpointer data)
425 {
426   guint retval;
427   AtkUtilClass *klass = g_type_class_peek (ATK_TYPE_UTIL);
428   if (klass && klass->add_key_event_listener)
429     {
430       retval = klass->add_key_event_listener (listener, data);
431     }
432   else
433     {
434       retval = 0;
435     }
436
437   return retval;
438 }
439
440 /**
441  * atk_remove_key_event_listener:
442  * @listener_id: the id of the event listener to remove
443  *
444  * @listener_id is the value returned by #atk_add_key_event_listener
445  * when you registered that event listener.
446  *
447  * Removes the specified event listener.
448  **/
449 void
450 atk_remove_key_event_listener (guint listener_id)
451 {
452   AtkUtilClass *klass = g_type_class_peek (ATK_TYPE_UTIL);
453
454   if (klass->remove_key_event_listener)
455     klass->remove_key_event_listener (listener_id);
456 }
457
458 /**
459  * atk_get_root:
460  *
461  * Gets the root accessible container for the current application.
462  *
463  * Returns: (transfer none): the root accessible container for the current
464  * application
465  **/
466 AtkObject*
467 atk_get_root (void)
468 {
469   AtkUtilClass *klass = g_type_class_ref (ATK_TYPE_UTIL);
470   AtkObject    *retval;
471   if (klass->get_root)
472     {
473       retval = klass->get_root ();
474     }
475   else
476     {
477       retval = NULL;
478     }
479   g_type_class_unref (klass);
480
481   return retval;
482 }
483
484 /**
485  * atk_get_focus_object:
486  *
487  * Gets the currently focused object.
488  * 
489  * Since: 1.6
490  *
491  * Returns: (transfer none): the currently focused object for the current
492  * application
493  **/
494 AtkObject*
495 atk_get_focus_object (void)
496 {
497   return previous_focus_object;
498 }
499
500 /**
501  * atk_get_toolkit_name:
502  *
503  * Gets name string for the GUI toolkit implementing ATK for this application.
504  *
505  * Returns: name string for the GUI toolkit implementing ATK for this application
506  **/
507 const gchar*
508 atk_get_toolkit_name (void)
509 {
510   const gchar *retval;
511   AtkUtilClass *klass = g_type_class_ref (ATK_TYPE_UTIL);
512   if (klass->get_toolkit_name)
513     {
514       retval = klass->get_toolkit_name ();
515     }
516   else
517     {
518       retval = NULL;
519     }
520   g_type_class_unref (klass);
521
522   return retval;
523 }
524
525 /**
526  * atk_get_toolkit_version:
527  *
528  * Gets version string for the GUI toolkit implementing ATK for this application.
529  *
530  * Returns: version string for the GUI toolkit implementing ATK for this application
531  **/
532 const gchar*
533 atk_get_toolkit_version (void)
534 {
535   const gchar *retval;
536   AtkUtilClass *klass = g_type_class_ref (ATK_TYPE_UTIL);
537   if (klass->get_toolkit_version)
538     {
539       retval = klass->get_toolkit_version ();
540     }
541   else
542     {
543       retval = NULL;
544     }
545   g_type_class_unref (klass);
546
547   return retval;
548 }
549
550 /**
551  * atk_get_version:
552  *
553  * Gets the current version for ATK.
554  *
555  * Returns: version string for ATK
556  *
557  * Since: 1.20
558  */
559 const gchar *
560 atk_get_version (void)
561 {
562   return VERSION;
563 }
564
565 static void
566 atk_util_class_init (AtkUtilClass *klass)
567 {
568   klass->add_global_event_listener = atk_util_real_add_global_event_listener;
569   klass->remove_global_event_listener = atk_util_real_remove_global_event_listener;
570   klass->get_root = NULL;
571   klass->get_toolkit_name = NULL;
572   klass->get_toolkit_version = NULL;
573
574   listener_list = g_hash_table_new_full (g_int_hash, g_int_equal, NULL,
575                                          g_free);
576 }