Fix for 95827, adds API for registering "AccessibleDeviceListeners"
[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 /**
29  * SPI_registerGlobalEventListener:
30  * @listener: the #AccessibleEventListener to be registered against an
31  *            event type.
32  * @eventType: a character string indicating the type of events for which
33  *            notification is requested.  Format is
34  *            EventClass:major_type:minor_type:detail
35  *            where all subfields other than EventClass are optional.
36  *            EventClasses include "object", "window", "mouse",
37  *            and toolkit events (e.g. "Gtk", "AWT").
38  *            Examples: "focus:", "Gtk:GtkWidget:button_press_event".
39  *
40  * Legal object event types:
41  *
42  *    (property change events)
43  *
44  *            object:property-change
45  *            object:property-change:accessible-name
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:state-changed 
60  *            object:children-changed
61  *            object:visible-data-changed
62  *            object:selection-changed
63  *            object:text-selection-changed
64  *            object:text-changed
65  *            object:text-caret-moved
66  *            object:row-inserted
67  *            object:row-reordered
68  *            object:row-deleted
69  *            object:column-inserted
70  *            object:column-reordered
71  *            object:column-deleted
72  *            object:model-changed
73  *
74  *  (window events)
75  *
76  *            window:minimize
77  *            window:maximize
78  *            window:restore
79  *            window:close
80  *            window:create
81  *            window:reparent
82  *            window:desktop-create
83  *            window:desktop-destroy
84  *            window:activate
85  *            window:deactivate
86  *            window:raise
87  *            window:lower
88  *            window:move
89  *            window:resize
90  *            window:shade
91  *            window:unshade
92  *            window:restyle
93  *
94  *  (other events)
95  *
96  *            focus:
97  *            mouse:abs
98  *            mouse:rel
99  *            mouse:b1p
100  *            mouse:b1r
101  *            mouse:b2p
102  *            mouse:b2r
103  *            mouse:b3p
104  *            mouse:b3r
105  *
106  * NOTE: this string may be UTF-8, but should not contain byte value 56
107  *            (ascii ':'), except as a delimiter, since non-UTF-8 string
108  *            delimiting functions are used internally.
109  *            In general, listening to
110  *            toolkit-specific events is not recommended.
111  *
112  * Add an in-process callback function to an existing AccessibleEventListener.
113  *
114  * Returns: #TRUE if successful, otherwise #FALSE.
115  **/
116 SPIBoolean
117 SPI_registerGlobalEventListener (AccessibleEventListener *listener,
118                                  const char              *eventType)
119 {
120   if (!listener)
121     {
122       return FALSE;
123     }
124
125   Accessibility_Registry_registerGlobalEventListener (
126     cspi_registry (),
127     cspi_event_listener_get_corba (listener),
128     eventType, cspi_ev ());
129
130   return  !cspi_exception ();
131 }
132
133 /**
134  * SPI_deregisterGlobalEventListenerAll:
135  * @listener: the #AccessibleEventListener to be registered against
136  *            an event type.
137  *
138  * deregisters an AccessibleEventListener from the registry, for all
139  *            event types it may be listening to. Use
140  *            AccessibleEventListener_unref to release the
141  *            listener reference.
142  *
143  * Returns: #TRUE if successful, otherwise #FALSE.
144  **/
145 SPIBoolean
146 SPI_deregisterGlobalEventListenerAll (AccessibleEventListener *listener)
147 {
148   if (!listener)
149     {
150       return FALSE;
151     }
152
153   Accessibility_Registry_deregisterGlobalEventListenerAll (
154     cspi_registry (),
155     cspi_event_listener_get_corba (listener),
156     cspi_ev ());
157
158   return !cspi_exception ();
159 }
160
161 /**
162  * SPI_deregisterGlobalEventListener:
163  * @listener: the #AccessibleEventListener registered against an event type.
164  * @eventType: a string specifying the event type for which this
165  *             listener is to be deregistered.
166  *
167  * deregisters an AccessibleEventListener from the registry, for a specific
168  *             event type.
169  *
170  * Returns: #TRUE if successful, otherwise #FALSE.
171  **/
172 SPIBoolean
173 SPI_deregisterGlobalEventListener (AccessibleEventListener *listener,
174                                    const char              *eventType)
175 {
176   if (!listener)
177     {
178       return FALSE;
179     }
180
181   Accessibility_Registry_deregisterGlobalEventListener (
182     cspi_registry (), 
183     cspi_event_listener_get_corba (listener),
184     eventType, cspi_ev ());
185
186   return !cspi_exception ();
187 }
188
189 /**
190  * SPI_getDesktopCount:
191  *
192  * Get the number of virtual desktops.
193  * NOTE: currently multiple virtual desktops are not implemented, this
194  *       function always returns '1'.
195  *
196  * Returns: an integer indicating the number of active virtual desktops.
197  **/
198 int
199 SPI_getDesktopCount ()
200 {
201   int retval;
202
203   retval = Accessibility_Registry_getDesktopCount (
204     cspi_registry (), cspi_ev ());
205
206   cspi_return_val_if_ev ("getDesktopCount", -1);
207
208   return retval;
209 }
210
211 /**
212  * SPI_getDesktop:
213  * @i: an integer indicating which of the accessible desktops is to be returned.
214  *
215  * Get the virtual desktop indicated by index @i.
216  * NOTE: currently multiple virtual desktops are not implemented, this
217  *       function always returns '1'.
218  *
219  * Returns: a pointer to the 'i-th' virtual desktop's #Accessible representation.
220  **/
221 Accessible*
222 SPI_getDesktop (int i)
223 {
224   return cspi_object_add (
225     Accessibility_Registry_getDesktop (
226       cspi_registry (), i, cspi_ev ()));
227 }
228
229 /**
230  * SPI_getDesktopList:
231  * @desktop_list: a pointer to an array of #Accessible references.
232  *
233  * Get the list of virtual desktops.  On return, @list will point
234  *     to a newly-created, NULL terminated array of virtual desktop
235  *     pointers.
236  *     It is the responsibility of the caller to free this array when
237  *     it is no longer needed.
238  *
239  * Not Yet Implemented : this implementation always returns a single
240  * #Accessible desktop.
241  *
242  * Returns: an integer indicating how many virtual desktops have been
243  *          placed in the list pointed to by parameter @list.
244  **/
245 int
246 SPI_getDesktopList (Accessible ***desktop_list)
247 {
248   int i;
249   Accessible **list;
250   Accessibility_DesktopSeq *desktops;
251
252   if (!desktop_list)
253           return 0;
254
255   *desktop_list = NULL;
256
257   desktops = Accessibility_Registry_getDesktopList (cspi_registry (),
258                                                     cspi_ev ());
259
260   cspi_return_val_if_ev ("getDesktopList", 0);
261
262   list = g_new0 (Accessible *, desktops->_length + 1);
263
264   for (i = 0; i < desktops->_length; i++)
265     {
266       list [i] = cspi_object_add (
267               CORBA_Object_duplicate (desktops->_buffer [i], cspi_ev ()));
268     }
269   list [i] = NULL;
270
271   CORBA_free (desktops);
272
273   *desktop_list = list;
274
275   return i;
276 }
277
278 /**
279  * SPI_freeDesktopList:
280  * @desktop_list: a pointer to an array of #Accessible objects
281  * as returned from @SPI_getDesktopList
282  * 
283  * This routine frees the memory associated with the list.
284  **/
285 void
286 SPI_freeDesktopList (Accessible **desktop_list)
287 {
288   Accessible **p;
289   
290   for (p = desktop_list; p && *p; p++)
291     {
292       cspi_object_unref (*p);
293     }
294   g_free (desktop_list);
295 }
296
297 /**
298  * SPI_KEYSET_ALL_KEYS:
299  * @SPI_KEYSET_ALL_KEYS: A special value for an AccessibleKeySet type, which tacitly
300  *                       includes all keycodes and keyvals for the specified modifier set.
301  **/
302
303 /**
304  * SPI_registerAccessibleKeystrokeListener:
305  * @listener:  a pointer to the #AccessibleKeystrokeListener for which
306  *             keystroke events are requested.
307  * @keys:      a pointer to the #AccessibleKeySet indicating which
308  *             keystroke events are requested, or #CSPI_KEYSET_ALL_KEYS.
309  * @modmask:   an #AccessibleKeyMaskType mask indicating which
310  *             key event modifiers must be set in combination with @keys,
311  *             events will only be reported for key events for which all
312  *             modifiers in @modmask are set.  If you wish to listen for
313  *             events with multiple modifier combinations you must call
314  *             registerAccessibleKeystrokeListener() once for each combination.
315  * @eventmask: an #AccessibleKeyMaskType mask indicating which
316  *             types of key events are requested (#SPI_KEY_PRESSED, etc.).
317  * @sync_type: a #AccessibleKeyListenerSyncType parameter indicating
318  *             the behavior of the notification/listener transaction.
319  *             
320  * Register a listener for keystroke events, either pre-emptively for
321  *             all windows (CSPI_KEYLISTENER_ALL_WINDOWS), or
322  *             non-preemptively (CSPI_KEYLISTENER_NOSYNC).
323  *             ( Other sync_type values may be available in the future.)
324  *
325  * Returns: #TRUE if successful, otherwise #FALSE.
326  **/
327 SPIBoolean
328 SPI_registerAccessibleKeystrokeListener (AccessibleKeystrokeListener  *listener,
329                                          AccessibleKeySet             *keys,
330                                          AccessibleKeyMaskType         modmask,
331                                          AccessibleKeyEventMask        eventmask,
332                                          AccessibleKeyListenerSyncType sync_type)
333 {
334   gint                                i, mask;
335   Accessibility_KeySet                key_set;
336   Accessibility_KeyEventTypeSeq       key_events;
337   Accessibility_ControllerEventMask   controller_event_mask;
338   Accessibility_DeviceEventController device_event_controller;
339   Accessibility_EventListenerMode     listener_mode;
340   Accessibility_KeyEventType          key_event_types [2];
341   SPIBoolean                          retval = FALSE;
342
343   if (!listener)
344     {
345       return retval;
346     }
347
348   device_event_controller = 
349     Accessibility_Registry_getDeviceEventController (cspi_registry (), cspi_ev ());
350
351   cspi_return_val_if_ev ("getting event controller", FALSE);
352
353   /* copy the keyval filter values from the C api into the CORBA KeySet */
354   if (keys)
355     {
356       key_set._length = keys->len;
357       key_set._buffer = Accessibility_KeySet_allocbuf (keys->len);
358       for (i = 0; i < key_set._length; ++i)
359         {
360           key_set._buffer[i].keycode = keys->keycodes[i];
361           key_set._buffer[i].keysym = keys->keysyms[i];
362           if (keys->keystrings && keys->keystrings[i]) 
363             {
364               key_set._buffer[i].keystring = CORBA_string_dup(keys->keystrings[i]);
365             } 
366           else 
367             {
368               key_set._buffer[i].keystring = CORBA_string_dup("");
369             }
370         }
371     }
372   else
373     {
374       key_set._length = 0;
375       key_set._buffer = NULL;
376     }
377         
378   /* copy the event filter values from the C api into the CORBA KeyEventTypeSeq */
379   i = 0;
380   key_events._buffer = key_event_types;
381   if (eventmask & SPI_KEY_PRESSED)
382     {
383       key_events._buffer[i++] = Accessibility_KEY_PRESSED;
384     }
385   if (eventmask & SPI_KEY_RELEASED)
386     {
387       key_events._buffer[i++] = Accessibility_KEY_RELEASED;
388     }
389   key_events._length = i;
390   
391   controller_event_mask = (CORBA_unsigned_long) modmask;
392
393   listener_mode.synchronous =
394           (CORBA_boolean) ((sync_type & SPI_KEYLISTENER_SYNCHRONOUS)!=0);
395   listener_mode.preemptive =
396           (CORBA_boolean) ((sync_type & SPI_KEYLISTENER_CANCONSUME)!=0);
397   listener_mode.global =
398           (CORBA_boolean) ((sync_type & SPI_KEYLISTENER_ALL_WINDOWS)!=0);
399
400   retval = Accessibility_DeviceEventController_registerKeystrokeListener (
401     device_event_controller,
402     cspi_event_listener_get_corba (listener),
403     &key_set,
404     controller_event_mask,
405     &key_events,
406     &listener_mode,
407     cspi_ev ());
408
409   CORBA_free (key_set._buffer);
410
411   cspi_return_val_if_ev ("registering keystroke listener", FALSE);
412
413   cspi_release_unref (device_event_controller);
414
415   return retval;
416 }
417
418 /**
419  * SPI_deregisterAccessibleKeystrokeListener:
420  * @listener: a pointer to the #AccessibleKeystrokeListener for which
421  *            keystroke events are requested.
422  * @modmask:  the key modifier mask for which this listener is to be
423  *            'deregistered' (of type #AccessibleeyMaskType).
424  *
425  * Removes a keystroke event listener from the registry's listener queue,
426  *            ceasing notification of events with modifiers matching @modmask.
427  *
428  * Returns: #TRUE if successful, otherwise #FALSE.
429  **/
430 SPIBoolean
431 SPI_deregisterAccessibleKeystrokeListener (AccessibleKeystrokeListener *listener,
432                                            AccessibleKeyMaskType        modmask)
433 {
434   Accessibility_ControllerEventMask   controller_event_mask;
435   Accessibility_KeySet                key_set;
436   Accessibility_KeyEventTypeSeq       key_events;
437   Accessibility_DeviceEventController device_event_controller;
438
439   if (!listener)
440     {
441       return FALSE;
442     }
443
444   device_event_controller = 
445     Accessibility_Registry_getDeviceEventController (cspi_registry (), cspi_ev ());
446
447   cspi_return_val_if_ev ("getting keystroke listener", FALSE);
448
449   controller_event_mask = (CORBA_unsigned_long) modmask;
450
451   key_events._buffer = NULL;
452   key_events._length = 0;
453
454   key_set._buffer = NULL;
455   key_set._length = 0;
456
457   Accessibility_DeviceEventController_deregisterKeystrokeListener (
458     device_event_controller,
459     cspi_event_listener_get_corba (listener),
460     &key_set,
461     controller_event_mask,
462     &key_events,
463     cspi_ev ());
464
465   cspi_release_unref (device_event_controller);
466
467   return TRUE;
468 }
469
470 /**
471  * SPI_registerDeviceEventListener:
472  * @listener:  a pointer to the #AccessibleDeviceListener which requests
473  *             the events.
474  * @eventmask: an #AccessibleDeviceEventMask mask indicating which
475  *             types of key events are requested (#SPI_KEY_PRESSED, etc.).
476  *             
477  * Register a listener for device events, for instance button events.
478  *
479  * Returns: #TRUE if successful, otherwise #FALSE.
480  **/
481 SPIBoolean
482 SPI_registerDeviceEventListener (AccessibleDeviceListener  *listener,
483                                  AccessibleDeviceEventMask  eventmask,
484                                  void                      *filter)
485 {
486   Accessibility_DeviceEventController device_event_controller;
487   SPIBoolean                          retval = FALSE;
488   Accessibility_EventTypeSeq          event_types;
489   Accessibility_EventType             event_type_buffer[2];
490   gint                                i, mask;
491
492   if (!listener)
493     {
494       return retval;
495     }
496
497   device_event_controller = 
498     Accessibility_Registry_getDeviceEventController (cspi_registry (), cspi_ev ());
499
500   cspi_return_val_if_ev ("getting event controller", FALSE);
501
502   /* copy the event filter values from the C api into the CORBA KeyEventTypeSeq */
503   
504   event_types._buffer = event_type_buffer;
505   i = 0;
506
507   if (eventmask & SPI_BUTTON_PRESSED)
508     {
509       event_types._buffer[i++] = Accessibility_BUTTON_PRESSED_EVENT;
510     }
511   if (eventmask & SPI_BUTTON_RELEASED)
512     {
513       event_types._buffer[i++] = Accessibility_BUTTON_RELEASED_EVENT;
514     }
515
516   event_types._length = i;
517   
518   retval = Accessibility_DeviceEventController_registerDeviceEventListener (
519     device_event_controller,
520     cspi_event_listener_get_corba (listener),
521     &event_types,
522     cspi_ev ());
523
524   cspi_return_val_if_ev ("registering keystroke listener", FALSE);
525
526   cspi_release_unref (device_event_controller);
527
528   return retval;
529 }
530
531 /**
532  * SPI_deregisterDeviceEventListener:
533  * @listener: a pointer to the #AccessibleDeviceListener for which
534  *            device events are requested.
535  *
536  * Removes a device event listener from the registry's listener queue,
537  *            ceasing notification of events of the specified type.
538  *
539  * Returns: #TRUE if successful, otherwise #FALSE.
540  **/
541 SPIBoolean
542 SPI_deregisterDeviceEventListener (AccessibleDeviceListener *listener,
543                                    void                     *filter)
544 {
545   Accessibility_ControllerEventMask   controller_event_mask;
546   Accessibility_DeviceEventController device_event_controller;
547   Accessibility_EventTypeSeq       event_types;
548
549   if (!listener)
550     {
551       return FALSE;
552     }
553
554   device_event_controller = 
555     Accessibility_Registry_getDeviceEventController (cspi_registry (), cspi_ev ());
556
557   cspi_return_val_if_ev ("getting keystroke listener", FALSE);
558
559   event_types._buffer = Accessibility_EventTypeSeq_allocbuf (2);
560   event_types._length = 2;
561   event_types._buffer[0] = Accessibility_BUTTON_PRESSED_EVENT;
562   event_types._buffer[1] = Accessibility_BUTTON_RELEASED_EVENT;
563
564   Accessibility_DeviceEventController_deregisterDeviceEventListener (
565     device_event_controller,
566     cspi_event_listener_get_corba (listener),
567     &event_types,    
568     cspi_ev ());
569
570   cspi_release_unref (device_event_controller);
571
572   return TRUE;
573 }
574
575 /**
576  * SPI_generateKeyboardEvent:
577  * @keyval: a long integer indicating the keycode or keysym of the key event
578  *           being synthesized.
579  * @keystring: an (optional) UTF-8 string which, if @keyval is NULL,
580  *           indicates a 'composed' keyboard input string which is 
581  *           being synthesized; this type of keyboard event synthesis does
582  *           not emulate hardware keypresses but injects the string 
583  *           as though a composing input method (such as XIM) were used.
584  * @synth_type: a #AccessibleKeySynthType flag indicating whether @keyval
585  *           is to be interpreted as a keysym rather than a keycode
586  *           (CSPI_KEYSYM), or whether to synthesize
587  *           SPI_KEY_PRESS, SPI_KEY_RELEASE, or both (SPI_KEY_PRESSRELEASE).
588  *
589  * Synthesize a keyboard event (as if a hardware keyboard event occurred in the
590  * current UI context).
591  *
592  * Returns: #TRUE if successful, otherwise #FALSE.
593  **/
594 SPIBoolean
595 SPI_generateKeyboardEvent (long int keyval,
596                            char *keystring,
597                            AccessibleKeySynthType synth_type)
598 {
599 /* TODO: check current modifier status and
600  *  send keycode to alter, if necessary
601  */
602         
603   /* TODO: implement keystring use case */
604   Accessibility_KeySynthType keysynth_type;
605   Accessibility_DeviceEventController device_event_controller = 
606           Accessibility_Registry_getDeviceEventController (cspi_registry (), cspi_ev ());
607
608   cspi_return_val_if_ev ("getting event controller for key event gen", FALSE);
609
610   switch (synth_type)
611     {
612       case SPI_KEY_PRESS:
613           keysynth_type = Accessibility_KEY_PRESS;
614           break;
615       case SPI_KEY_RELEASE:
616           keysynth_type = Accessibility_KEY_RELEASE;
617           break;
618       case SPI_KEY_PRESSRELEASE:
619           keysynth_type = Accessibility_KEY_PRESSRELEASE;
620           break;
621       case SPI_KEY_SYM:
622           keysynth_type = Accessibility_KEY_SYM;
623           break;
624       case SPI_KEY_STRING:
625           keysynth_type = Accessibility_KEY_STRING;
626           break;
627       default:
628           return FALSE;
629     }
630
631   Accessibility_DeviceEventController_generateKeyboardEvent (device_event_controller,
632                                                              keyval,
633                                                              "",
634                                                              keysynth_type,
635                                                              cspi_ev ());
636
637   cspi_return_val_if_ev ("generating keyboard event", FALSE);
638
639   cspi_release_unref (device_event_controller);
640
641   return TRUE;
642 }
643
644 /**
645  * SPI_generateMouseEvent:
646  * @x: a #long indicating the screen x coordinate of the mouse event.
647  * @y: a #long indicating the screen y coordinate of the mouse event.
648  * @name: a string indicating which mouse event to be synthesized
649  *        (e.g. "b1p", "b1c", "b2r", "rel", "abs").
650  *
651  * Synthesize a mouse event at a specific screen coordinate.
652  * Most AT clients should use the #AccessibleAction interface when
653  * tempted to generate mouse events, rather than this method.
654  * Event names: b1p = button 1 press; b2r = button 2 release;
655  *              b3c = button 3 click; b2d = button 2 double-click;
656  *              abs = absolute motion; rel = relative motion.
657  *
658  * Returns: #TRUE if successful, otherwise #FALSE.
659  **/
660 SPIBoolean
661 SPI_generateMouseEvent (long x, long y, char *name)
662 {
663   Accessibility_DeviceEventController device_event_controller = 
664           Accessibility_Registry_getDeviceEventController (cspi_registry (), cspi_ev ());
665
666   cspi_return_val_if_ev ("getting event controller for mouse event gen", FALSE);
667
668   Accessibility_DeviceEventController_generateMouseEvent (device_event_controller,
669                                                           x, y, name, cspi_ev ());
670   cspi_return_val_if_ev ("generating mouse event", FALSE);
671
672   cspi_release_unref (device_event_controller);
673
674   return TRUE;
675 }
676