Merge branch 'enum-types'
[platform/upstream/at-spi2-core.git] / atspi / atspi-registry.c
1
2 /*
3  * AT-SPI - Assistive Technology Service Provider Interface
4  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5  *
6  * Copyright 2001, 2002 Sun Microsystems Inc.,
7  * Copyright 2001, 2002 Ximian, Inc.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 /* atspi_registry.c: Global functions wrapping the registry */
26
27 #include "atspi-private.h"
28
29 typedef struct
30 {
31   AtspiDeviceListener *listener;
32   GArray             *key_set;
33   AtspiKeyMaskType         modmask;
34   AtspiKeyEventMask        event_types;
35   gint sync_type;
36 } DeviceListenerEntry;
37
38 static GList *device_listeners;
39
40 /**
41  * atspi_get_desktop_count:
42  *
43  * Gets the number of virtual desktops.
44  * NOTE: multiple virtual desktops are not implemented yet; as a 
45  * consequence, this function always returns 1.
46  *
47  * Returns: a #gint indicating the number of active virtual desktops.
48  **/
49 gint
50 atspi_get_desktop_count ()
51 {
52   return 1;
53 }
54
55 /**
56  * atspi_get_desktop:
57  * @i: a #gint indicating which of the accessible desktops is to be returned.
58  *
59  * Gets the virtual desktop indicated by index @i.
60  * NOTE: currently multiple virtual desktops are not implemented;
61  * as a consequence, any @i value different from 0 will not return a
62  * virtual desktop - instead it will return NULL.
63  *
64  * Returns: (transfer full): a pointer to the @i-th virtual desktop's
65  * #AtspiAccessible representation.
66  **/
67 AtspiAccessible*
68 atspi_get_desktop (gint i)
69 {
70   if (i != 0) return NULL;
71   return _atspi_ref_accessible (atspi_bus_registry, atspi_path_root);
72 }
73
74 /**
75  * atspi_get_desktop_list:
76  *
77  * Gets the list of virtual desktops.  On return, @list will point
78  *     to a newly-created, NULL terminated array of virtual desktop
79  *     pointers.
80  *     It is the responsibility of the caller to free this array when
81  *     it is no longer needed.
82  * NOTE: currently multiple virtual desktops are not implemented;
83  * this implementation always returns a #Garray with a single
84  * #AtspiAccessible desktop.
85  *
86  * Returns: (transfer full): a #GArray of desktops.
87  **/
88 GArray *
89 atspi_get_desktop_list ()
90 {
91   GArray *array = g_array_new (TRUE, TRUE, sizeof (AtspiAccessible *));
92   AtspiAccessible *desktop;
93
94   desktop = _atspi_ref_accessible (atspi_bus_registry, atspi_path_root);
95   if (array)
96     g_array_index (array, AtspiAccessible *, 0) = desktop;
97   return array;
98 }
99
100 static gboolean
101 notify_keystroke_listener (DeviceListenerEntry *e)
102 {
103   gchar *path = _atspi_device_listener_get_path (e->listener);
104   dbus_uint32_t d_modmask = e->modmask;
105   dbus_uint32_t d_event_types = e->event_types;
106   AtspiEventListenerMode     listener_mode;
107   gboolean                          retval = FALSE;
108   DBusError d_error;
109
110   listener_mode.synchronous =
111           (dbus_bool_t) ((e->sync_type & ATSPI_KEYLISTENER_SYNCHRONOUS)!=0);
112   listener_mode.preemptive =
113           (dbus_bool_t) ((e->sync_type & ATSPI_KEYLISTENER_CANCONSUME)!=0);
114   listener_mode.global =
115           (dbus_bool_t) ((e->sync_type & ATSPI_KEYLISTENER_ALL_WINDOWS)!=0);
116
117   dbus_error_init (&d_error);
118   dbind_method_call_reentrant (_atspi_bus(), atspi_bus_registry,
119                                atspi_path_dec, atspi_interface_dec,
120                                "RegisterKeystrokeListener", &d_error,
121                                "oa(iisi)uu(bbb)=>b", path, e->key_set,
122                                d_modmask, d_event_types, &listener_mode,
123                                &retval);
124   if (dbus_error_is_set (&d_error))
125     {
126       g_warning ("RegisterKeystrokeListener failed: %s", d_error.message);
127       dbus_error_free (&d_error);
128     }
129
130   g_free (path);
131
132   return retval;
133 }
134
135 static void
136 device_listener_entry_free (DeviceListenerEntry *e)
137 {
138   g_array_free (e->key_set, TRUE);
139   g_free (e);
140 }
141
142 static void
143 unregister_listener (gpointer data, GObject *object)
144 {
145   GList *l;
146   AtspiDeviceListener *listener = ATSPI_DEVICE_LISTENER (object);
147
148   for (l = device_listeners; l;)
149     {
150       DeviceListenerEntry *e = l->data;
151       if (e->listener == listener)
152         {
153           GList *next = l->next;
154           device_listener_entry_free (e);
155           device_listeners = g_list_delete_link (device_listeners, l);
156           l = next;
157         }
158       else
159         l = l->next;
160     }
161 }
162
163 /**
164  * atspi_register_keystroke_listener:
165  * @listener:  a pointer to the #AtspiDeviceListener for which
166  *             keystroke events are requested.
167  * @key_set: (element-type AtspiKeyDefinition) (allow-none): a pointer to the
168  *        #AtspiKeyDefinition array indicating which keystroke events are
169  *        requested, or NULL
170  *        to indicate that all keycodes and keyvals for the specified
171  *        modifier set are to be included.
172  * @modmask:   an #AtspiKeyMaskType mask indicating which
173  *             key event modifiers must be set in combination with @keys,
174  *             events will only be reported for key events for which all
175  *             modifiers in @modmask are set.  If you wish to listen for
176  *             events with multiple modifier combinations, you must call
177  *             #atspi_register_keystroke_listener once for each
178  *             combination.
179  * @event_types: an #AtspiKeyMaskType mask indicating which
180  *             types of key events are requested (%ATSPI_KEY_PRESSED etc.).
181  * @sync_type: an #AtspiKeyListenerSyncType parameter indicating
182  *             the behavior of the notification/listener transaction.
183  * @error: (allow-none): a pointer to a %NULL #GError pointer, or %NULL
184  *             
185  * Registers a listener for keystroke events, either pre-emptively for
186  *             all windows (%ATSPI_KEYLISTENER_ALL_WINDOWS),
187  *             non-preemptively (%ATSPI_KEYLISTENER_NOSYNC), or
188  *             pre-emptively at the toolkit level (%ATSPI_KEYLISTENER_CANCONSUME).
189  *             If ALL_WINDOWS or CANCONSUME are used, the event is consumed
190  *             upon receipt if one of @listener's callbacks returns %TRUE 
191  *             (other sync_type values may be available in the future).
192  *
193  * Returns: %TRUE if successful, otherwise %FALSE.
194  **/
195 gboolean
196 atspi_register_keystroke_listener (AtspiDeviceListener  *listener,
197                                          GArray             *key_set,
198                                          AtspiKeyMaskType         modmask,
199                                          AtspiKeyEventMask        event_types,
200                                          AtspiKeyListenerSyncType sync_type,
201                                          GError **error)
202 {
203   DeviceListenerEntry *e;
204
205   g_return_val_if_fail (listener != NULL, FALSE);
206
207   e = g_new0 (DeviceListenerEntry, 1);
208   e->listener = listener;
209   e->modmask = modmask;
210   e->event_types = event_types;
211   e->sync_type = sync_type;
212   if (key_set)
213     {
214       gint i;
215       e->key_set = g_array_sized_new (FALSE, TRUE, sizeof (AtspiKeyDefinition),
216                                       key_set->len);
217       e->key_set->len = key_set->len;
218       for (i = 0; i < key_set->len; i++)
219         {
220           AtspiKeyDefinition *kd =  ((AtspiKeyDefinition *) key_set->data) + i;
221           AtspiKeyDefinition *d_kd =  ((AtspiKeyDefinition *) e->key_set->data) + i;
222           d_kd->keycode = kd->keycode;
223           d_kd->keysym = kd->keysym;
224           if (kd->keystring)
225             {
226               d_kd->keystring = kd->keystring;
227             } 
228           else 
229             {
230               d_kd->keystring = "";
231             }
232         }
233     }
234   else
235     {
236       e->key_set = g_array_sized_new (FALSE, TRUE, sizeof (AtspiKeyDefinition), 0);
237     }
238
239   g_object_weak_ref (G_OBJECT (listener), unregister_listener, NULL);
240   device_listeners = g_list_prepend (device_listeners, e);
241   return notify_keystroke_listener (e);
242 }
243
244 /**
245  * atspi_deregister_keystroke_listener:
246  * @listener: a pointer to the #AtspiDeviceListener for which
247  *            keystroke events are requested.
248  * @key_set: (element-type AtspiKeyDefinition) (allow-none): a pointer to the
249  *        #AtspiKeyDefinition array indicating which keystroke events are
250  *        requested, or %NULL
251  *        to indicate that all keycodes and keyvals for the specified
252  *        modifier set are to be included.
253  * @modmask:  the key modifier mask for which this listener is to be
254  *            'deregistered' (of type #AtspiKeyMaskType).
255  * @event_types: an #AtspiKeyMaskType mask indicating which
256  *             types of key events were requested (%ATSPI_KEY_PRESSED, etc.).
257  * @error: (allow-none): a pointer to a %NULL #GError pointer, or %NULL
258  *
259  * Removes a keystroke event listener from the registry's listener queue,
260  *            ceasing notification of events with modifiers matching @modmask.
261  *
262  * Returns: %TRUE if successful, otherwise %FALSE.
263  **/
264 gboolean
265 atspi_deregister_keystroke_listener (AtspiDeviceListener *listener,
266                                      GArray              *key_set,
267                                      AtspiKeyMaskType     modmask,
268                                      AtspiKeyEventMask    event_types,
269                                      GError             **error)
270 {
271   GArray *d_key_set;
272   gchar *path = _atspi_device_listener_get_path (listener);
273   gint i;
274   dbus_uint32_t d_modmask = modmask;
275   dbus_uint32_t d_event_types = event_types;
276   DBusError d_error;
277   GList *l;
278
279   dbus_error_init (&d_error);
280   if (!listener)
281     {
282       return FALSE;
283     }
284
285   /* copy the keyval filter values from the C api into the DBind KeySet */
286   if (key_set)
287     {
288       d_key_set = g_array_sized_new (FALSE, TRUE, sizeof (AtspiKeyDefinition), key_set->len);
289       d_key_set->len = key_set->len;
290       for (i = 0; i < key_set->len; ++i)
291         {
292           AtspiKeyDefinition *kd =  ((AtspiKeyDefinition *) key_set->data) + i;
293           AtspiKeyDefinition *d_kd =  ((AtspiKeyDefinition *) d_key_set->data) + i;
294           d_kd->keycode = kd->keycode;
295           d_kd->keysym = kd->keysym;
296           if (kd->keystring)
297             {
298               d_kd->keystring = kd->keystring;
299             } 
300           else 
301             {
302               d_kd->keystring = "";
303             }
304         }
305     }
306   else
307     {
308       d_key_set = g_array_sized_new (FALSE, TRUE, sizeof (AtspiKeyDefinition), 0);
309     }
310
311   dbind_method_call_reentrant (_atspi_bus(), atspi_bus_registry,
312                                atspi_path_dec, atspi_interface_dec,
313                                "DeregisterKeystrokeListener", &d_error,
314                                "oa(iisi)uu", path, d_key_set, d_modmask,
315                                d_event_types);
316   if (dbus_error_is_set (&d_error))
317     {
318       g_warning ("DeregisterKeystrokeListener failed: %s", d_error.message);
319       dbus_error_free (&d_error);
320     }
321
322   unregister_listener (listener, NULL);
323   for (l = device_listeners; l;)
324     {
325       /* TODO: This code is all wrong / doesn't match what is in
326  *       deviceeventcontroller.c. It would be nice to deprecate these methods
327  *       in favor of methods that return an ID for the registration that can
328  *       be passed to a deregister function, for instance. */
329       DeviceListenerEntry *e = l->data;
330       if (e->modmask == modmask && e->event_types == event_types)
331         {
332           GList *next = l->next;
333           device_listener_entry_free (e);
334           device_listeners = g_list_delete_link (device_listeners, l);
335           l = next;
336         }
337       else
338         l = l->next;
339     }
340   g_array_free (d_key_set, TRUE);
341   g_free (path);
342   return TRUE;
343 }
344
345 /**
346  * atspi_register_device_event_listener:
347  * @listener:  a pointer to the #AtspiDeviceListener which requests
348  *             the events.
349  * @event_types: an #AtspiDeviceEventMask mask indicating which
350  *             types of key events are requested (%ATSPI_KEY_PRESSED, etc.).
351  * @filter: Unused parameter.
352  * @error: (allow-none): a pointer to a %NULL #GError pointer, or %NULL
353  *             
354  * Registers a listener for device events, for instance button events.
355  *
356  * Returns: %TRUE if successful, otherwise %FALSE.
357  **/
358 gboolean
359 atspi_register_device_event_listener (AtspiDeviceListener  *listener,
360                                  AtspiDeviceEventMask  event_types,
361                                  void                      *filter, GError **error)
362 {
363   gboolean                          retval = FALSE;
364   dbus_uint32_t d_event_types = event_types;
365   gchar *path = _atspi_device_listener_get_path (listener);
366   DBusError d_error;
367
368   dbus_error_init (&d_error);
369   if (!listener)
370     {
371       return retval;
372     }
373
374     dbind_method_call_reentrant (_atspi_bus(), atspi_bus_registry, atspi_path_dec, atspi_interface_dec, "RegisterDeviceEventListener", &d_error, "ou=>b", path, d_event_types, &retval);
375     if (dbus_error_is_set (&d_error))
376       {
377         g_warning ("RegisterDeviceEventListener failed: %s", d_error.message);
378         dbus_error_free (&d_error);
379       }
380
381   g_free (path);
382   return retval;
383 }
384
385 /**
386  * atspi_deregister_device_event_listener:
387  * @listener: a pointer to the #AtspiDeviceListener for which
388  *            device events are requested.
389  * @filter: Unused parameter.
390  * @error: (allow-none): a pointer to a %NULL #GError pointer, or %NULL
391  *
392  * Removes a device event listener from the registry's listener queue,
393  *            ceasing notification of events of the specified type.
394  *
395  * Returns: %TRUE if successful, otherwise %FALSE.
396  **/
397 gboolean
398 atspi_deregister_device_event_listener (AtspiDeviceListener *listener,
399                                    void                     *filter, GError **error)
400 {
401   dbus_uint32_t event_types = 0;
402   gchar *path = _atspi_device_listener_get_path (listener);
403   DBusError d_error;
404
405   dbus_error_init (&d_error);
406
407   if (!listener)
408     {
409       return FALSE;
410     }
411
412   event_types |= (1 << ATSPI_BUTTON_PRESSED_EVENT);
413   event_types |= (1 << ATSPI_BUTTON_RELEASED_EVENT);
414
415   dbind_method_call_reentrant (_atspi_bus(), atspi_bus_registry, atspi_path_dec, atspi_interface_dec, "DeregisterDeviceEventListener", &d_error, "ou", path, event_types);
416   if (dbus_error_is_set (&d_error))
417     {
418       g_warning ("DeregisterDeviceEventListener failed: %s", d_error.message);
419       dbus_error_free (&d_error);
420     }
421
422   g_free (path);
423   return TRUE;
424 }
425
426 /**
427  * atspi_generate_keyboard_event:
428  * @keyval: a #gint indicating the keycode or keysym of the key event
429  *           being synthesized.
430  * @keystring: (allow-none): an (optional) UTF-8 string which, if
431  *           @synth_type is %ATSPI_KEY_STRING, indicates a 'composed'
432  *           keyboard input string being synthesized; this type of
433  *           keyboard event synthesis does not emulate hardware
434  *           keypresses but injects the string as though a composing
435  *           input method (such as XIM) were used.
436  * @synth_type: an #AtspiKeySynthType flag indicating whether @keyval
437  *           is to be interpreted as a keysym rather than a keycode
438  *           (%ATSPI_KEY_SYM) or a string (%ATSPI_KEY_STRING), or
439  *           whether to synthesize %ATSPI_KEY_PRESS,
440  *           %ATSPI_KEY_RELEASE, or both (%ATSPI_KEY_PRESSRELEASE).
441  * @error: (allow-none): a pointer to a %NULL #GError pointer, or %NULL
442  *
443  * Synthesizes a keyboard event (as if a hardware keyboard event occurred in the
444  * current UI context).
445  *
446  * Returns: %TRUE if successful, otherwise %FALSE.
447  **/
448 gboolean
449 atspi_generate_keyboard_event (glong keyval,
450                            const gchar *keystring,
451                            AtspiKeySynthType synth_type, GError **error)
452 {
453   dbus_uint32_t d_synth_type = synth_type;
454   dbus_int32_t d_keyval = keyval;
455   DBusError d_error;
456
457   dbus_error_init (&d_error);
458   if (!keystring)
459     keystring = "";
460   dbind_method_call_reentrant (_atspi_bus(), atspi_bus_registry, atspi_path_dec, atspi_interface_dec, "GenerateKeyboardEvent", &d_error, "isu", d_keyval, keystring, d_synth_type);
461   if (dbus_error_is_set (&d_error))
462     {
463       g_warning ("GenerateKeyboardEvent failed: %s", d_error.message);
464       dbus_error_free (&d_error);
465     }
466
467   return TRUE;
468 }
469
470 /**
471  * atspi_generate_mouse_event:
472  * @x: a #glong indicating the screen x coordinate of the mouse event.
473  * @y: a #glong indicating the screen y coordinate of the mouse event.
474  * @name: a string indicating which mouse event to be synthesized
475  *        (e.g. "b1p", "b1c", "b2r", "rel", "abs").
476  * @error: (allow-none): a pointer to a %NULL #GError pointer, or %NULL
477  *
478  * Synthesizes a mouse event at a specific screen coordinate.
479  * Most AT clients should use the #AccessibleAction interface when
480  * tempted to generate mouse events, rather than this method.
481  * Event names: b1p = button 1 press; b2r = button 2 release;
482  *              b3c = button 3 click; b2d = button 2 double-click;
483  *              abs = absolute motion; rel = relative motion.
484  *
485  * Returns: %TRUE if successful, otherwise %FALSE.
486  **/
487 gboolean
488 atspi_generate_mouse_event (glong x, glong y, const gchar *name, GError **error)
489 {
490   dbus_int32_t d_x = x, d_y = y;
491   DBusError d_error;
492
493   dbus_error_init (&d_error);
494   dbind_method_call_reentrant (_atspi_bus(), atspi_bus_registry,
495                                atspi_path_dec, atspi_interface_dec,
496                                "GenerateMouseEvent", &d_error, "iis",
497                                d_x, d_y, name);
498   if (dbus_error_is_set (&d_error))
499     {
500       g_warning ("GenerateMouseEvent failed: %s", d_error.message);
501       dbus_error_free (&d_error);
502     }
503
504   return TRUE;
505 }
506
507 AtspiKeyDefinition *
508 atspi_key_definition_copy (AtspiKeyDefinition *src)
509 {
510   AtspiKeyDefinition *dst;
511
512   dst = g_new0 (AtspiKeyDefinition, 1);
513   dst->keycode = src->keycode;
514   dst->keysym = src->keysym;
515   if (src->keystring)
516     dst->keystring = g_strdup (src->keystring);
517   dst->unused = src->unused;
518   return dst;
519 }
520
521 void
522 atspi_key_definition_free (AtspiKeyDefinition *kd)
523 {
524   if (kd->keystring)
525     g_free (kd->keystring);
526   g_free (kd);
527 }
528
529 void
530 _atspi_reregister_device_listeners ()
531 {
532   GList *l;
533   DeviceListenerEntry *e;
534
535   for (l = device_listeners; l; l = l->next)
536     {
537       e = l->data;
538       notify_keystroke_listener (e);
539     }
540 }
541 G_DEFINE_BOXED_TYPE (AtspiKeyDefinition, atspi_key_definition, atspi_key_definition_copy, atspi_key_definition_free)