2002-01-08 Michael Meeks <michael@ximian.com>
[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 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 /* spi_registry.c: Global functions wrapping the registry */
24
25 #include <cspi/spi-private.h>
26
27 /**
28  * SPI_registerGlobalEventListener:
29  * @listener: the #AccessibleEventListener to be registered against an
30  *            event type.
31  * @eventType: a character string indicating the type of events for which
32  *            notification is requested.  Format is
33  *            EventClass:major_type:minor_type:detail
34  *            where all subfields other than EventClass are optional.
35  *            EventClasses include "object", "window", "mouse",
36  *            and toolkit events (e.g. "Gtk", "AWT").
37  *            Examples: "focus:", "Gtk:GtkWidget:button_press_event".
38  *
39  * Legal object event types:
40  *
41  *    (property change events)
42  *
43  *            object:property-change
44  *            object:property-change:accessible-name
45  *            object:property-change:accessible-state
46  *            object:property-change:accessible-description
47  *            object:property-change:accessible-parent
48  *            object:property-change:accessible-value
49  *            object:property-change:accessible-role
50  *            object:property-change:accessible-table-caption
51  *            object:property-change:accessible-table-column-description
52  *            object:property-change:accessible-table-column-header
53  *            object:property-change:accessible-table-row-description
54  *            object:property-change:accessible-table-row-header
55  *            object:property-change:accessible-table-summary
56  *
57  *    (other object events)
58  *
59  *            object:children-changed
60  *            object:visible-data-changed
61  *            object:selection-changed
62  *            object:text-selection-changed
63  *            object:text-changed
64  *            object:text-caret-moved
65  *            object:row-inserted
66  *            object:row-reordered
67  *            object:row-deleted
68  *            object:column-inserted
69  *            object:column-reordered
70  *            object:column-deleted
71  *            object:model-changed
72  *
73  *  (window events)
74  *
75  *            window:minimize
76  *            window:maximize
77  *            window:restore
78  *            window:close
79  *            window:create
80  *            window:reparent
81  *            window:desktop-create
82  *            window:desktop-destroy
83  *            window:focus-in
84  *            window:focus-out
85  *            window:raise
86  *            window:lower
87  *            window:move
88  *            window:resize
89  *            window:shade
90  *            window:unshade
91  *            window:restyle
92  *
93  * NOTE: this string may be UTF-8, but should not contain byte value 56
94  *            (ascii ':'), except as a delimiter, since non-UTF-8 string
95  *            delimiting functions are used internally.
96  *            In general, listening to
97  *            toolkit-specific events is not recommended.
98  *
99  * Add an in-process callback function to an existing AccessibleEventListener.
100  *
101  * Returns: #TRUE if successful, otherwise #FALSE.
102  **/
103 SPIBoolean
104 SPI_registerGlobalEventListener (AccessibleEventListener *listener,
105                                  const char              *eventType)
106 {
107   SPIBoolean retval;
108
109   if (!listener)
110     {
111       return FALSE;
112     }
113
114   Accessibility_Registry_registerGlobalEventListener (
115     cspi_registry (),
116     cspi_event_listener_get_corba (listener),
117     eventType, cspi_ev ());
118
119   retval = !cspi_exception ();
120  
121   return retval;
122 }
123
124 /**
125  * SPI_deregisterGlobalEventListenerAll:
126  * @listener: the #AccessibleEventListener to be registered against
127  *            an event type.
128  *
129  * deregisters an AccessibleEventListener from the registry, for all
130  *            event types it may be listening to. Use
131  *            AccessibleEventListener_unref to release the
132  *            listener reference.
133  *
134  * Returns: #TRUE if successful, otherwise #FALSE.
135  **/
136 SPIBoolean
137 SPI_deregisterGlobalEventListenerAll (AccessibleEventListener *listener)
138 {
139   if (!listener)
140     {
141       return FALSE;
142     }
143
144   Accessibility_Registry_deregisterGlobalEventListenerAll (
145     cspi_registry (),
146     cspi_event_listener_get_corba (listener),
147     cspi_ev ());
148
149   return !cspi_exception ();
150 }
151
152 /**
153  * SPI_deregisterGlobalEventListener:
154  * @listener: the #AccessibleEventListener registered against an event type.
155  * @eventType: a string specifying the event type for which this
156  *             listener is to be deregistered.
157  *
158  * deregisters an AccessibleEventListener from the registry, for a specific
159  *             event type.
160  *
161  * Returns: #TRUE if successful, otherwise #FALSE.
162  **/
163 SPIBoolean
164 SPI_deregisterGlobalEventListener (AccessibleEventListener *listener,
165                                    const char              *eventType)
166 {
167   if (!listener)
168     {
169       return FALSE;
170     }
171
172   Accessibility_Registry_deregisterGlobalEventListener (
173     cspi_registry (), 
174     cspi_event_listener_get_corba (listener),
175     (CORBA_char *) eventType, cspi_ev ());
176
177   return !cspi_exception ();
178 }
179
180 /**
181  * SPI_getDesktopCount:
182  *
183  * Get the number of virtual desktops.
184  * NOTE: currently multiple virtual desktops are not implemented, this
185  *       function always returns '1'.
186  *
187  * Returns: an integer indicating the number of active virtual desktops.
188  **/
189 int
190 SPI_getDesktopCount ()
191 {
192   int retval;
193
194   retval = Accessibility_Registry_getDesktopCount (
195     cspi_registry (), cspi_ev ());
196
197   cspi_return_val_if_ev ("getDesktopCount", -1);
198
199   return retval;
200 }
201
202 /**
203  * SPI_getDesktop:
204  * @i: an integer indicating which of the accessible desktops is to be returned.
205  *
206  * Get the virtual desktop indicated by index @i.
207  * NOTE: currently multiple virtual desktops are not implemented, this
208  *       function always returns '1'.
209  *
210  * Returns: a pointer to the 'i-th' virtual desktop's #Accessible representation.
211  **/
212 Accessible*
213 SPI_getDesktop (int i)
214 {
215   return cspi_object_add (
216     Accessibility_Registry_getDesktop (
217       cspi_registry (), (CORBA_short) i, cspi_ev ()));
218 }
219
220 /**
221  * SPI_getDesktopList:
222  * @desktop_list: a pointer to an array of #Accessible references.
223  *
224  * Get the list of virtual desktops.  On return, @list will point
225  *     to a newly-created, NULL terminated array of virtual desktop
226  *     pointers.
227  *     It is the responsibility of the caller to free this array when
228  *     it is no longer needed.
229  *
230  * Not Yet Implemented : this implementation always returns a single
231  * #Accessible desktop.
232  *
233  * Returns: an integer indicating how many virtual desktops have been
234  *          placed in the list pointed to by parameter @list.
235  **/
236 int
237 SPI_getDesktopList (Accessible ***desktop_list)
238 {
239   int i;
240   Accessible **list;
241   Accessibility_DesktopSeq *desktops;
242
243   if (!desktop_list)
244           return 0;
245
246   *desktop_list = NULL;
247
248   desktops = Accessibility_Registry_getDesktopList (cspi_registry (),
249                                                     cspi_ev ());
250
251   cspi_return_val_if_ev ("getting desktop list", 0);
252
253   list = g_new0 (Accessible *, desktops->_length + 1);
254
255   for (i = 0; i < desktops->_length; i++)
256     {
257       list [i] = cspi_object_add (
258               CORBA_Object_duplicate (desktops->_buffer [i], cspi_ev ()));
259     }
260   list [i] = NULL;
261
262   CORBA_free (desktops);
263
264   *desktop_list = list;
265
266   return i;
267 }
268
269 /**
270  * SPI_freeDesktopList:
271  * @desktop_list: a pointer to an array of #Accessible objects
272  * as returned from @SPI_getDesktopList
273  * 
274  * This routine frees the memory associated with the list.
275  **/
276 void
277 SPI_freeDesktopList (Accessible **desktop_list)
278 {
279   Accessible **p;
280   
281   for (p = desktop_list; p && *p; p++)
282     {
283       cspi_object_unref (*p);
284     }
285   g_free (desktop_list);
286 }
287
288 /**
289  * SPI_registerAccessibleKeystrokeListener:
290  * @listener:  a pointer to the #AccessibleKeystrokeListener for which
291  *             keystroke events are requested.
292  * @keys:      a pointer to the #AccessibleKeySet indicating which
293  *             keystroke events are requested, or #CSPI_KEYSET_ALL_KEYS.
294  * @modmask:   an #AccessibleKeyMaskType mask indicating which
295  *             key event modifiers must be set in combination with @keys,
296  *             events will only be reported for key events for which all
297  *             modifiers in @modmask are set.  If you wish to listen for
298  *             events with multiple modifier combinations you must call
299  *             registerAccessibleKeystrokeListener() once for each combination.
300  * @eventmask: an #AccessibleKeyMaskType mask indicating which
301  *             types of key events are requested (#SPI_KEY_PRESSED, etc.).
302  * @sync_type: a #AccessibleKeyListenerSyncType parameter indicating
303  *             the behavior of the notification/listener transaction.
304  *             
305  * Register a listener for keystroke events, either pre-emptively for
306  *             all windows (CSPI_KEYLISTENER_ALL_WINDOWS), or
307  *             non-preemptively (CSPI_KEYLISTENER_NOSYNC).
308  *             ( Other sync_type values may be available in the future.)
309  *
310  * Returns: #TRUE if successful, otherwise #FALSE.
311  **/
312 SPIBoolean
313 SPI_registerAccessibleKeystrokeListener (AccessibleKeystrokeListener *listener,
314                                          AccessibleKeySet *keys,
315                                          AccessibleKeyMaskType modmask,
316                                          AccessibleKeyEventMask eventmask,
317                                          AccessibleKeyListenerSyncType sync_type)
318 {
319   gint                                i, mask;
320   Accessibility_KeySet                key_set;
321   Accessibility_KeyEventTypeSeq       key_events;
322   Accessibility_ControllerEventMask   controller_event_mask;
323   Accessibility_DeviceEventController device_event_controller;
324   Accessibility_EventListenerMode     listener_mode;
325
326   if (!listener)
327     {
328       return FALSE;
329     }
330
331   device_event_controller = 
332     Accessibility_Registry_getDeviceEventController (cspi_registry (), cspi_ev ());
333
334   cspi_return_val_if_ev ("getting event controller", FALSE);
335
336   /* copy the keyval filter values from the C api into the CORBA KeySet */
337   if (keys)
338     {
339       key_set._length = keys->len;
340       key_set._buffer = Accessibility_KeySet_allocbuf (keys->len);
341       for (i = 0; i < key_set._length; ++i)
342         {
343           /* we overload the keyset long w/keycodes, the - bit acts as a flag */
344           key_set._buffer[i] = (keys->keysyms[i]) ? keys->keysyms[i] :
345                                                   - keys->keycodes[i];
346           /* fprintf (stderr, "key-set %d = %d\n", i, (int) key_set->_buffer[i]); */
347         }
348     }
349   else
350     {
351       key_set._length = 0;
352       key_set._buffer = NULL;
353     }
354         
355   /* copy the event filter values from the C api into the CORBA KeyEventTypeSeq */
356   mask = 1;
357   i = 0;
358   do
359     {
360       if (mask & eventmask)
361         {
362           ++i; 
363         }
364       mask <<= 1;
365     }
366   while (mask & 0xFFFF);
367   
368   key_events._buffer = Accessibility_KeyEventTypeSeq_allocbuf (i);
369   i = 0;
370   if (eventmask & SPI_KEY_PRESSED)
371     {
372       key_events._buffer[i++] = Accessibility_KEY_PRESSED;
373     }
374   if (eventmask & SPI_KEY_RELEASED)
375     {
376       key_events._buffer[i++] = Accessibility_KEY_RELEASED;
377     }
378   key_events._length = i;
379   
380   controller_event_mask = (CORBA_unsigned_long) modmask;
381
382   listener_mode.synchronous =
383           (CORBA_boolean) ((sync_type & SPI_KEYLISTENER_SYNCHRONOUS)!=0);
384   listener_mode.preemptive =
385           (CORBA_boolean) ((sync_type & SPI_KEYLISTENER_CANCONSUME)!=0);
386   listener_mode.global =
387           (CORBA_boolean) ((sync_type & SPI_KEYLISTENER_ALL_WINDOWS)!=0);
388
389   Accessibility_DeviceEventController_registerKeystrokeListener (
390     device_event_controller,
391     cspi_event_listener_get_corba (listener),
392     &key_set,
393     controller_event_mask,
394     &key_events,
395     &listener_mode,
396     cspi_ev ());
397
398   cspi_return_val_if_ev ("registering keystroke listener", FALSE);
399
400   cspi_release_unref (device_event_controller);
401
402   return TRUE;
403 }
404
405 /**
406  * SPI_deregisterAccessibleKeystrokeListener:
407  * @listener: a pointer to the #AccessibleKeystrokeListener for which
408  *            keystroke events are requested.
409  * @modmask:  the key modifier mask for which this listener is to be
410  *            'deregistered' (of type #AccessibleeyMaskType).
411  *
412  * Removes a keystroke event listener from the registry's listener queue,
413  *            ceasing notification of events with modifiers matching @modmask.
414  *
415  * Returns: #TRUE if successful, otherwise #FALSE.
416  **/
417 SPIBoolean
418 SPI_deregisterAccessibleKeystrokeListener (AccessibleKeystrokeListener *listener,
419                                            AccessibleKeyMaskType modmask)
420 {
421   Accessibility_ControllerEventMask   controller_event_mask;
422   Accessibility_KeySet                key_set;
423   Accessibility_KeyEventTypeSeq       key_events;
424   Accessibility_DeviceEventController device_event_controller;
425
426   if (!listener)
427     {
428       return FALSE;
429     }
430
431   device_event_controller = 
432     Accessibility_Registry_getDeviceEventController (cspi_registry (), cspi_ev ());
433
434   cspi_return_val_if_ev ("getting keystroke listener", FALSE);
435
436   controller_event_mask = (CORBA_unsigned_long) modmask;
437
438   key_events._buffer = NULL;
439   key_events._length = 0;
440
441   key_set._buffer = NULL;
442   key_set._length = 0;
443
444   Accessibility_DeviceEventController_deregisterKeystrokeListener (
445     device_event_controller,
446     cspi_event_listener_get_corba (listener),
447     &key_set,
448     controller_event_mask,
449     &key_events,
450     cspi_ev ());
451
452   cspi_release_unref (device_event_controller);
453
454   return TRUE;
455 }
456
457 /**
458  * SPI_generateKeyboardEvent:
459  * @keyval: a long integer indicating the keycode or keysym of the key event
460  *           being synthesized.
461  * @synth_type: a #AccessibleKeySynthType flag indicating whether @keyval
462  *           is to be interpreted as a keysym rather than a keycode
463  *           (CSPI_KEYSYM), or whether to synthesize
464  *           SPI_KEY_PRESS, SPI_KEY_RELEASE, or both (SPI_KEY_PRESSRELEASE).
465  *
466  * Synthesize a keyboard event (as if a hardware keyboard event occurred in the
467  * current UI context).
468  *
469  * Returns: #TRUE if successful, otherwise #FALSE.
470  **/
471 SPIBoolean
472 SPI_generateKeyboardEvent (long int keyval,
473                            char *keystring,
474                            AccessibleKeySynthType synth_type)
475 {
476 /* TODO: check current modifier status and
477  *  send keycode to alter, if necessary
478  */
479         
480   /* TODO: implement keystring use case */
481   Accessibility_KeySynthType keysynth_type;
482   Accessibility_DeviceEventController device_event_controller = 
483           Accessibility_Registry_getDeviceEventController (cspi_registry (), cspi_ev ());
484
485   cspi_return_val_if_ev ("getting event controller for key event gen", FALSE);
486
487   switch (synth_type)
488     {
489       case SPI_KEY_PRESS:
490           keysynth_type = Accessibility_KEY_PRESS;
491           break;
492       case SPI_KEY_RELEASE:
493           keysynth_type = Accessibility_KEY_RELEASE;
494           break;
495       case SPI_KEY_PRESSRELEASE:
496           keysynth_type = Accessibility_KEY_PRESSRELEASE;
497           break;
498       case SPI_KEY_SYM:
499           keysynth_type = Accessibility_KEY_SYM;
500           break;
501       case SPI_KEY_STRING:
502           keysynth_type = Accessibility_KEY_STRING;
503           break;
504     }
505
506   Accessibility_DeviceEventController_generateKeyboardEvent (device_event_controller,
507                                                              keyval,
508                                                              "",
509                                                              keysynth_type,
510                                                              cspi_ev ());
511
512   cspi_return_val_if_ev ("generating keyboard event", FALSE);
513
514   cspi_release_unref (device_event_controller);
515
516   return TRUE;
517 }
518
519 /**
520  * SPI_generateMouseEvent:
521  * @x: a #long indicating the screen x coordinate of the mouse event.
522  * @y: a #long indicating the screen y coordinate of the mouse event.
523  * @name: a string indicating which mouse event to be synthesized
524  *        (e.g. "button1", "button2", "mousemove").
525  *
526  * Synthesize a mouse event at a specific screen coordinate.
527  * Most AT clients should use the #AccessibleAction interface when
528  * tempted to generate mouse events, rather than this method.
529  * Not Yet Implemented.
530  *
531  * Returns: #TRUE if successful, otherwise #FALSE.
532  **/
533 SPIBoolean
534 SPI_generateMouseEvent (long x, long y, char *name)
535 {
536   return FALSE;
537 }
538