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