1 | /* |
---|
2 | * AT-SPI - Assistive Technology Service Provider Interface |
---|
3 | * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap) |
---|
4 | * |
---|
5 | * Copyright 2001 Sun Microsystems Inc. |
---|
6 | * |
---|
7 | * This library is free software; you can redistribute it and/or |
---|
8 | * modify it under the terms of the GNU Library General Public |
---|
9 | * License as published by the Free Software Foundation; either |
---|
10 | * version 2 of the License, or (at your option) any later version. |
---|
11 | * |
---|
12 | * This library is distributed in the hope that it will be useful, |
---|
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
15 | * Library General Public License for more details. |
---|
16 | * |
---|
17 | * You should have received a copy of the GNU Library General Public |
---|
18 | * License along with this library; if not, write to the |
---|
19 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
---|
20 | * Boston, MA 02111-1307, USA. |
---|
21 | */ |
---|
22 | |
---|
23 | #include <stdio.h> |
---|
24 | #include <stdlib.h> |
---|
25 | #include <stdarg.h> |
---|
26 | #include <libbonobo.h> |
---|
27 | #include <orbit/orbit.h> |
---|
28 | #include <atk/atk.h> |
---|
29 | #include <atk/atkobject.h> |
---|
30 | #include <atk/atknoopobject.h> |
---|
31 | #include <libspi/Accessibility.h> |
---|
32 | #include "accessible.h" |
---|
33 | #include "application.h" |
---|
34 | |
---|
35 | #include <bonobo-activation/bonobo-activation-register.h> |
---|
36 | |
---|
37 | #undef SPI_BRIDGE_DEBUG |
---|
38 | |
---|
39 | static CORBA_Environment ev; |
---|
40 | static Accessibility_Registry registry = NULL; |
---|
41 | static SpiApplication *this_app = NULL; |
---|
42 | static gboolean registry_died = FALSE; |
---|
43 | |
---|
44 | static Accessibility_Registry spi_atk_bridge_get_registry (void); |
---|
45 | static void spi_atk_bridge_exit_func (void); |
---|
46 | static void spi_atk_register_event_listeners (void); |
---|
47 | static void spi_atk_bridge_focus_tracker (AtkObject *object); |
---|
48 | static void spi_atk_bridge_register_application (Accessibility_Registry registry); |
---|
49 | static gboolean spi_atk_bridge_property_event_listener (GSignalInvocationHint *signal_hint, |
---|
50 | guint n_param_values, |
---|
51 | const GValue *param_values, |
---|
52 | gpointer data); |
---|
53 | static gboolean |
---|
54 | spi_atk_bridge_window_event_listener (GSignalInvocationHint *signal_hint, |
---|
55 | guint n_param_values, |
---|
56 | const GValue *param_values, |
---|
57 | gpointer data); |
---|
58 | static gboolean |
---|
59 | spi_atk_bridge_state_event_listener (GSignalInvocationHint *signal_hint, |
---|
60 | guint n_param_values, |
---|
61 | const GValue *param_values, |
---|
62 | gpointer data); |
---|
63 | static gboolean spi_atk_bridge_signal_listener (GSignalInvocationHint *signal_hint, |
---|
64 | guint n_param_values, |
---|
65 | const GValue *param_values, |
---|
66 | gpointer data); |
---|
67 | static gint spi_atk_bridge_key_listener (AtkKeyEventStruct *event, |
---|
68 | gpointer data); |
---|
69 | |
---|
70 | /* For automatic libgnome init */ |
---|
71 | extern void gnome_accessibility_module_init (void); |
---|
72 | extern void gnome_accessibility_module_shutdown (void); |
---|
73 | |
---|
74 | static int atk_bridge_initialized = FALSE; |
---|
75 | static guint atk_bridge_focus_tracker_id = 0; |
---|
76 | static guint atk_bridge_key_event_listener_id = 0; |
---|
77 | static GArray *listener_ids = NULL; |
---|
78 | |
---|
79 | /* |
---|
80 | * These exported symbols are hooked by gnome-program |
---|
81 | * to provide automatic module initialization and shutdown. |
---|
82 | */ |
---|
83 | extern void gnome_accessibility_module_init (void); |
---|
84 | extern void gnome_accessibility_module_shutdown (void); |
---|
85 | |
---|
86 | static int |
---|
87 | atk_bridge_init (gint *argc, gchar **argv[]) |
---|
88 | { |
---|
89 | CORBA_Environment ev; |
---|
90 | |
---|
91 | if (atk_bridge_initialized) |
---|
92 | { |
---|
93 | return 0; |
---|
94 | } |
---|
95 | atk_bridge_initialized = TRUE; |
---|
96 | |
---|
97 | if (!bonobo_init (argc, argv ? *argv : NULL)) |
---|
98 | { |
---|
99 | g_error ("Could not initialize Bonobo"); |
---|
100 | } |
---|
101 | |
---|
102 | /* |
---|
103 | * We only want to enable the bridge for top level |
---|
104 | * applications, we detect bonobo components by seeing |
---|
105 | * if they were activated with the intention of extracting |
---|
106 | * an impl. by IID - very solid. |
---|
107 | */ |
---|
108 | if (bonobo_activation_iid_get ()) |
---|
109 | return 0; |
---|
110 | |
---|
111 | CORBA_exception_init(&ev); |
---|
112 | |
---|
113 | if (spi_atk_bridge_get_registry () == CORBA_OBJECT_NIL) |
---|
114 | { |
---|
115 | g_error ("Could not locate registry"); |
---|
116 | } |
---|
117 | |
---|
118 | bonobo_activate (); |
---|
119 | |
---|
120 | /* Create the accessible application server object */ |
---|
121 | |
---|
122 | this_app = spi_application_new (atk_get_root ()); |
---|
123 | |
---|
124 | fprintf (stderr, "About to register application\n"); |
---|
125 | |
---|
126 | spi_atk_bridge_register_application (spi_atk_bridge_get_registry ()); |
---|
127 | |
---|
128 | g_atexit (spi_atk_bridge_exit_func); |
---|
129 | |
---|
130 | fprintf (stderr, "Application registered & listening\n"); |
---|
131 | |
---|
132 | return 0; |
---|
133 | } |
---|
134 | |
---|
135 | static void |
---|
136 | spi_atk_bridge_register_application (Accessibility_Registry registry) |
---|
137 | { |
---|
138 | Accessibility_Registry_registerApplication (spi_atk_bridge_get_registry (), |
---|
139 | BONOBO_OBJREF (this_app), |
---|
140 | &ev); |
---|
141 | spi_atk_register_event_listeners (); |
---|
142 | } |
---|
143 | |
---|
144 | static Accessibility_Registry |
---|
145 | spi_atk_bridge_get_registry () |
---|
146 | { |
---|
147 | CORBA_Environment ev; |
---|
148 | |
---|
149 | if (registry_died || (registry == NULL)) { |
---|
150 | CORBA_exception_init (&ev); |
---|
151 | if (registry_died) g_warning ("registry died! restarting..."); |
---|
152 | registry = bonobo_activation_activate_from_id ( |
---|
153 | "OAFIID:Accessibility_Registry:1.0", 0, NULL, &ev); |
---|
154 | |
---|
155 | if (ev._major != CORBA_NO_EXCEPTION) |
---|
156 | { |
---|
157 | g_error ("Accessibility app error: exception during " |
---|
158 | "registry activation from id: %s\n", |
---|
159 | CORBA_exception_id (&ev)); |
---|
160 | CORBA_exception_free (&ev); |
---|
161 | } |
---|
162 | |
---|
163 | if (registry_died && registry) { |
---|
164 | registry_died = FALSE; |
---|
165 | spi_atk_bridge_register_application (registry); |
---|
166 | } |
---|
167 | } |
---|
168 | return registry; |
---|
169 | } |
---|
170 | |
---|
171 | int |
---|
172 | gtk_module_init (gint *argc, gchar **argv[]) |
---|
173 | { |
---|
174 | return atk_bridge_init (argc, argv); |
---|
175 | } |
---|
176 | |
---|
177 | static void |
---|
178 | add_signal_listener (const char *signal_name) |
---|
179 | { |
---|
180 | guint id; |
---|
181 | |
---|
182 | id = atk_add_global_event_listener ( |
---|
183 | spi_atk_bridge_signal_listener, signal_name); |
---|
184 | |
---|
185 | g_array_append_val (listener_ids, id); |
---|
186 | } |
---|
187 | |
---|
188 | static void |
---|
189 | spi_atk_register_event_listeners (void) |
---|
190 | { |
---|
191 | /* |
---|
192 | * kludge to make sure the Atk interface types are registered, otherwise |
---|
193 | * the AtkText signal handlers below won't get registered |
---|
194 | */ |
---|
195 | guint id; |
---|
196 | GObject *ao = g_object_new (ATK_TYPE_OBJECT, NULL); |
---|
197 | AtkObject *bo = atk_no_op_object_new (ao); |
---|
198 | |
---|
199 | /* Register for focus event notifications, and register app with central registry */ |
---|
200 | |
---|
201 | listener_ids = g_array_sized_new (FALSE, TRUE, sizeof (guint), 16); |
---|
202 | |
---|
203 | atk_bridge_focus_tracker_id = atk_add_focus_tracker (spi_atk_bridge_focus_tracker); |
---|
204 | |
---|
205 | id = atk_add_global_event_listener (spi_atk_bridge_property_event_listener, |
---|
206 | "Gtk:AtkObject:property-change"); |
---|
207 | g_array_append_val (listener_ids, id); |
---|
208 | id = atk_add_global_event_listener (spi_atk_bridge_window_event_listener, |
---|
209 | "window:create"); |
---|
210 | g_array_append_val (listener_ids, id); |
---|
211 | id = atk_add_global_event_listener (spi_atk_bridge_window_event_listener, |
---|
212 | "window:destroy"); |
---|
213 | g_array_append_val (listener_ids, id); |
---|
214 | id = atk_add_global_event_listener (spi_atk_bridge_window_event_listener, |
---|
215 | "window:minimize"); |
---|
216 | g_array_append_val (listener_ids, id); |
---|
217 | id = atk_add_global_event_listener (spi_atk_bridge_window_event_listener, |
---|
218 | "window:maximize"); |
---|
219 | g_array_append_val (listener_ids, id); |
---|
220 | id = atk_add_global_event_listener (spi_atk_bridge_window_event_listener, |
---|
221 | "window:restore"); |
---|
222 | g_array_append_val (listener_ids, id); |
---|
223 | id = atk_add_global_event_listener (spi_atk_bridge_window_event_listener, |
---|
224 | "window:activate"); |
---|
225 | g_array_append_val (listener_ids, id); |
---|
226 | id = atk_add_global_event_listener (spi_atk_bridge_window_event_listener, |
---|
227 | "window:deactivate"); |
---|
228 | g_array_append_val (listener_ids, id); |
---|
229 | id = atk_add_global_event_listener (spi_atk_bridge_state_event_listener, |
---|
230 | "Gtk:AtkObject:state-change"); |
---|
231 | g_array_append_val (listener_ids, id); |
---|
232 | |
---|
233 | add_signal_listener ("Gtk:AtkObject:children-changed"); |
---|
234 | add_signal_listener ("Gtk:AtkObject:visible-data-changed"); |
---|
235 | add_signal_listener ("Gtk:AtkSelection:selection-changed"); |
---|
236 | add_signal_listener ("Gtk:AtkText:text-selection-changed"); |
---|
237 | add_signal_listener ("Gtk:AtkText:text-changed"); |
---|
238 | add_signal_listener ("Gtk:AtkText:text-caret-moved"); |
---|
239 | add_signal_listener ("Gtk:AtkTable:row-inserted"); |
---|
240 | add_signal_listener ("Gtk:AtkTable:row-reordered"); |
---|
241 | add_signal_listener ("Gtk:AtkTable:row-deleted"); |
---|
242 | add_signal_listener ("Gtk:AtkTable:column-inserted"); |
---|
243 | add_signal_listener ("Gtk:AtkTable:column-reordered"); |
---|
244 | add_signal_listener ("Gtk:AtkTable:column-deleted"); |
---|
245 | add_signal_listener ("Gtk:AtkTable:model-changed"); |
---|
246 | /* |
---|
247 | * May add the following listeners to implement preemptive key listening for GTK+ |
---|
248 | * |
---|
249 | * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-press-event"); |
---|
250 | * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-release-event"); |
---|
251 | */ |
---|
252 | atk_bridge_key_event_listener_id = atk_add_key_event_listener ( |
---|
253 | spi_atk_bridge_key_listener, NULL); |
---|
254 | |
---|
255 | g_object_unref (G_OBJECT (bo)); |
---|
256 | g_object_unref (ao); |
---|
257 | } |
---|
258 | |
---|
259 | static void |
---|
260 | deregister_application (BonoboObject *app) |
---|
261 | { |
---|
262 | Accessibility_Registry registry = spi_atk_bridge_get_registry (); |
---|
263 | Accessibility_Registry_deregisterApplication (registry, BONOBO_OBJREF (app), &ev); |
---|
264 | |
---|
265 | registry = bonobo_object_release_unref (registry, &ev); |
---|
266 | |
---|
267 | app = bonobo_object_unref (app); |
---|
268 | } |
---|
269 | |
---|
270 | static void |
---|
271 | spi_atk_bridge_exit_func (void) |
---|
272 | { |
---|
273 | BonoboObject *app = (BonoboObject *) this_app; |
---|
274 | |
---|
275 | fprintf (stderr, "exiting bridge\n"); |
---|
276 | |
---|
277 | if (!app) |
---|
278 | { |
---|
279 | return; |
---|
280 | } |
---|
281 | this_app = NULL; |
---|
282 | |
---|
283 | /* |
---|
284 | * FIXME: this may be incorrect for apps that do their own bonobo |
---|
285 | * shutdown, until we can explicitly shutdown to get the ordering |
---|
286 | * right. |
---|
287 | */ |
---|
288 | if (!bonobo_is_initialized ()) |
---|
289 | { |
---|
290 | fprintf (stderr, "Re-initializing bonobo\n"); |
---|
291 | g_assert (bonobo_init (0, NULL)); |
---|
292 | g_assert (bonobo_activate ()); |
---|
293 | } |
---|
294 | |
---|
295 | deregister_application (app); |
---|
296 | |
---|
297 | fprintf (stderr, "bridge exit func complete.\n"); |
---|
298 | |
---|
299 | if (g_getenv ("AT_BRIDGE_SHUTDOWN")) |
---|
300 | { |
---|
301 | g_assert (!bonobo_debug_shutdown ()); |
---|
302 | } |
---|
303 | } |
---|
304 | |
---|
305 | void |
---|
306 | gnome_accessibility_module_init (void) |
---|
307 | { |
---|
308 | atk_bridge_init (NULL, NULL); |
---|
309 | |
---|
310 | g_print("Atk Accessibilty bridge initialized\n"); |
---|
311 | } |
---|
312 | |
---|
313 | void |
---|
314 | gnome_accessibility_module_shutdown (void) |
---|
315 | { |
---|
316 | BonoboObject *app = (BonoboObject *) this_app; |
---|
317 | int i; |
---|
318 | GArray *ids = listener_ids; |
---|
319 | |
---|
320 | if (!atk_bridge_initialized) |
---|
321 | { |
---|
322 | return; |
---|
323 | } |
---|
324 | atk_bridge_initialized = FALSE; |
---|
325 | this_app = NULL; |
---|
326 | |
---|
327 | g_print("Atk Accessibilty bridge shutdown\n"); |
---|
328 | |
---|
329 | listener_ids = NULL; |
---|
330 | atk_remove_focus_tracker (atk_bridge_focus_tracker_id); |
---|
331 | |
---|
332 | for (i = 0; ids && i < ids->len; i++) |
---|
333 | { |
---|
334 | atk_remove_global_event_listener (g_array_index (ids, guint, i)); |
---|
335 | } |
---|
336 | |
---|
337 | atk_remove_key_event_listener (atk_bridge_key_event_listener_id); |
---|
338 | |
---|
339 | deregister_application (app); |
---|
340 | } |
---|
341 | |
---|
342 | static void |
---|
343 | spi_atk_bridge_focus_tracker (AtkObject *object) |
---|
344 | { |
---|
345 | SpiAccessible *source; |
---|
346 | Accessibility_Event e; |
---|
347 | |
---|
348 | source = spi_accessible_new (object); |
---|
349 | |
---|
350 | e.type = "focus:"; |
---|
351 | e.source = BONOBO_OBJREF (source); |
---|
352 | e.detail1 = 0; |
---|
353 | e.detail2 = 0; |
---|
354 | |
---|
355 | Accessibility_Registry_notifyEvent (spi_atk_bridge_get_registry (), &e, &ev); |
---|
356 | if (BONOBO_EX (&ev)) registry_died = TRUE; |
---|
357 | |
---|
358 | Accessibility_Accessible_unref (e.source, &ev); |
---|
359 | |
---|
360 | CORBA_exception_free (&ev); |
---|
361 | } |
---|
362 | |
---|
363 | static void |
---|
364 | spi_atk_emit_eventv (GObject *gobject, |
---|
365 | unsigned long detail1, |
---|
366 | unsigned long detail2, |
---|
367 | const char *format, ...) |
---|
368 | { |
---|
369 | va_list args; |
---|
370 | Accessibility_Event e; |
---|
371 | SpiAccessible *source; |
---|
372 | AtkObject *aobject; |
---|
373 | #ifdef SPI_BRIDGE_DEBUG |
---|
374 | CORBA_string s; |
---|
375 | #endif |
---|
376 | |
---|
377 | va_start (args, format); |
---|
378 | |
---|
379 | if (ATK_IS_IMPLEMENTOR (gobject)) |
---|
380 | { |
---|
381 | aobject = atk_implementor_ref_accessible (ATK_IMPLEMENTOR (gobject)); |
---|
382 | source = spi_accessible_new (aobject); |
---|
383 | g_object_unref (G_OBJECT (aobject)); |
---|
384 | } |
---|
385 | else if (ATK_IS_OBJECT (gobject)) |
---|
386 | { |
---|
387 | aobject = ATK_OBJECT (gobject); |
---|
388 | source = spi_accessible_new (aobject); |
---|
389 | } |
---|
390 | else |
---|
391 | { |
---|
392 | aobject = NULL; |
---|
393 | source = NULL; |
---|
394 | g_error ("received property-change event from non-AtkImplementor"); |
---|
395 | } |
---|
396 | |
---|
397 | if (source != NULL) |
---|
398 | { |
---|
399 | e.type = g_strdup_vprintf (format, args); |
---|
400 | e.source = BONOBO_OBJREF (source); |
---|
401 | e.detail1 = detail1; |
---|
402 | e.detail2 = detail2; |
---|
403 | |
---|
404 | #ifdef SPI_BRIDGE_DEBUG |
---|
405 | s = Accessibility_Accessible__get_name (BONOBO_OBJREF (source), &ev); |
---|
406 | g_warning ("Emitting event '%s' (%lu, %lu) on %s", |
---|
407 | e.type, e.detail1, e.detail2, s); |
---|
408 | CORBA_free (s); |
---|
409 | #endif |
---|
410 | |
---|
411 | Accessibility_Registry_notifyEvent (spi_atk_bridge_get_registry (), &e, &ev); |
---|
412 | #ifdef SPI_BRIDGE_DEBUG |
---|
413 | if (ev._major != CORBA_NO_EXCEPTION) |
---|
414 | g_warning ("error emitting event %s, (%d) %s", |
---|
415 | e.type, |
---|
416 | ev._major, |
---|
417 | CORBA_exception_id(&ev)); |
---|
418 | #endif |
---|
419 | if (BONOBO_EX (&ev)) registry_died = TRUE; |
---|
420 | Accessibility_Accessible_unref (e.source, &ev); |
---|
421 | |
---|
422 | CORBA_exception_free (&ev); |
---|
423 | |
---|
424 | g_free (e.type); |
---|
425 | } |
---|
426 | |
---|
427 | va_end (args); |
---|
428 | |
---|
429 | } |
---|
430 | |
---|
431 | static gboolean |
---|
432 | spi_atk_bridge_property_event_listener (GSignalInvocationHint *signal_hint, |
---|
433 | guint n_param_values, |
---|
434 | const GValue *param_values, |
---|
435 | gpointer data) |
---|
436 | { |
---|
437 | AtkPropertyValues *values; |
---|
438 | GObject *gobject; |
---|
439 | |
---|
440 | #ifdef SPI_BRIDGE_DEBUG |
---|
441 | GSignalQuery signal_query; |
---|
442 | const gchar *name; |
---|
443 | const gchar *s, *s2; |
---|
444 | |
---|
445 | g_signal_query (signal_hint->signal_id, &signal_query); |
---|
446 | name = signal_query.signal_name; |
---|
447 | |
---|
448 | s2 = g_type_name (G_OBJECT_TYPE (g_value_get_object (param_values + 0))); |
---|
449 | s = atk_object_get_name (ATK_OBJECT (g_value_get_object (param_values + 0))); |
---|
450 | values = (AtkPropertyValues*) g_value_get_pointer (param_values + 1); |
---|
451 | fprintf (stderr, "Received (property) signal %s:%s:%s from object %s (gail %s)\n", |
---|
452 | g_type_name (signal_query.itype), name, values->property_name, s, s2); |
---|
453 | |
---|
454 | #endif |
---|
455 | |
---|
456 | gobject = g_value_get_object (param_values + 0); |
---|
457 | values = (AtkPropertyValues*) g_value_get_pointer (param_values + 1); |
---|
458 | |
---|
459 | spi_atk_emit_eventv (gobject, 0, 0, "object:property-change:%s", values->property_name); |
---|
460 | |
---|
461 | return TRUE; |
---|
462 | } |
---|
463 | |
---|
464 | static gboolean |
---|
465 | spi_atk_bridge_state_event_listener (GSignalInvocationHint *signal_hint, |
---|
466 | guint n_param_values, |
---|
467 | const GValue *param_values, |
---|
468 | gpointer data) |
---|
469 | { |
---|
470 | GObject *gobject; |
---|
471 | gchar *property_name; |
---|
472 | gchar *type; |
---|
473 | unsigned long detail1; |
---|
474 | #ifdef SPI_BRIDGE_DEBUG |
---|
475 | GSignalQuery signal_query; |
---|
476 | const gchar *name; |
---|
477 | |
---|
478 | g_signal_query (signal_hint->signal_id, &signal_query); |
---|
479 | name = signal_query.signal_name; |
---|
480 | fprintf (stderr, "Received (state) signal %s:%s\n", |
---|
481 | g_type_name (signal_query.itype), name); |
---|
482 | #endif |
---|
483 | |
---|
484 | gobject = g_value_get_object (param_values + 0); |
---|
485 | property_name = g_strdup (g_value_get_string (param_values + 1)); |
---|
486 | detail1 = (g_value_get_boolean (param_values + 2)) |
---|
487 | ? 1 : 0; |
---|
488 | type = g_strdup_printf ("object:state-changed:%s", property_name); |
---|
489 | spi_atk_emit_eventv (gobject, |
---|
490 | detail1, |
---|
491 | 0, |
---|
492 | type); |
---|
493 | g_free (property_name); |
---|
494 | g_free (type); |
---|
495 | return TRUE; |
---|
496 | } |
---|
497 | |
---|
498 | |
---|
499 | static void |
---|
500 | spi_init_keystroke_from_atk_key_event (Accessibility_DeviceEvent *keystroke, |
---|
501 | AtkKeyEventStruct *event) |
---|
502 | { |
---|
503 | #ifdef SPI_DEBUG |
---|
504 | if (event) |
---|
505 | { |
---|
506 | g_print ("event %c (%d)\n", (int) event->keyval, (int) event->keycode); |
---|
507 | } |
---|
508 | else |
---|
509 | #endif |
---|
510 | if (!event) |
---|
511 | { |
---|
512 | g_print ("WARNING: NULL key event!"); |
---|
513 | } |
---|
514 | |
---|
515 | keystroke->id = (CORBA_long) event->keyval; |
---|
516 | keystroke->hw_code = (CORBA_short) event->keycode; |
---|
517 | keystroke->timestamp = (CORBA_unsigned_long) event->timestamp; |
---|
518 | keystroke->modifiers = (CORBA_unsigned_short) (event->state & 0xFFFF); |
---|
519 | if (event->string) |
---|
520 | { |
---|
521 | keystroke->event_string = CORBA_string_dup (event->string); |
---|
522 | keystroke->is_text = CORBA_TRUE; |
---|
523 | } |
---|
524 | else |
---|
525 | { |
---|
526 | keystroke->event_string = CORBA_string_dup (""); |
---|
527 | keystroke->is_text = CORBA_FALSE; |
---|
528 | } |
---|
529 | switch (event->type) |
---|
530 | { |
---|
531 | case (ATK_KEY_EVENT_PRESS): |
---|
532 | keystroke->type = Accessibility_KEY_PRESSED_EVENT; |
---|
533 | break; |
---|
534 | case (ATK_KEY_EVENT_RELEASE): |
---|
535 | keystroke->type = Accessibility_KEY_RELEASED_EVENT; |
---|
536 | break; |
---|
537 | default: |
---|
538 | keystroke->type = 0; |
---|
539 | break; |
---|
540 | } |
---|
541 | #if 0 |
---|
542 | g_print ("key_event type %d; val=%d code=%d modifiers=%x name=%s is_text=%d, time=%lx\n", |
---|
543 | (int) keystroke->type, (int) keystroke->id, (int) keystroke->hw_code, |
---|
544 | (int) keystroke->modifiers, |
---|
545 | keystroke->event_string, (int) keystroke->is_text, (unsigned long) keystroke->timestamp); |
---|
546 | #endif |
---|
547 | } |
---|
548 | |
---|
549 | static gint |
---|
550 | spi_atk_bridge_key_listener (AtkKeyEventStruct *event, gpointer data) |
---|
551 | { |
---|
552 | CORBA_boolean result; |
---|
553 | Accessibility_DeviceEvent key_event; |
---|
554 | Accessibility_DeviceEventController controller; |
---|
555 | |
---|
556 | if (BONOBO_EX (&ev)) |
---|
557 | g_warning ("failure: pre-listener get dec\n"); |
---|
558 | |
---|
559 | controller = |
---|
560 | Accessibility_Registry_getDeviceEventController ( |
---|
561 | spi_atk_bridge_get_registry (), &ev); |
---|
562 | |
---|
563 | if (BONOBO_EX (&ev)) |
---|
564 | { |
---|
565 | g_warning ("failure: no deviceeventcontroller found\n"); |
---|
566 | CORBA_exception_free (&ev); |
---|
567 | registry_died = TRUE; |
---|
568 | result = FALSE; |
---|
569 | } |
---|
570 | else |
---|
571 | { |
---|
572 | |
---|
573 | spi_init_keystroke_from_atk_key_event (&key_event, event); |
---|
574 | |
---|
575 | result = Accessibility_DeviceEventController_notifyListenersSync ( |
---|
576 | controller, &key_event, &ev); |
---|
577 | |
---|
578 | bonobo_object_release_unref (controller, &ev); |
---|
579 | CORBA_exception_free (&ev); |
---|
580 | } |
---|
581 | |
---|
582 | return result; |
---|
583 | } |
---|
584 | |
---|
585 | static gboolean |
---|
586 | spi_atk_bridge_signal_listener (GSignalInvocationHint *signal_hint, |
---|
587 | guint n_param_values, |
---|
588 | const GValue *param_values, |
---|
589 | gpointer data) |
---|
590 | { |
---|
591 | GObject *gobject; |
---|
592 | GSignalQuery signal_query; |
---|
593 | const gchar *name; |
---|
594 | const gchar *detail; |
---|
595 | |
---|
596 | gint detail1 = 0, detail2 = 0; |
---|
597 | #ifdef SPI_BRIDGE_DEBUG |
---|
598 | const gchar *s, *s2; |
---|
599 | #endif |
---|
600 | |
---|
601 | g_signal_query (signal_hint->signal_id, &signal_query); |
---|
602 | |
---|
603 | name = signal_query.signal_name; |
---|
604 | if (signal_hint->detail) |
---|
605 | detail = g_quark_to_string (signal_hint->detail); |
---|
606 | else |
---|
607 | detail = NULL; |
---|
608 | |
---|
609 | #ifdef SPI_BRIDGE_DEBUG |
---|
610 | s2 = g_type_name (G_OBJECT_TYPE (g_value_get_object (param_values + 0))); |
---|
611 | s = atk_object_get_name (ATK_OBJECT (g_value_get_object (param_values + 0))); |
---|
612 | fprintf (stderr, "Received signal %s:%s detail: %s from object %s (gail %s)\n", |
---|
613 | g_type_name (signal_query.itype), name, |
---|
614 | detail ? detail : "<NULL>", s ? s : "<NULL>" , s2); |
---|
615 | #endif |
---|
616 | |
---|
617 | gobject = g_value_get_object (param_values + 0); |
---|
618 | if (G_VALUE_TYPE (param_values + 1) == G_TYPE_INT) |
---|
619 | detail1 = g_value_get_int (param_values + 1); |
---|
620 | if (G_VALUE_TYPE (param_values + 2) == G_TYPE_INT) |
---|
621 | detail2 = g_value_get_int (param_values + 2); |
---|
622 | |
---|
623 | if (detail) |
---|
624 | spi_atk_emit_eventv (gobject, detail1, detail2, "object:%s:%s", name, detail); |
---|
625 | else |
---|
626 | spi_atk_emit_eventv (gobject, detail1, detail2, "object:%s", name); |
---|
627 | |
---|
628 | return TRUE; |
---|
629 | } |
---|
630 | |
---|
631 | static gboolean |
---|
632 | spi_atk_bridge_window_event_listener (GSignalInvocationHint *signal_hint, |
---|
633 | guint n_param_values, |
---|
634 | const GValue *param_values, |
---|
635 | gpointer data) |
---|
636 | { |
---|
637 | GObject *gobject; |
---|
638 | GSignalQuery signal_query; |
---|
639 | const gchar *name; |
---|
640 | #ifdef SPI_BRIDGE_DEBUG |
---|
641 | const gchar *s, *s2; |
---|
642 | #endif |
---|
643 | |
---|
644 | g_signal_query (signal_hint->signal_id, &signal_query); |
---|
645 | |
---|
646 | name = signal_query.signal_name; |
---|
647 | |
---|
648 | #ifdef SPI_BRIDGE_DEBUG |
---|
649 | s2 = g_type_name (G_OBJECT_TYPE (g_value_get_object (param_values + 0))); |
---|
650 | s = atk_object_get_name (ATK_OBJECT (g_value_get_object (param_values + 0))); |
---|
651 | fprintf (stderr, "Received signal %s:%s from object %s (gail %s)\n", |
---|
652 | g_type_name (signal_query.itype), name, s ? s : "<NULL>" , s2); |
---|
653 | #endif |
---|
654 | |
---|
655 | gobject = g_value_get_object (param_values + 0); |
---|
656 | spi_atk_emit_eventv (gobject, 0, 0, "window:%s", name); |
---|
657 | |
---|
658 | return TRUE; |
---|
659 | } |
---|