* cspi/spi_accessible.c
[platform/core/uifw/at-spi2-atk.git] / libspi / application.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2001, 2002 Sun Microsystems Inc.,
6  * Copyright 2001, 2002 Ximian, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /* application.c: implements SpiApplication.idl */
25
26 #include <string.h>
27 #include <config.h>
28 #include <atk/atkutil.h>
29 #include <libspi/application.h>
30 #include "spi-private.h"
31
32 /* Our parent Gtk object type */
33 #define PARENT_TYPE SPI_ACCESSIBLE_TYPE
34
35 /* A pointer to our parent object class */
36 static SpiAccessibleClass *spi_application_parent_class;
37
38 static SpiApplication *the_app;
39
40 /* static methods */
41
42 static void notify_listeners (GList *listeners,
43                               SpiAccessible *source,
44                               Accessibility_Event *e);
45
46 static const char *reverse_lookup_name_for_toolkit_event (char *toolkit_name);
47
48 static const char *
49 lookup_toolkit_event_for_name (const char *generic_name)
50 {
51   char *toolkit_specific_name;
52   SpiApplicationClass *klass = g_type_class_peek (SPI_APPLICATION_TYPE);
53 #ifdef SPI_DEBUG
54   fprintf (stderr, "looking for %s in hash table.\n", generic_name);
55 #endif
56   toolkit_specific_name =
57     (char *) g_hash_table_lookup (klass->toolkit_event_names, generic_name);
58 #ifdef SPI_DEBUG
59   fprintf (stderr, "generic event %s converted to %s\n", generic_name, toolkit_specific_name);
60 #endif
61   return toolkit_specific_name;
62 }
63
64 /*
65  * Implemented GObject::finalize
66  */
67 static void
68 spi_accessible_application_finalize (GObject *object)
69 {
70   GList *l;
71   SpiApplication *application = (SpiApplication *) object;
72   CORBA_Environment ev;
73
74   CORBA_exception_init (&ev);
75
76   for (l = application->toolkit_listeners; l; l = l->next)
77     {
78       CORBA_Object_release ((CORBA_Object) l->data, &ev);
79     }
80
81   CORBA_exception_free (&ev);
82
83   g_list_free (application->toolkit_listeners);
84   application->toolkit_listeners = NULL;
85
86   g_print ("application finalize called\n");
87   (G_OBJECT_CLASS (spi_application_parent_class))->finalize (object);
88 }
89
90 static CORBA_string
91 impl_accessibility_application_get_toolkit_name (PortableServer_Servant servant,
92                                                  CORBA_Environment     *ev)
93 {
94   return CORBA_string_dup (atk_get_toolkit_name ());
95 }
96
97 static CORBA_string
98 impl_accessibility_application_get_version (PortableServer_Servant servant,
99                                             CORBA_Environment     *ev)
100 {
101   return CORBA_string_dup (atk_get_toolkit_version ());
102 }
103
104 static CORBA_long
105 impl_accessibility_application_get_id (PortableServer_Servant servant,
106                                        CORBA_Environment     *ev)
107 {
108   SpiApplication *application = SPI_APPLICATION (
109     bonobo_object_from_servant (servant));
110
111   return application->id;
112 }
113
114 static void
115 impl_accessibility_application_set_id (PortableServer_Servant servant,
116                                        const CORBA_long id,
117                                        CORBA_Environment *ev)
118 {
119   SpiApplication *application = SPI_APPLICATION (
120     bonobo_object_from_servant (servant));
121
122   application->id = id;
123 }
124
125 static AtkObject *
126 get_atk_object_ref (GObject *gobject)
127 {
128   AtkObject *aobject;
129
130   if (ATK_IS_IMPLEMENTOR (gobject))
131     {
132       aobject = atk_implementor_ref_accessible (ATK_IMPLEMENTOR (gobject));
133     }
134   else if (ATK_IS_OBJECT (gobject))
135     {
136       aobject = ATK_OBJECT (gobject);
137       g_object_ref (G_OBJECT (aobject));
138     }
139   else
140     {
141       aobject = NULL;
142       g_error ("received event from non-AtkImplementor");
143     }
144
145   return aobject;
146 }
147
148 static gboolean
149 spi_application_object_event_listener (GSignalInvocationHint *signal_hint,
150                                        guint                   n_param_values,
151                                        const GValue           *param_values,
152                                        gpointer                data)
153 {
154   Accessibility_Event e;
155   AtkObject     *aobject;
156   SpiAccessible *source;
157   GSignalQuery   signal_query;
158   gchar         *event_name;
159   const char    *generic_name;
160
161   g_return_val_if_fail (the_app != NULL, FALSE);
162   
163   g_signal_query (signal_hint->signal_id, &signal_query);
164
165   /* TODO: move GTK reference out of app.c into bridge */
166   event_name = g_strdup_printf ("Gtk:%s:%s",
167                                 g_type_name (signal_query.itype),
168                                 signal_query.signal_name);
169
170   generic_name = reverse_lookup_name_for_toolkit_event (event_name);
171
172   fprintf (stderr, "Received (object) signal %s maps to '%s'\n",
173            event_name, generic_name);
174
175   g_free (event_name);
176
177   g_return_val_if_fail (generic_name, FALSE);
178
179   aobject = get_atk_object_ref (g_value_get_object (param_values + 0));
180
181   source = spi_accessible_new (aobject);
182   e.type = CORBA_string_dup (generic_name);
183   e.source = CORBA_OBJECT_NIL;
184   e.detail1 = 0;
185   e.detail2 = 0;
186   spi_init_any_nil (&e.any_data);
187   notify_listeners (the_app->toolkit_listeners, source, &e);
188
189   bonobo_object_unref (BONOBO_OBJECT (source));
190
191   g_object_unref (G_OBJECT (aobject));
192
193   return TRUE;
194 }
195
196 static gboolean
197 spi_application_toolkit_event_listener (GSignalInvocationHint *signal_hint,
198                                         guint                  n_param_values,
199                                         const GValue          *param_values,
200                                         gpointer               data)
201 {
202   Accessibility_Event e;
203   AtkObject      *aobject;
204   SpiAccessible *source;
205   GSignalQuery   signal_query;
206   char          *event_name;
207
208   g_return_val_if_fail (the_app != NULL, FALSE);
209
210   g_signal_query (signal_hint->signal_id, &signal_query);
211
212   /* TODO: move GTK reference out of app.c into bridge */
213   event_name = g_strdup_printf ("Gtk:%s:%s",
214                                 g_type_name (signal_query.itype), 
215                                 signal_query.signal_name);
216
217 #ifdef SPI_DEBUG  
218   fprintf (stderr, "Received signal %s\n", event_name);
219 #endif
220   
221   aobject = get_atk_object_ref (g_value_get_object (param_values + 0));
222
223   source = spi_accessible_new (aobject);
224   e.type = CORBA_string_dup (event_name);
225   e.source = CORBA_OBJECT_NIL;
226   e.detail1 = 0;
227   e.detail2 = 0;
228   spi_init_any_nil (&e.any_data);
229   notify_listeners (the_app->toolkit_listeners, source, &e);
230
231   bonobo_object_unref (BONOBO_OBJECT (source));
232   g_object_unref (G_OBJECT (aobject));
233
234   g_free (event_name);
235
236   return TRUE;
237 }
238
239 static void
240 impl_accessibility_application_register_toolkit_event_listener (PortableServer_Servant servant,
241                                                                 Accessibility_EventListener listener,
242                                                                 const CORBA_char *event_name,
243                                                                 CORBA_Environment *ev)
244 {
245   guint spi_listener_id;
246   spi_listener_id =
247      atk_add_global_event_listener (spi_application_toolkit_event_listener, event_name);
248   the_app->toolkit_listeners = g_list_append (the_app->toolkit_listeners,
249                                               CORBA_Object_duplicate (listener, ev));
250 #ifdef SPI_DEBUG
251   fprintf (stderr, "registered %d for toolkit events named: %s\n",
252            spi_listener_id,
253            event_name);
254 #endif
255 }
256
257 static void
258 impl_accessibility_application_register_object_event_listener (PortableServer_Servant servant,
259                                                                Accessibility_EventListener listener,
260                                                                const CORBA_char *event_name,
261                                                                CORBA_Environment *ev)
262 {
263   guint spi_listener_id = 0;
264   const char *toolkit_specific_event_name =
265           lookup_toolkit_event_for_name (event_name);
266   if (toolkit_specific_event_name)
267   {
268     spi_listener_id =
269        atk_add_global_event_listener (spi_application_object_event_listener,
270                                       toolkit_specific_event_name);
271     the_app->toolkit_listeners = g_list_append (the_app->toolkit_listeners,
272                                               CORBA_Object_duplicate (listener, ev));
273   }
274 #ifdef SPI_DEBUG
275   fprintf (stderr, "registered %d for object events named: %s\n",
276            spi_listener_id,
277            event_name);
278 #endif
279 }
280
281 static void
282 notify_listeners (GList *listeners, SpiAccessible *source, Accessibility_Event *e)
283 {
284   GList *l;
285   CORBA_Environment ev;
286
287   CORBA_exception_init (&ev);
288
289   for (l = listeners; l; l = l->next)
290     {
291       Accessibility_EventListener listener = l->data;
292
293       e->source = bonobo_object_dup_ref (BONOBO_OBJREF (source), &ev);
294
295       Accessibility_EventListener_notifyEvent (listener, e, &ev);
296       /*
297        * when this (oneway) call completes, the CORBA refcount and
298        * Bonobo_Unknown refcount will be decremented by the recipient
299        */
300       CORBA_exception_free (&ev);
301     }
302 }
303
304 static const char *
305 reverse_lookup_name_for_toolkit_event (char *toolkit_specific_name)
306 {
307     const char *generic_name;
308     SpiApplicationClass *klass = g_type_class_peek (SPI_APPLICATION_TYPE);
309 #ifdef SPI_DEBUG
310     fprintf (stderr, "(reverse lookup) looking for %s in hash table.\n", toolkit_specific_name);
311 #endif
312     generic_name =
313             (const char *) g_hash_table_lookup (klass->generic_event_names, toolkit_specific_name);
314 #ifdef SPI_DEBUG
315     fprintf (stderr, "toolkit event %s converted to %s\n", toolkit_specific_name, generic_name);
316 #endif
317     return generic_name;
318 }
319
320 static void
321 init_toolkit_names (GHashTable **generic_event_names, GHashTable **toolkit_event_names)
322 {
323         *toolkit_event_names = g_hash_table_new (g_str_hash, g_str_equal);
324         *generic_event_names = g_hash_table_new (g_str_hash, g_str_equal);
325         g_hash_table_insert (*toolkit_event_names,
326                              "object:property-change",
327                              "Gtk:AtkObject:property-change");
328         g_hash_table_insert (*generic_event_names,
329                              "Gtk:AtkObject:property-change",
330                              "object:property-change");
331 #ifdef SPI_DEBUG
332         fprintf (stderr, "inserted spi_selection_changed hash\n");
333 #endif
334 }
335
336 static void
337 spi_application_class_init (SpiApplicationClass *klass)
338 {
339   GObjectClass * object_class = (GObjectClass *) klass;
340   POA_Accessibility_Application__epv *epv = &klass->epv;
341
342   spi_application_parent_class = g_type_class_ref (SPI_ACCESSIBLE_TYPE);
343
344   object_class->finalize = spi_accessible_application_finalize;
345
346   epv->_get_toolkitName = impl_accessibility_application_get_toolkit_name;
347   epv->_get_version = impl_accessibility_application_get_version;
348   epv->_get_id = impl_accessibility_application_get_id;
349   epv->_set_id = impl_accessibility_application_set_id;
350   epv->registerToolkitEventListener = impl_accessibility_application_register_toolkit_event_listener;
351   init_toolkit_names (&klass->generic_event_names, &klass->toolkit_event_names);
352 }
353
354 static void
355 spi_application_init (SpiApplication *application)
356 {
357   application->toolkit_listeners = NULL;
358   the_app = application;
359 }
360
361 BONOBO_TYPE_FUNC_FULL (SpiApplication,
362                        Accessibility_Application,
363                        PARENT_TYPE, spi_application);
364
365 SpiApplication *
366 spi_application_new (AtkObject *app_root)
367 {
368   return SPI_APPLICATION (spi_accessible_construct (
369         SPI_APPLICATION_TYPE, app_root));
370 }