2008-07-23 Mark Doffman <mark.doffman@codethink.co.uk>
[platform/core/uifw/at-spi2-atk.git] / cspi / spi-registry.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 /* spi_registry.c: Global functions wrapping the registry */
25
26 #include <cspi/spi-private.h>
27
28 static GArray *desktops;
29
30 /**
31  * SPI_getDesktopCount:
32  *
33  * Get the number of virtual desktops.
34  * NOTE: currently multiple virtual desktops are not implemented, this
35  *       function always returns '1'.
36  *
37  * Returns: an integer indicating the number of active virtual desktops.
38  **/
39 int
40 SPI_getDesktopCount ()
41 {
42   if (!desktops) SPI_getDesktopList (NULL);
43   if (!desktops) return -1;
44   return desktops->len;
45 }
46
47 /**
48  * SPI_getDesktop:
49  * @i: an integer indicating which of the accessible desktops is to be returned.
50  *
51  * Get the virtual desktop indicated by index @i.
52  * NOTE: currently multiple virtual desktops are not implemented, this
53  *       function always returns '1'.
54  *
55  * Returns: a pointer to the 'i-th' virtual desktop's #Accessible representation.
56  **/
57 Accessible*
58 SPI_getDesktop (int i)
59 {
60   if (!desktops) SPI_getDesktopList (NULL);
61   if (!desktops) return NULL;
62   return cspi_ref_accessible (spi_bus_registry, g_array_index (desktops, char *, i));
63 }
64
65 /**
66  * SPI_getDesktopList:
67  * @desktop_list: a pointer to an array of #Accessible references.
68  *
69  * Get the list of virtual desktops.  On return, @list will point
70  *     to a newly-created, NULL terminated array of virtual desktop
71  *     pointers.
72  *     It is the responsibility of the caller to free this array when
73  *     it is no longer needed.
74  *
75  * Not Yet Implemented : this implementation always returns a single
76  * #Accessible desktop.
77  *
78  * Returns: an integer indicating how many virtual desktops have been
79  *          placed in the list pointed to by parameter @list.
80  **/
81 int
82 SPI_getDesktopList (Accessible ***desktop_list)
83 {
84   int i;
85   Accessible **list;
86
87   if (desktop_list) *desktop_list = NULL;
88
89   if (!desktops)
90   {
91     dbind_connection_method_call (cspi_bus(), spi_bus_registry, spi_path_registry, spi_interface_registry, "getDesktopList", NULL, "=>ao", &desktops);
92     if (!desktops) return 0;
93   }
94
95   list = g_new0 (Accessible *, desktops->len + 1);
96
97   if (!desktop_list) return desktops->len;
98   for (i = 0; i < desktops->len; i++)
99     {
100       list [i] = cspi_ref_accessible (spi_bus_registry, g_array_index (desktops, char *, i));
101     }
102   list [i] = NULL;
103
104   *desktop_list = list;
105
106   return i;
107 }
108
109 /**
110  * SPI_freeDesktopList:
111  * @desktop_list: a pointer to an array of #Accessible objects
112  * as returned from @SPI_getDesktopList
113  * 
114  * This routine frees the memory associated with the list.
115  **/
116 void
117 SPI_freeDesktopList (Accessible **desktop_list)
118 {
119   Accessible **p;
120   
121   for (p = desktop_list; p && *p; p++)
122     {
123       cspi_object_unref (*p);
124     }
125   g_free (desktop_list);
126 }
127
128 /**
129  * SPI_KEYSET_ALL_KEYS:
130  * @SPI_KEYSET_ALL_KEYS: A special value for an AccessibleKeySet type, which tacitly
131  *                       includes all keycodes and keyvals for the specified modifier set.
132  **/
133
134 /**
135  * SPI_registerAccessibleKeystrokeListener:
136  * @listener:  a pointer to the #AccessibleKeystrokeListener for which
137  *             keystroke events are requested.
138  * @keys:      a pointer to the #AccessibleKeySet indicating which
139  *             keystroke events are requested, or #SPI_KEYSET_ALL_KEYS
140  *             to indicate that all keycodes and keyvals for the specified
141  *             modifier set are to be included.
142  * @modmask:   an #AccessibleKeyMaskType mask indicating which
143  *             key event modifiers must be set in combination with @keys,
144  *             events will only be reported for key events for which all
145  *             modifiers in @modmask are set.  If you wish to listen for
146  *             events with multiple modifier combinations you must call
147  *             registerAccessibleKeystrokeListener() once for each combination.
148  * @eventmask: an #AccessibleKeyMaskType mask indicating which
149  *             types of key events are requested (#SPI_KEY_PRESSED, etc.).
150  * @sync_type: a #AccessibleKeyListenerSyncType parameter indicating
151  *             the behavior of the notification/listener transaction.
152  *             
153  * Register a listener for keystroke events, either pre-emptively for
154  *             all windows (SPI_KEYLISTENER_ALL_WINDOWS),
155  *             non-preemptively (SPI_KEYLISTENER_NOSYNC), or
156  *             pre-emptively at the toolkit level (SPI_KEYLISTENER_CANCONSUME).
157  *             If ALL_WINDOWS or CANCONSUME are used, the event is consumed
158  *             upon receipt if one of @listener's callbacks returns #TRUE.
159  *             ( Other sync_type values may be available in the future )
160  *
161  * Returns: #TRUE if successful, otherwise #FALSE.
162  **/
163 SPIBoolean
164 SPI_registerAccessibleKeystrokeListener (AccessibleKeystrokeListener  *listener,
165                                          AccessibleKeySet             *keys,
166                                          AccessibleKeyMaskType         modmask,
167                                          AccessibleKeyEventMask        eventmask,
168                                          AccessibleKeyListenerSyncType sync_type)
169 {
170   gchar *path = cspi_device_listener_get_path (listener);
171   gint                                i;
172   GArray *key_set;
173   dbus_uint32_t key_events = 0;
174   Accessibility_ControllerEventMask   controller_event_mask;
175   Accessibility_EventListenerMode     listener_mode;
176   DBusError error;
177   SPIBoolean                          retval = FALSE;
178
179   if (!listener)
180     {
181       return retval;
182     }
183
184   /* copy the keyval filter values from the C api into the DBind KeySet */
185   if (keys)
186     {
187       key_set = g_array_sized_new (FALSE, TRUE, sizeof (Accessibility_KeyDefinition), keys->len);
188       key_set->len = keys->len;
189       for (i = 0; i < keys->len; ++i)
190         {
191           Accessibility_KeyDefinition *kd =  ((Accessibility_KeyDefinition *) key_set->data) + i;
192           kd->keycode = keys->keycodes[i];
193           kd->keysym = keys->keysyms[i];
194           if (keys->keystrings && keys->keystrings[i])
195             {
196               kd->keystring = keys->keystrings[i];
197             } 
198           else 
199             {
200               kd->keystring = "";
201             }
202         }
203     }
204   else
205     {
206       key_set = g_array_sized_new (FALSE, TRUE, sizeof (Accessibility_KeyDefinition), 0);
207     }
208         
209   /* copy the event filter values from the C api into the DBus key_events */
210   if (eventmask & SPI_KEY_PRESSED)
211     {
212       key_events |= (1 << Accessibility_KEY_PRESSED_EVENT);
213     }
214   if (eventmask & SPI_KEY_RELEASED)
215     {
216       key_events |= (1 << Accessibility_KEY_RELEASED_EVENT);
217     }
218   
219   controller_event_mask = (dbus_uint32_t) modmask;
220
221   listener_mode.synchronous =
222           (dbus_bool_t) ((sync_type & SPI_KEYLISTENER_SYNCHRONOUS)!=0);
223   listener_mode.preemptive =
224           (dbus_bool_t) ((sync_type & SPI_KEYLISTENER_CANCONSUME)!=0);
225   listener_mode.global =
226           (dbus_bool_t) ((sync_type & SPI_KEYLISTENER_ALL_WINDOWS)!=0);
227
228     dbus_error_init (&error);
229     dbind_connection_method_call (cspi_bus(), spi_bus_registry, spi_path_dec, spi_interface_dec, "registerKeystrokeListener", &error, "oa(iisi)uu(bbb)=>b", path, key_set, controller_event_mask, key_set, &listener_mode, &retval);
230
231   g_array_free (key_set, TRUE);
232   g_free (path);
233
234   return retval;
235 }
236
237 /**
238  * SPI_deregisterAccessibleKeystrokeListener:
239  * @listener: a pointer to the #AccessibleKeystrokeListener for which
240  *            keystroke events are requested.
241  * @modmask:  the key modifier mask for which this listener is to be
242  *            'deregistered' (of type #AccessibleeyMaskType).
243  *
244  * Removes a keystroke event listener from the registry's listener queue,
245  *            ceasing notification of events with modifiers matching @modmask.
246  *
247  * Returns: #TRUE if successful, otherwise #FALSE.
248  **/
249 SPIBoolean
250 SPI_deregisterAccessibleKeystrokeListener (AccessibleKeystrokeListener *listener,
251                                            AccessibleKeyMaskType        modmask)
252 {
253   gchar *path = cspi_device_listener_get_path (listener);
254   Accessibility_ControllerEventMask   controller_event_mask;
255   GArray *key_set;
256   dbus_uint32_t key_events = 0;
257   DBusError error;
258
259   if (!listener)
260     {
261       return FALSE;
262     }
263
264
265   controller_event_mask = (dbus_uint32_t) modmask;
266
267       key_set = g_array_sized_new (FALSE, TRUE, sizeof (Accessibility_KeyDefinition), 0);
268     dbind_connection_method_call (cspi_bus(), spi_bus_registry, spi_path_dec, spi_interface_dec, "deregisterKeystrokeListener", &error, "oa(iisi)uu", path, &key_set, key_events, controller_event_mask);
269   g_free (path);
270   return TRUE;
271 }
272
273 /**
274  * SPI_registerDeviceEventListener:
275  * @listener:  a pointer to the #AccessibleDeviceListener which requests
276  *             the events.
277  * @eventmask: an #AccessibleDeviceEventMask mask indicating which
278  *             types of key events are requested (#SPI_KEY_PRESSED, etc.).
279  * @filter: Unused parameter.
280  *             
281  * Register a listener for device events, for instance button events.
282  *
283  * Returns: #TRUE if successful, otherwise #FALSE.
284  **/
285 SPIBoolean
286 SPI_registerDeviceEventListener (AccessibleDeviceListener  *listener,
287                                  AccessibleDeviceEventMask  eventmask,
288                                  void                      *filter)
289 {
290   SPIBoolean                          retval = FALSE;
291   dbus_uint32_t event_types = 0;
292   gint                                i;
293   gchar *path = cspi_device_listener_get_path (listener);
294   DBusError error;
295
296   if (!listener)
297     {
298       return retval;
299     }
300
301   /* copy the event filter values from the C api into the CORBA KeyEventTypeSeq */
302   
303   if (eventmask & SPI_BUTTON_PRESSED)
304     {
305       event_types |= (1 << Accessibility_BUTTON_PRESSED_EVENT);
306     }
307   if (eventmask & SPI_BUTTON_RELEASED)
308     {
309       event_types |= (1 << Accessibility_BUTTON_RELEASED_EVENT);
310     }
311
312   dbus_error_init (&error);
313     dbind_connection_method_call (cspi_bus(), spi_bus_registry, spi_path_dec, spi_interface_dec, "registerDeviceEventListener", &error, "ou=>b", path, event_types, &retval);
314   g_free (path);
315   return retval;
316 }
317
318 /**
319  * SPI_deregisterDeviceEventListener:
320  * @listener: a pointer to the #AccessibleDeviceListener for which
321  *            device events are requested.
322  * @filter: Unused parameter.
323  *
324  * Removes a device event listener from the registry's listener queue,
325  *            ceasing notification of events of the specified type.
326  *
327  * Returns: #TRUE if successful, otherwise #FALSE.
328  **/
329 SPIBoolean
330 SPI_deregisterDeviceEventListener (AccessibleDeviceListener *listener,
331                                    void                     *filter)
332 {
333   dbus_uint32_t event_types = 0;
334   gchar *path = cspi_device_listener_get_path (listener);
335   DBusError error;
336
337   if (!listener)
338     {
339       return FALSE;
340     }
341
342   event_types |= (1 << Accessibility_BUTTON_PRESSED_EVENT);
343   event_types |= (1 << Accessibility_BUTTON_RELEASED_EVENT);
344
345   dbus_error_init (&error);
346     dbind_connection_method_call (cspi_bus(), spi_bus_registry, spi_path_dec, spi_interface_dec, "deregisterDeviceEventListener", &error, "ou", path, event_types);
347   g_free (path);
348   return TRUE;
349 }
350
351 /**
352  * SPI_generateKeyboardEvent:
353  * @keyval: a long integer indicating the keycode or keysym of the key event
354  *           being synthesized.
355  * @keystring: an (optional) UTF-8 string which, if @keyval is NULL,
356  *           indicates a 'composed' keyboard input string which is 
357  *           being synthesized; this type of keyboard event synthesis does
358  *           not emulate hardware keypresses but injects the string 
359  *           as though a composing input method (such as XIM) were used.
360  * @synth_type: a #AccessibleKeySynthType flag indicating whether @keyval
361  *           is to be interpreted as a keysym rather than a keycode
362  *           (CSPI_KEYSYM), or whether to synthesize
363  *           SPI_KEY_PRESS, SPI_KEY_RELEASE, or both (SPI_KEY_PRESSRELEASE).
364  *
365  * Synthesize a keyboard event (as if a hardware keyboard event occurred in the
366  * current UI context).
367  *
368  * Returns: #TRUE if successful, otherwise #FALSE.
369  **/
370 SPIBoolean
371 SPI_generateKeyboardEvent (long int keyval,
372                            char *keystring,
373                            AccessibleKeySynthType synth_type)
374 {
375   dbus_uint32_t keysynth_type;
376   dbus_int32_t keycode = keyval;
377   DBusError error;
378
379   switch (synth_type)
380     {
381       case SPI_KEY_PRESS:
382           keysynth_type = Accessibility_KEY_PRESS;
383           break;
384       case SPI_KEY_RELEASE:
385           keysynth_type = Accessibility_KEY_RELEASE;
386           break;
387       case SPI_KEY_PRESSRELEASE:
388           keysynth_type = Accessibility_KEY_PRESSRELEASE;
389           break;
390       case SPI_KEY_SYM:
391           keysynth_type = Accessibility_KEY_SYM;
392           break;
393       case SPI_KEY_STRING:
394           keysynth_type = Accessibility_KEY_STRING;
395           break;
396       default:
397           return FALSE;
398     }
399
400   if (!keystring) keystring = "";
401   dbus_error_init (&error);
402     dbind_connection_method_call (cspi_bus(), spi_bus_registry, spi_path_dec, spi_interface_dec, "generateKeyboardEvent", &error, "isu", keycode, keystring, keysynth_type);
403
404   return TRUE;
405 }
406
407 /**
408  * SPI_generateMouseEvent:
409  * @x: a #long indicating the screen x coordinate of the mouse event.
410  * @y: a #long indicating the screen y coordinate of the mouse event.
411  * @name: a string indicating which mouse event to be synthesized
412  *        (e.g. "b1p", "b1c", "b2r", "rel", "abs").
413  *
414  * Synthesize a mouse event at a specific screen coordinate.
415  * Most AT clients should use the #AccessibleAction interface when
416  * tempted to generate mouse events, rather than this method.
417  * Event names: b1p = button 1 press; b2r = button 2 release;
418  *              b3c = button 3 click; b2d = button 2 double-click;
419  *              abs = absolute motion; rel = relative motion.
420  *
421  * Returns: #TRUE if successful, otherwise #FALSE.
422  **/
423 SPIBoolean
424 SPI_generateMouseEvent (long x, long y, char *name)
425 {
426   dbus_int32_t dbus_x = x, dbus__y = y;
427   DBusError error;
428
429   dbus_error_init (&error);
430     dbind_connection_method_call (cspi_bus(), spi_bus_registry, spi_path_dec, spi_interface_dec, "generateMouseEvent", &error, "iis", x, y, name);
431   return TRUE;
432 }
433
434 char *
435 cspi_device_listener_get_path (CSpiDeviceListener *listener)
436 {
437   return g_strdup_printf ("/org/freedesktop/atspi/listeners/%d", listener->id);
438 }