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