Bugfix for keylistener problem.
[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  * 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           key_set._buffer[i].keycode = keys->keycodes[i];
350           key_set._buffer[i].keysym = keys->keysyms[i];
351           if (keys->keystrings && keys->keystrings[i]) 
352             {
353               key_set._buffer[i].keystring = keys->keystrings[i];
354             } 
355           else 
356             {
357               key_set._buffer[i].keystring = CORBA_string_dup("");
358             }
359         }
360     }
361   else
362     {
363       key_set._length = 0;
364       key_set._buffer = NULL;
365     }
366         
367   /* copy the event filter values from the C api into the CORBA KeyEventTypeSeq */
368   mask = 1;
369   i = 0;
370   do
371     {
372       if (mask & eventmask)
373         {
374           ++i; 
375         }
376       mask <<= 1;
377     }
378   while (mask & 0xFFFF);
379   
380   key_events._buffer = Accessibility_KeyEventTypeSeq_allocbuf (i);
381   i = 0;
382   if (eventmask & SPI_KEY_PRESSED)
383     {
384       key_events._buffer[i++] = Accessibility_KEY_PRESSED;
385     }
386   if (eventmask & SPI_KEY_RELEASED)
387     {
388       key_events._buffer[i++] = Accessibility_KEY_RELEASED;
389     }
390   key_events._length = i;
391   
392   controller_event_mask = (CORBA_unsigned_long) modmask;
393
394   listener_mode.synchronous =
395           (CORBA_boolean) ((sync_type & SPI_KEYLISTENER_SYNCHRONOUS)!=0);
396   listener_mode.preemptive =
397           (CORBA_boolean) ((sync_type & SPI_KEYLISTENER_CANCONSUME)!=0);
398   listener_mode.global =
399           (CORBA_boolean) ((sync_type & SPI_KEYLISTENER_ALL_WINDOWS)!=0);
400
401   Accessibility_DeviceEventController_registerKeystrokeListener (
402     device_event_controller,
403     cspi_event_listener_get_corba (listener),
404     &key_set,
405     controller_event_mask,
406     &key_events,
407     &listener_mode,
408     cspi_ev ());
409
410   cspi_return_val_if_ev ("registering keystroke listener", FALSE);
411
412   cspi_release_unref (device_event_controller);
413
414   return TRUE;
415 }
416
417 /**
418  * SPI_deregisterAccessibleKeystrokeListener:
419  * @listener: a pointer to the #AccessibleKeystrokeListener for which
420  *            keystroke events are requested.
421  * @modmask:  the key modifier mask for which this listener is to be
422  *            'deregistered' (of type #AccessibleeyMaskType).
423  *
424  * Removes a keystroke event listener from the registry's listener queue,
425  *            ceasing notification of events with modifiers matching @modmask.
426  *
427  * Returns: #TRUE if successful, otherwise #FALSE.
428  **/
429 SPIBoolean
430 SPI_deregisterAccessibleKeystrokeListener (AccessibleKeystrokeListener *listener,
431                                            AccessibleKeyMaskType        modmask)
432 {
433   Accessibility_ControllerEventMask   controller_event_mask;
434   Accessibility_KeySet                key_set;
435   Accessibility_KeyEventTypeSeq       key_events;
436   Accessibility_DeviceEventController device_event_controller;
437
438   if (!listener)
439     {
440       return FALSE;
441     }
442
443   device_event_controller = 
444     Accessibility_Registry_getDeviceEventController (cspi_registry (), cspi_ev ());
445
446   cspi_return_val_if_ev ("getting keystroke listener", FALSE);
447
448   controller_event_mask = (CORBA_unsigned_long) modmask;
449
450   key_events._buffer = NULL;
451   key_events._length = 0;
452
453   key_set._buffer = NULL;
454   key_set._length = 0;
455
456   Accessibility_DeviceEventController_deregisterKeystrokeListener (
457     device_event_controller,
458     cspi_event_listener_get_corba (listener),
459     &key_set,
460     controller_event_mask,
461     &key_events,
462     cspi_ev ());
463
464   cspi_release_unref (device_event_controller);
465
466   return TRUE;
467 }
468
469 /**
470  * SPI_generateKeyboardEvent:
471  * @keyval: a long integer indicating the keycode or keysym of the key event
472  *           being synthesized.
473  * @keystring: an (optional) UTF-8 string which, if @keyval is NULL,
474  *           indicates a 'composed' keyboard input string which is 
475  *           being synthesized; this type of keyboard event synthesis does
476  *           not emulate hardware keypresses but injects the string 
477  *           as though a composing input method (such as XIM) were used.
478  * @synth_type: a #AccessibleKeySynthType flag indicating whether @keyval
479  *           is to be interpreted as a keysym rather than a keycode
480  *           (CSPI_KEYSYM), or whether to synthesize
481  *           SPI_KEY_PRESS, SPI_KEY_RELEASE, or both (SPI_KEY_PRESSRELEASE).
482  *
483  * Synthesize a keyboard event (as if a hardware keyboard event occurred in the
484  * current UI context).
485  *
486  * Returns: #TRUE if successful, otherwise #FALSE.
487  **/
488 SPIBoolean
489 SPI_generateKeyboardEvent (long int keyval,
490                            char *keystring,
491                            AccessibleKeySynthType synth_type)
492 {
493 /* TODO: check current modifier status and
494  *  send keycode to alter, if necessary
495  */
496         
497   /* TODO: implement keystring use case */
498   Accessibility_KeySynthType keysynth_type;
499   Accessibility_DeviceEventController device_event_controller = 
500           Accessibility_Registry_getDeviceEventController (cspi_registry (), cspi_ev ());
501
502   cspi_return_val_if_ev ("getting event controller for key event gen", FALSE);
503
504   switch (synth_type)
505     {
506       case SPI_KEY_PRESS:
507           keysynth_type = Accessibility_KEY_PRESS;
508           break;
509       case SPI_KEY_RELEASE:
510           keysynth_type = Accessibility_KEY_RELEASE;
511           break;
512       case SPI_KEY_PRESSRELEASE:
513           keysynth_type = Accessibility_KEY_PRESSRELEASE;
514           break;
515       case SPI_KEY_SYM:
516           keysynth_type = Accessibility_KEY_SYM;
517           break;
518       case SPI_KEY_STRING:
519           keysynth_type = Accessibility_KEY_STRING;
520           break;
521       default:
522           return FALSE;
523     }
524
525   Accessibility_DeviceEventController_generateKeyboardEvent (device_event_controller,
526                                                              keyval,
527                                                              "",
528                                                              keysynth_type,
529                                                              cspi_ev ());
530
531   cspi_return_val_if_ev ("generating keyboard event", FALSE);
532
533   cspi_release_unref (device_event_controller);
534
535   return TRUE;
536 }
537
538 /**
539  * SPI_generateMouseEvent:
540  * @x: a #long indicating the screen x coordinate of the mouse event.
541  * @y: a #long indicating the screen y coordinate of the mouse event.
542  * @name: a string indicating which mouse event to be synthesized
543  *        (e.g. "b1p", "b1c", "b2r", "rel", "abs").
544  *
545  * Synthesize a mouse event at a specific screen coordinate.
546  * Most AT clients should use the #AccessibleAction interface when
547  * tempted to generate mouse events, rather than this method.
548  * Event names: b1p = button 1 press; b2r = button 2 release;
549  *              b3c = button 3 click; b2d = button 2 double-click;
550  *              abs = absolute motion; rel = relative motion.
551  *
552  * Returns: #TRUE if successful, otherwise #FALSE.
553  **/
554 SPIBoolean
555 SPI_generateMouseEvent (long x, long y, char *name)
556 {
557   Accessibility_DeviceEventController device_event_controller = 
558           Accessibility_Registry_getDeviceEventController (cspi_registry (), cspi_ev ());
559
560   cspi_return_val_if_ev ("getting event controller for mouse event gen", FALSE);
561
562   Accessibility_DeviceEventController_generateMouseEvent (device_event_controller,
563                                                           x, y, name, cspi_ev ());
564   cspi_return_val_if_ev ("generating mouse event", FALSE);
565
566   cspi_release_unref (device_event_controller);
567
568   return TRUE;
569 }
570