Updated NEWS; committed Marc's patch for state-change 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 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-description
46  *            object:property-change:accessible-parent
47  *            object:property-change:accessible-value
48  *            object:property-change:accessible-role
49  *            object:property-change:accessible-table-caption
50  *            object:property-change:accessible-table-column-description
51  *            object:property-change:accessible-table-column-header
52  *            object:property-change:accessible-table-row-description
53  *            object:property-change:accessible-table-row-header
54  *            object:property-change:accessible-table-summary
55  *
56  *    (other object events)
57  *
58  *            object:state-changed 
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_KEYSET_ALL_KEYS:
290  * @SPI_KEYSET_ALL_KEYS: A special value for an AccessibleKeySet type, which tacitly
291  *                       includes all keycodes and keyvals for the specified modifier set.
292  **/
293
294 /**
295  * SPI_registerAccessibleKeystrokeListener:
296  * @listener:  a pointer to the #AccessibleKeystrokeListener for which
297  *             keystroke events are requested.
298  * @keys:      a pointer to the #AccessibleKeySet indicating which
299  *             keystroke events are requested, or #CSPI_KEYSET_ALL_KEYS.
300  * @modmask:   an #AccessibleKeyMaskType mask indicating which
301  *             key event modifiers must be set in combination with @keys,
302  *             events will only be reported for key events for which all
303  *             modifiers in @modmask are set.  If you wish to listen for
304  *             events with multiple modifier combinations you must call
305  *             registerAccessibleKeystrokeListener() once for each combination.
306  * @eventmask: an #AccessibleKeyMaskType mask indicating which
307  *             types of key events are requested (#SPI_KEY_PRESSED, etc.).
308  * @sync_type: a #AccessibleKeyListenerSyncType parameter indicating
309  *             the behavior of the notification/listener transaction.
310  *             
311  * Register a listener for keystroke events, either pre-emptively for
312  *             all windows (CSPI_KEYLISTENER_ALL_WINDOWS), or
313  *             non-preemptively (CSPI_KEYLISTENER_NOSYNC).
314  *             ( Other sync_type values may be available in the future.)
315  *
316  * Returns: #TRUE if successful, otherwise #FALSE.
317  **/
318 SPIBoolean
319 SPI_registerAccessibleKeystrokeListener (AccessibleKeystrokeListener  *listener,
320                                          AccessibleKeySet             *keys,
321                                          AccessibleKeyMaskType         modmask,
322                                          AccessibleKeyEventMask        eventmask,
323                                          AccessibleKeyListenerSyncType sync_type)
324 {
325   gint                                i, mask;
326   Accessibility_KeySet                key_set;
327   Accessibility_KeyEventTypeSeq       key_events;
328   Accessibility_ControllerEventMask   controller_event_mask;
329   Accessibility_DeviceEventController device_event_controller;
330   Accessibility_EventListenerMode     listener_mode;
331
332   if (!listener)
333     {
334       return FALSE;
335     }
336
337   device_event_controller = 
338     Accessibility_Registry_getDeviceEventController (cspi_registry (), cspi_ev ());
339
340   cspi_return_val_if_ev ("getting event controller", FALSE);
341
342   /* copy the keyval filter values from the C api into the CORBA KeySet */
343   if (keys)
344     {
345       key_set._length = keys->len;
346       key_set._buffer = Accessibility_KeySet_allocbuf (keys->len);
347       for (i = 0; i < key_set._length; ++i)
348         {
349           /* we overload the keyset long w/keycodes, the - bit acts as a flag */
350           key_set._buffer[i] = (keys->keysyms[i]) ? keys->keysyms[i] :
351                                                   - keys->keycodes[i];
352           /* fprintf (stderr, "key-set %d = %d\n", i, (int) key_set->_buffer[i]); */
353         }
354     }
355   else
356     {
357       key_set._length = 0;
358       key_set._buffer = NULL;
359     }
360         
361   /* copy the event filter values from the C api into the CORBA KeyEventTypeSeq */
362   mask = 1;
363   i = 0;
364   do
365     {
366       if (mask & eventmask)
367         {
368           ++i; 
369         }
370       mask <<= 1;
371     }
372   while (mask & 0xFFFF);
373   
374   key_events._buffer = Accessibility_KeyEventTypeSeq_allocbuf (i);
375   i = 0;
376   if (eventmask & SPI_KEY_PRESSED)
377     {
378       key_events._buffer[i++] = Accessibility_KEY_PRESSED;
379     }
380   if (eventmask & SPI_KEY_RELEASED)
381     {
382       key_events._buffer[i++] = Accessibility_KEY_RELEASED;
383     }
384   key_events._length = i;
385   
386   controller_event_mask = (CORBA_unsigned_long) modmask;
387
388   listener_mode.synchronous =
389           (CORBA_boolean) ((sync_type & SPI_KEYLISTENER_SYNCHRONOUS)!=0);
390   listener_mode.preemptive =
391           (CORBA_boolean) ((sync_type & SPI_KEYLISTENER_CANCONSUME)!=0);
392   listener_mode.global =
393           (CORBA_boolean) ((sync_type & SPI_KEYLISTENER_ALL_WINDOWS)!=0);
394
395   Accessibility_DeviceEventController_registerKeystrokeListener (
396     device_event_controller,
397     cspi_event_listener_get_corba (listener),
398     &key_set,
399     controller_event_mask,
400     &key_events,
401     &listener_mode,
402     cspi_ev ());
403
404   cspi_return_val_if_ev ("registering keystroke listener", FALSE);
405
406   cspi_release_unref (device_event_controller);
407
408   return TRUE;
409 }
410
411 /**
412  * SPI_deregisterAccessibleKeystrokeListener:
413  * @listener: a pointer to the #AccessibleKeystrokeListener for which
414  *            keystroke events are requested.
415  * @modmask:  the key modifier mask for which this listener is to be
416  *            'deregistered' (of type #AccessibleeyMaskType).
417  *
418  * Removes a keystroke event listener from the registry's listener queue,
419  *            ceasing notification of events with modifiers matching @modmask.
420  *
421  * Returns: #TRUE if successful, otherwise #FALSE.
422  **/
423 SPIBoolean
424 SPI_deregisterAccessibleKeystrokeListener (AccessibleKeystrokeListener *listener,
425                                            AccessibleKeyMaskType        modmask)
426 {
427   Accessibility_ControllerEventMask   controller_event_mask;
428   Accessibility_KeySet                key_set;
429   Accessibility_KeyEventTypeSeq       key_events;
430   Accessibility_DeviceEventController device_event_controller;
431
432   if (!listener)
433     {
434       return FALSE;
435     }
436
437   device_event_controller = 
438     Accessibility_Registry_getDeviceEventController (cspi_registry (), cspi_ev ());
439
440   cspi_return_val_if_ev ("getting keystroke listener", FALSE);
441
442   controller_event_mask = (CORBA_unsigned_long) modmask;
443
444   key_events._buffer = NULL;
445   key_events._length = 0;
446
447   key_set._buffer = NULL;
448   key_set._length = 0;
449
450   Accessibility_DeviceEventController_deregisterKeystrokeListener (
451     device_event_controller,
452     cspi_event_listener_get_corba (listener),
453     &key_set,
454     controller_event_mask,
455     &key_events,
456     cspi_ev ());
457
458   cspi_release_unref (device_event_controller);
459
460   return TRUE;
461 }
462
463 /**
464  * SPI_generateKeyboardEvent:
465  * @keyval: a long integer indicating the keycode or keysym of the key event
466  *           being synthesized.
467  * @keystring: an (optional) UTF-8 string which, if @keyval is NULL,
468  *           indicates a 'composed' keyboard input string which is 
469  *           being synthesized; this type of keyboard event synthesis does
470  *           not emulate hardware keypresses but injects the string 
471  *           as though a composing input method (such as XIM) were used.
472  * @synth_type: a #AccessibleKeySynthType flag indicating whether @keyval
473  *           is to be interpreted as a keysym rather than a keycode
474  *           (CSPI_KEYSYM), or whether to synthesize
475  *           SPI_KEY_PRESS, SPI_KEY_RELEASE, or both (SPI_KEY_PRESSRELEASE).
476  *
477  * Synthesize a keyboard event (as if a hardware keyboard event occurred in the
478  * current UI context).
479  *
480  * Returns: #TRUE if successful, otherwise #FALSE.
481  **/
482 SPIBoolean
483 SPI_generateKeyboardEvent (long int keyval,
484                            char *keystring,
485                            AccessibleKeySynthType synth_type)
486 {
487 /* TODO: check current modifier status and
488  *  send keycode to alter, if necessary
489  */
490         
491   /* TODO: implement keystring use case */
492   Accessibility_KeySynthType keysynth_type;
493   Accessibility_DeviceEventController device_event_controller = 
494           Accessibility_Registry_getDeviceEventController (cspi_registry (), cspi_ev ());
495
496   cspi_return_val_if_ev ("getting event controller for key event gen", FALSE);
497
498   switch (synth_type)
499     {
500       case SPI_KEY_PRESS:
501           keysynth_type = Accessibility_KEY_PRESS;
502           break;
503       case SPI_KEY_RELEASE:
504           keysynth_type = Accessibility_KEY_RELEASE;
505           break;
506       case SPI_KEY_PRESSRELEASE:
507           keysynth_type = Accessibility_KEY_PRESSRELEASE;
508           break;
509       case SPI_KEY_SYM:
510           keysynth_type = Accessibility_KEY_SYM;
511           break;
512       case SPI_KEY_STRING:
513           keysynth_type = Accessibility_KEY_STRING;
514           break;
515       default:
516           return FALSE;
517     }
518
519   Accessibility_DeviceEventController_generateKeyboardEvent (device_event_controller,
520                                                              keyval,
521                                                              "",
522                                                              keysynth_type,
523                                                              cspi_ev ());
524
525   cspi_return_val_if_ev ("generating keyboard event", FALSE);
526
527   cspi_release_unref (device_event_controller);
528
529   return TRUE;
530 }
531
532 /**
533  * SPI_generateMouseEvent:
534  * @x: a #long indicating the screen x coordinate of the mouse event.
535  * @y: a #long indicating the screen y coordinate of the mouse event.
536  * @name: a string indicating which mouse event to be synthesized
537  *        (e.g. "b1p", "b1c", "b2r", "rel", "abs").
538  *
539  * Synthesize a mouse event at a specific screen coordinate.
540  * Most AT clients should use the #AccessibleAction interface when
541  * tempted to generate mouse events, rather than this method.
542  * Event names: b1p = button 1 press; b2r = button 2 release;
543  *              b3c = button 3 click; b2d = button 2 double-click;
544  *              abs = absolute motion; rel = relative motion.
545  *
546  * Returns: #TRUE if successful, otherwise #FALSE.
547  **/
548 SPIBoolean
549 SPI_generateMouseEvent (long x, long y, char *name)
550 {
551   Accessibility_DeviceEventController device_event_controller = 
552           Accessibility_Registry_getDeviceEventController (cspi_registry (), cspi_ev ());
553
554   cspi_return_val_if_ev ("getting event controller for mouse event gen", FALSE);
555
556   Accessibility_DeviceEventController_generateMouseEvent (device_event_controller,
557                                                           x, y, name, cspi_ev ());
558   cspi_return_val_if_ev ("generating mouse event", FALSE);
559
560   cspi_release_unref (device_event_controller);
561
562   return TRUE;
563 }
564