Enhancements to Magnifier.idl, based on feedback from Gnopernicus team.
authorbillh <billh@e2bd861d-eb25-0410-b326-f6ed22b6b98c>
Fri, 9 Nov 2001 00:06:14 +0000 (00:06 +0000)
committerbillh <billh@e2bd861d-eb25-0410-b326-f6ed22b6b98c>
Fri, 9 Nov 2001 00:06:14 +0000 (00:06 +0000)
Added support for 'passive grab' keylisteners (synchronous and
pre-emptive) to libspi.
Modifier simple-at.c to use these keylisteners (other types not yet
implemented) and provide some simple keyboard commands, including
a quit command that cleans up and deregisters cleanly.

git-svn-id: http://svn.gnome.org/svn/at-spi/trunk@83 e2bd861d-eb25-0410-b326-f6ed22b6b98c

27 files changed:
ChangeLog
configure.in
cspi/spi-listener.h
cspi/spi.h
cspi/spi_event.c
cspi/spi_main.c
cspi/spi_registry.c
idl/Accessibility_Registry.idl
idl/Registry.idl
libspi/Makefile.am
libspi/accessible.c
libspi/deviceeventcontroller.c
libspi/keystrokelistener.c
libspi/registry.c
registryd/Makefile.am
registryd/deviceeventcontroller.c
registryd/registry-main.c
registryd/registry.c
registryd/registryd.c
test/simple-at.c
util/idl/Magnifier.idl
util/mag_client.c
util/mag_client.h
util/mag_control.c
util/mag_image.c
util/mag_image.h
util/magnifier.c

index ebc1e6c..40ffba9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,63 @@
+2001-11-09  Bill Haneman <bill.haneman@sun.com
+
+       * libspi/Makefile.am: 
+       * registryd/Makefile.am:
+       (temporary) hack to include libXtst in libspi and registryd.
+       (Needed for keystroke synthesis, see below).
+
+       * idl/Registry.idl:
+       Improved API for registerKeystrokeListener, in accordance with
+       discussions with Gnopernicus team and X server research.
+
+       * libspi/registry.c:
+       * libspi/deviceeventcontroller.c:
+       * libspi/accessible.c:
+       * libspi/keystrokelistener.c:
+       Changes and fixes to support keylisteners for potentially
+       consumed key events (that is, 'passive grabs').
+       Added implementation for generateKeyEvent() [untested].
+
+       * cspi/spi.h:
+       Changes to registerKeystrokeListener() API, as above.
+       Added deregisterGlobalEventListenerAll(), and 
+       deregisterKeystrokeListener(), which are needed for clean exit of
+       clients.
+       Added typedefs for KeyListenerSyncType, KeyEventMask, and KeySet,
+       and a macro ALL_KEYS which may be used in place of a KeySet pointer.
+       
+       * cspi/spi_registry.c:
+       Added implementations of function prototypes mentioned above.
+       
+       * registryd/registryd.c:
+       Added the key listener event source as a g_timeout(), to allow
+       receipt of key events that are not caught by GDK (since GDK
+       doesn't support passive keygrabs, this was necessary).
+
+       * test/simple-at.c:
+       Changed to attach a keylistener to 'Alt' keys, and
+       respond to the following keycommands: Alt-M (toggle magnifier);
+       Alt-F (toggle speech); Alt-Q (quit).
+       Added an exit routine to deregister the listeners, and a key
+       listener that prints some key info to the console when a key
+       matches the listener mask (and is thus received by the listener).
+       
+       * util/idl/Magnifier.idl:
+       Changes to magnifier API to support multiple zoom regions,
+       non-uniform scaling in x and y, markDirty, and a host of other
+       features that would be useful to magnification.
+
+       * util/mag_image.h:
+       * util/mag_client.c:
+       * util/mag_client.h:
+       * util/mag_control.c:
+       * util/magnifier.c:
+       Source code changes to support the above IDL changes.
+       
+       * util/mag_image.c:
+       As above, and also changes to use a (slower) generic conversion
+       path for colormap conversions, since the fast RGB conversions have been
+       reported to fail for 16-bit displays.
+
 2001-10-26  Michael Meeks  <michael@ximian.com>
 
        * libspi/Makefile.am (orbittypelibdir): install in orbit-2.0
index 1cd1578..9a30f0d 100644 (file)
@@ -2,7 +2,7 @@ AC_INIT(idl/Accessible.idl)
 
 AT_SPI_MAJOR_VERSION=0
 AT_SPI_MINOR_VERSION=0
-AT_SPI_MICRO_VERSION=2
+AT_SPI_MICRO_VERSION=3
 AT_SPI_INTERFACE_AGE=0
 AT_SPI_BINARY_AGE=0
 AT_SPI_VERSION="$AT_SPI_MAJOR_VERSION.$AT_SPI_MINOR_VERSION.$AT_SPI_MICRO_VERSION"
index 616d74e..6aada88 100644 (file)
@@ -6,8 +6,9 @@
 extern "C" {
 #endif /* __cplusplus */
 
-#include "keystrokelistener.h"
 #include "accessibleeventlistener.h"
+#include "keystrokelistener.h"
+
 
 /*
  *
index 49a773b..f83d20c 100644 (file)
@@ -62,13 +62,30 @@ typedef enum _KeyEventType {
   KEY_RELEASED
 } KeyEventType;
 
+typedef enum _KeyListenerSyncType {
+  KEYLISTENER_SYNCHRONOUS = 1,
+  KEYLISTENER_CANCONSUME = 2,
+  KEYLISTENER_ALLWINDOWS = 4
+} KeyListenerSyncType;
+
+typedef unsigned long KeyEventMask;
+
 typedef struct _KeyStroke
 {
        long keyID;
+       short keycode;
        KeyEventType type;
        unsigned short modifiers;
 } KeyStroke;
 
+typedef struct _KeySet
+{
+       unsigned long *keysyms;
+       unsigned short *keycodes;
+       short len;
+} KeySet;
+
+#define ALL_KEYS ((void *)NULL)
 
 /*
  *
@@ -305,7 +322,11 @@ getDesktopList (Accessible **list);
  *
  **/
 void
-registerKeystrokeListener (KeystrokeListener *listener, KeyMaskType keymask);
+registerKeystrokeListener (KeystrokeListener *listener,
+                          KeySet *keys,
+                          KeyMaskType modmask,
+                          KeyEventMask eventmask,
+                          KeyListenerSyncType sync_type);
 
 /**
  * generateKeyEvent:
index 60081ac..4db0b71 100644 (file)
@@ -67,7 +67,7 @@ EventListener_removeCallback (AccessibleEventListener *listener,
 KeystrokeListener *
 createKeystrokeListener (KeystrokeListenerCB callback)
 {
-  KeystrokeListener *listener = g_object_new (KEYSTROKE_LISTENER_TYPE, NULL);
+  KeystrokeListener *listener = keystroke_listener_new ();
   if (callback)
     {
       keystroke_listener_add_callback (listener, callback);
@@ -110,3 +110,4 @@ KeystrokeListener_removeCallback (KeystrokeListener *listener,
   keystroke_listener_remove_callback (listener, callback);
   return TRUE;
 }
+
index ffbb447..c4e1891 100644 (file)
@@ -64,7 +64,7 @@ SPI_init (void)
 void
 SPI_event_main (boolean isGNOMEApp)
 {
-  if (isGNOMEApp) {
+  if (isGNOMEApp) {      
     g_atexit(SPI_exit);
     bonobo_main();
   }
index 28f39de..6be863a 100644 (file)
@@ -5,6 +5,10 @@
  *
  */
 
+/* static stuff used only by registry C bindings */
+static GList *key_listeners = NULL;
+static Display *display = NULL;
+
 /**
  * registerGlobalEventListener:
  * @listener: the #AccessibleEventListener to be registered against an event type.
@@ -48,6 +52,34 @@ registerGlobalEventListener (AccessibleEventListener *listener,
 }
 
 /**
+ * deregisterGlobalEventListener:
+ * @listener: the #AccessibleEventListener to be registered against an event type.
+ *
+ * deregisters an AccessibleEventListener from the registry, for all event types it may be listening to.
+ *
+ * Returns: #TRUE if successful, otherwise #FALSE.
+ *
+ **/
+boolean
+deregisterGlobalEventListenerAll (AccessibleEventListener *listener)
+{
+  Accessibility_Registry_deregisterGlobalEventListenerAll (
+                         registry,
+                         (Accessibility_EventListener)
+                            CORBA_Object_duplicate (bonobo_object_corba_objref (bonobo_object (listener)), &ev),
+                         &ev);
+
+  if (ev._major != CORBA_NO_EXCEPTION)
+    {
+    return FALSE;
+    }
+  else
+    {
+      return TRUE;
+    }
+}
+
+/**
  * getDesktopCount:
  *
  * Get the number of virtual desktops.
@@ -101,16 +133,68 @@ getDesktopList (Accessible **list)
   return 0;
 }
 
+static gboolean
+key_event_source_func (void *p)
+{
+  GList *listeners = (GList *)p;
+  XEvent *x_event = g_new0 (XEvent, 1);
+  while (XPending (display))
+    {
+      XNextEvent (display, x_event);
+      while (listeners)
+        {
+        /* if the listener mask matches, notify it*/
+          if (1)
+           {
+             ;   
+           }
+       }
+    }
+  return TRUE;
+}
+
+void
+save_this_impl_registerKeystrokeListener (KeystrokeListener *listener, KeyMaskType keymask)
+{
+  static gboolean initialized = FALSE;
+  static Window grab_window;
+  XEvent *x_event = g_new0(XEvent, 1);
+  key_listeners = g_list_append (key_listeners, listener);
+  if (!initialized)
+    {
+      g_timeout_add_full (G_PRIORITY_HIGH_IDLE, 200, key_event_source_func, key_listeners, NULL);
+      display = XOpenDisplay (getenv ("DISPLAY"));
+      grab_window = DefaultRootWindow (display);
+      XSelectInput (display, grab_window, KeyPress | KeyRelease);
+      initialized = TRUE;
+    }
+  /* */
+  XGrabKey (display,
+           AnyKey,
+           LockMask,
+           grab_window,
+           False,
+           GrabModeAsync,
+           GrabModeAsync);
+  while (0)
+  {
+         XNextEvent (display, x_event);
+         g_print ("foo!\n");
+  }
+}
 /**
  * registerKeystrokeListener:
  * @listener: a pointer to the #KeystrokeListener for which
  *            keystroke events are requested.
  *
- * Not Yet Implemented.
- *
  **/
 void
-registerKeystrokeListener (KeystrokeListener *listener, KeyMaskType keymask)
+registerKeystrokeListener (KeystrokeListener *listener,
+                          KeySet *keys,
+                          KeyMaskType modmask,
+                          KeyEventMask eventmask,
+                          KeyListenerSyncType sync_type)
 {
   Accessibility_ControllerEventMask *controller_event_mask =
          Accessibility_ControllerEventMask__alloc();
@@ -118,19 +202,50 @@ registerKeystrokeListener (KeystrokeListener *listener, KeyMaskType keymask)
          Accessibility_Registry_getDeviceEventController (registry, &ev);
   Accessibility_KeySet *all_keys = Accessibility_KeySet__alloc();
   Accessibility_KeyEventTypeSeq *key_events = Accessibility_KeyEventTypeSeq__alloc();
+  Accessibility_KeystrokeListener listener_corba_ref;
   Accessibility_DeviceEventController_ref (device_event_controller, &ev);
-  controller_event_mask->value = (CORBA_unsigned_long) keymask;
+  controller_event_mask->value = (CORBA_unsigned_long) modmask;
   controller_event_mask->refcount = (CORBA_unsigned_short) 1;
-  /*
-  fprintf (stderr, "controller %p, mask value %lu\n", (void *) device_event_controller,
-          (unsigned long) controller_event_mask->value );
-  */
 
+  listener_corba_ref = (Accessibility_KeystrokeListener)
+         CORBA_Object_duplicate (bonobo_object_corba_objref (bonobo_object (listener)), &ev);
+  
+         Accessibility_DeviceEventController_registerKeystrokeListener (
+         device_event_controller,
+         listener_corba_ref,
+         all_keys,
+         controller_event_mask,
+         key_events,
+         (CORBA_boolean) ((sync_type | KEYLISTENER_CANCONSUME)!=0),
+         &ev);
+}
+
+/**
+ * deregisterKeystrokeListener:
+ * @listener: a pointer to the #KeystrokeListener for which
+ *            keystroke events are requested.
+ *
+ **/
+void
+deregisterKeystrokeListener (KeystrokeListener *listener, KeyMaskType keymask)
+{
+  Accessibility_ControllerEventMask *controller_event_mask =
+         Accessibility_ControllerEventMask__alloc();
+  Accessibility_DeviceEventController device_event_controller = 
+         Accessibility_Registry_getDeviceEventController (registry, &ev);
+  Accessibility_KeySet *all_keys = Accessibility_KeySet__alloc();
+  Accessibility_KeyEventTypeSeq *key_events = Accessibility_KeyEventTypeSeq__alloc();
+  Accessibility_KeystrokeListener listener_corba_ref;
+  Accessibility_DeviceEventController_unref (device_event_controller, &ev);
+  controller_event_mask->value = (CORBA_unsigned_long) keymask;
+  controller_event_mask->refcount = (CORBA_unsigned_short) 1;
 
-  Accessibility_DeviceEventController_registerKeystrokeListener (
+  listener_corba_ref = (Accessibility_KeystrokeListener)
+         CORBA_Object_duplicate (bonobo_object_corba_objref (bonobo_object (listener)), &ev);
+  
+  Accessibility_DeviceEventController_deregisterKeystrokeListener (
          device_event_controller,
-         (Accessibility_KeystrokeListener)
-             bonobo_object_corba_objref (bonobo_object (listener)),
+         listener_corba_ref,
          all_keys,
          controller_event_mask,
          key_events,
index 96da28b..3d519ff 100644 (file)
@@ -175,6 +175,7 @@ module Accessibility {
 
   struct KeyStroke {
     long keyID;
+    short keycode;
     KeyEventType type; 
     unsigned short modifiers;
   };
@@ -182,7 +183,7 @@ module Accessibility {
   typedef sequence< long > KeySet;
   typedef sequence< KeyEventType > KeyEventTypeSeq;
 
-  interface KeystrokeListener {
+  interface KeystrokeListener : Bonobo::Unknown {
         boolean keyEvent (in KeyStroke key);
   };
 
@@ -210,6 +211,27 @@ module Accessibility {
                                        in KeyEventTypeSeq type,
                                        in boolean is_synchronous);
     
+       /**
+         * deregisterKeystrokeListener:
+         * @listener: a @KeystrokeListener which will intercept key events.
+         * @keys:     a @KeySet indicating which keys to intercept, or KEYSET_ALL_KEYS.
+         * @mask:     a @ControllerEventMask filtering the intercepted key events.
+        * @type:     an @EventType mask that may created by ORing event types together.
+        * @is_synchronous: a @boolean indicating whether the listener should 
+        *            receive the events synchronously, potentially consuming them,
+        *            or just be notified asynchronously of those events that have
+        *            been generated.
+        * Returns: void
+         *
+         * De-register a previously registered keyboard eventlistener.
+         *
+        **/
+        void deregisterKeystrokeListener (in KeystrokeListener listener,
+                                       in KeySet keys,
+                                       in ControllerEventMask mask,
+                                       in KeyEventTypeSeq type,
+                                       in boolean is_synchronous);
+    
         /**
          * generateKeyEvent:
          * @keyEventID: a long integer indicating which keypress is synthesized.
index 96da28b..3d519ff 100644 (file)
@@ -175,6 +175,7 @@ module Accessibility {
 
   struct KeyStroke {
     long keyID;
+    short keycode;
     KeyEventType type; 
     unsigned short modifiers;
   };
@@ -182,7 +183,7 @@ module Accessibility {
   typedef sequence< long > KeySet;
   typedef sequence< KeyEventType > KeyEventTypeSeq;
 
-  interface KeystrokeListener {
+  interface KeystrokeListener : Bonobo::Unknown {
         boolean keyEvent (in KeyStroke key);
   };
 
@@ -210,6 +211,27 @@ module Accessibility {
                                        in KeyEventTypeSeq type,
                                        in boolean is_synchronous);
     
+       /**
+         * deregisterKeystrokeListener:
+         * @listener: a @KeystrokeListener which will intercept key events.
+         * @keys:     a @KeySet indicating which keys to intercept, or KEYSET_ALL_KEYS.
+         * @mask:     a @ControllerEventMask filtering the intercepted key events.
+        * @type:     an @EventType mask that may created by ORing event types together.
+        * @is_synchronous: a @boolean indicating whether the listener should 
+        *            receive the events synchronously, potentially consuming them,
+        *            or just be notified asynchronously of those events that have
+        *            been generated.
+        * Returns: void
+         *
+         * De-register a previously registered keyboard eventlistener.
+         *
+        **/
+        void deregisterKeystrokeListener (in KeystrokeListener listener,
+                                       in KeySet keys,
+                                       in ControllerEventMask mask,
+                                       in KeyEventTypeSeq type,
+                                       in boolean is_synchronous);
+    
         /**
          * generateKeyEvent:
          * @keyEventID: a long integer indicating which keypress is synthesized.
index 2edd31a..82cf5d5 100644 (file)
@@ -6,7 +6,7 @@ INCLUDES = -I $(top_srcdir)           \
            -I $(top_builddir)/libspi  \
            $(LIBSPI_CFLAGS)
 
-LDFLAGS = $(LIBSPI_LIBS) @LT_VERSION_INFO@
+LDFLAGS = $(LIBSPI_LIBS) -lXtst @LT_VERSION_INFO@
 
 DEBUG_CFLAGS=-DSPI_DEBUG
 
index ad5a89f..24cbd43 100644 (file)
@@ -329,7 +329,7 @@ accessible_new (AtkObject *o)
         bonobo_object_add_interface (bonobo_object (retval),
                                      BONOBO_OBJECT (action_interface_new (o)));
       }
-      
+
     if (ATK_IS_COMPONENT (o))
       {
         bonobo_object_add_interface (bonobo_object (retval),
index 8966fda..f96d7b0 100644 (file)
@@ -30,6 +30,7 @@
 #endif
 
 #include <X11/Xlib.h>
+#include <X11/extensions/XTest.h>
 #include <config.h>
 #include <gdk/gdkx.h> /* TODO: hide dependency (wrap in single porting file) */
 #include <gdk/gdkwindow.h>
@@ -53,6 +54,10 @@ static GObjectClass *device_event_controller_parent_class;
 
 static gboolean kbd_registered = FALSE;
 
+static Display *display;
+
+static Window root_window;
+
 typedef enum {
   DEVICE_TYPE_KBD,
   DEVICE_TYPE_MOUSE,
@@ -90,11 +95,13 @@ _compare_corba_objects (gconstpointer p1, gconstpointer p2)
 static gint
 _eventmask_compare_value (gconstpointer p1, gconstpointer p2)
 {
+    long d;
     if (!p1 || !p2)
        return (gint) (p1?1:(p2?-1:0));
     else
-       return ((long)((Accessibility_ControllerEventMask*)p2)->value) -
+       d = ((long)((Accessibility_ControllerEventMask*)p2)->value) -
                ((long)((Accessibility_ControllerEventMask*)p1)->value);
+    return (gint) d;
 }
 
 static void
@@ -104,7 +111,7 @@ _controller_register_device_listener (DeviceEventController *controller,
                                      DeviceTypeCategory type,
                                      CORBA_Environment *ev)
 {
-  Accessibility_ControllerEventMask *mask_ptr;
+  Accessibility_ControllerEventMask *mask_ptr = NULL;
   
   switch (type) {
   case DEVICE_TYPE_KBD:
@@ -156,17 +163,21 @@ _controller_deregister_device_listener (DeviceEventController *controller,
       list_ptr = g_list_find_custom (controller->key_listeners, l, _compare_corba_objects);
       if (list_ptr)
          controller->key_listeners = g_list_remove (controller->key_listeners, list_ptr);
-      
-      mask_ptr = (Accessibility_ControllerEventMask *)
+      list_ptr = (GList *)
                  g_list_find_custom (controller->keymask_list, (gpointer) mask,
                                     _eventmask_compare_value);
-      if (mask_ptr)
+      if (list_ptr)
+        {
+         mask_ptr = (Accessibility_ControllerEventMask *) list_ptr->data;
+          if (mask_ptr)
              --mask_ptr->refcount;
-      if (!mask_ptr->refcount)
-      {
-          controller->keymask_list = g_list_remove (controller->keymask_list, mask_ptr);
-          ;  /* TODO: release any key grabs that are in place for this key mask */
-      }
+          if (!mask_ptr->refcount)
+            {
+             controller->keymask_list =
+                     g_list_remove (controller->keymask_list, mask_ptr);
+             ;  /* TODO: release any key grabs that are in place for this key mask */
+           }
+       }
       break;
   case DEVICE_TYPE_MOUSE:
 /*    controller->mouse_listeners = g_list_append (controller->mouse_listeners,
@@ -181,35 +192,28 @@ static gboolean
 _controller_register_with_devices (DeviceEventController *controller)
 {
   gboolean retval = FALSE;
-  Display *default_display;
-  Window root_window;
 
-  default_display = GDK_DISPLAY();
-  root_window = GDK_ROOT_WINDOW();  
   /* calls to device-specific implementations and routines go here */
   /* register with: keyboard hardware code handler */
   /* register with: (translated) keystroke handler */
 #ifdef SPI_DEBUG
-  fprintf (stderr, "About to request events on window %ld of display %p\n",
-          (unsigned long) root_window, default_display);
+  fprintf (stderr, "About to request events on window %ld of display %x\n",
+          (unsigned long) GDK_ROOT_WINDOW(), GDK_DISPLAY());
 #endif
-  XSelectInput (default_display,
-               root_window,
-               KeyPressMask);
-  XSelectInput (default_display,
+  /* We must open a new connection to the server to avoid clashing with the GDK event loop */
+  display = XOpenDisplay (getenv ("DISPLAY"));
+  root_window = DefaultRootWindow (display);           
+  XSelectInput (display,
                root_window,
-               KeyReleaseMask);
+               KeyPressMask | KeyReleaseMask);
   /* register with: mouse hardware device handler? */
   /* register with: mouse event handler */
   return retval;
 }
 
-static gboolean _check_key_event (DeviceEventController *controller)
+static gboolean
+_check_key_event (DeviceEventController *controller)
 {
-#ifdef SPI_DEBUG
-       static Accessibility_ControllerEventMask shiftlock_mask =
-               {(CORBA_unsigned_long) LockMask, (CORBA_unsigned_short) 1};
-#endif
        static gboolean initialized = FALSE;
        static gboolean is_active = FALSE;
        XEvent *x_event = g_new0 (XEvent, 1);
@@ -221,89 +225,75 @@ static gboolean _check_key_event (DeviceEventController *controller)
        int n_listeners = g_list_length (controller->key_listeners);
        Accessibility_KeyStroke key_event;
        static CORBA_Environment ev;
-       
+
        if (!initialized)
        {
-               initialized = TRUE;
-               CORBA_exception_init (&ev);
+         initialized = TRUE;
+         CORBA_exception_init (&ev);
        }
 
-/*        if (!XPending(GDK_DISPLAY())) return TRUE; */
-
-       /*
-        * the call to XPending seemed like a good idea, why did it
-        * wreak such havoc?
-        */
-
-       XPeekEvent (GDK_DISPLAY(), x_event);
-       if (x_event->type == KeyPress)
-       {
-           x_key_event = (XKeyEvent *)x_event;
-           keysym = XLookupKeysym (x_key_event, 0);
-           key_event.keyID = (CORBA_long)(keysym);
-           key_event.type = Accessibility_KEY_PRESSED;
-           key_event.modifiers = (CORBA_unsigned_short)(x_key_event->state);
-#if defined SPI_KEYEVENT_DEBUG
+       while (XPending(display))
+         {
+           XNextEvent (display, x_event);
+           if (x_event->type == KeyPress)
+             {
+               x_key_event = (XKeyEvent *)x_event;
+               keysym = XLookupKeysym (x_key_event, 0);
+               key_event.keyID = (CORBA_long)(keysym);
+               key_event.keycode = (CORBA_short) x_key_event->keycode;
+               key_event.type = Accessibility_KEY_PRESSED;
+               key_event.modifiers = (CORBA_unsigned_short)(x_key_event->state);
+#ifdef SPI_KEYEVENT_DEBUG
            fprintf (stderr,
                     "Key %lu pressed (%c), modifiers %d\n",
                     (unsigned long) keysym,
-                    (char) keysym,
+                    keysym ? (int) keysym : '*',
                     (int) x_key_event->state);
-#elif defined SPI_DEBUG
+#endif
+#ifdef SPI_DEBUG
            fprintf(stderr, "%s%c",
                    (x_key_event->state & Mod1Mask)?"Alt-":"",
                    ((x_key_event->state & ShiftMask)^(x_key_event->state & LockMask))?
                    (char) toupper((int) keysym) : (char) tolower((int)keysym));
 #endif /* SPI_DEBUG */
-       }
-       else
-       {
+             }
+           else
+           {
 #ifdef SPI_KEYEVENT_DEBUG
-               fprintf (stderr, "other event, type %d\n", (int) x_event->type);
-#endif
-       }
-       /* relay to listeners, and decide whether to consume it or not */
-       for (i=0; i<n_listeners && !is_consumed; ++i)
-       {
-         Accessibility_KeystrokeListener ls;
-         ls = (Accessibility_KeystrokeListener)
-                       g_list_nth_data (controller->key_listeners, i);
-         if (!CORBA_Object_is_nil(ls, &ev))
-         {
-           is_consumed = Accessibility_KeystrokeListener_keyEvent (ls, &key_event, &ev);
-         }             
-       }
-       if (is_consumed) XNextEvent (GDK_DISPLAY(), x_event);
-       XAllowEvents (GDK_DISPLAY(), ReplayKeyboard, CurrentTime);
-/*
- *  I haven't figure out how to make this work correctly yet :-(
- *
- *     XGrabKeyboard (GDK_DISPLAY(), GDK_ROOT_WINDOW(), True,
- *                    GrabModeAsync, GrabModeSync, CurrentTime);
- *      XAllowEvents (GDK_DISPLAY(), SyncKeyboard, CurrentTime);
- *
- *
- * ControlMask grabs are broken, must be in use already.
- *
- */
-       
-/* Always grab ShiftLock in DEBUG mode */
-#ifdef SPI_DEBUG
-       if (!controller->keymask_list)
-           controller->keymask_list =
-               g_list_append (controller->keymask_list, &shiftlock_mask);
+                   fprintf (stderr, "other event, type %d\n", (int) x_event->type);
 #endif
+           }
+           /* relay to listeners, and decide whether to consume it or not */
+           for (i=0; i<n_listeners && !is_consumed; ++i)
+           {
+                   Accessibility_KeystrokeListener ls;
+                   ls = (Accessibility_KeystrokeListener)
+                           g_list_nth_data (controller->key_listeners, i);
+                   if (!CORBA_Object_is_nil(ls, &ev))
+                   {
+                           is_consumed = Accessibility_KeystrokeListener_keyEvent (ls, &key_event, &ev);
+                   }           
+           }
+           if (is_consumed)
+           {
+             XAllowEvents (display, SyncKeyboard, CurrentTime);
+           }
+           else
+           {
+             XAllowEvents (display, ReplayKeyboard, CurrentTime);
+           }
+         }
+       XUngrabKey (display, AnyKey, AnyModifier, root_window);
        return _controller_grab_keyboard (controller);
 }
 
 static gboolean
 _controller_grab_keyboard (DeviceEventController *controller)
 {
-       Display *display = GDK_DISPLAY();
-       Window root_window = GDK_ROOT_WINDOW();
        GList *maskList = controller->keymask_list;
        int i;
-       int last_mask = g_list_length (maskList);
+       int last_mask;
+       last_mask = g_list_length (maskList);
 
 /*
  * masks known to work with default RH 7.1: 
@@ -326,9 +316,6 @@ _controller_grab_keyboard (DeviceEventController *controller)
 #endif
                if (!(maskVal & ControlMask))
                {
-#ifdef SPI_KEYEVENT_DEBUG
-                       fprintf (stderr, "grabbing for mod %lu\n", (unsigned long) maskVal);
-#endif
                        XGrabKey (display,
                                  AnyKey,
                                  maskVal,
@@ -364,7 +351,10 @@ device_event_controller_object_finalize (GObject *object)
 static void
 impl_register_keystroke_listener (PortableServer_Servant     servant,
                                  const Accessibility_KeystrokeListener l,
+                                 const Accessibility_KeySet *keys,
                                  const Accessibility_ControllerEventMask *mask,
+                                 const Accessibility_KeyEventTypeSeq *type,
+                                 const CORBA_boolean is_synchronous,
                                  CORBA_Environment         *ev)
 {
        DeviceEventController *controller = DEVICE_EVENT_CONTROLLER (
@@ -373,7 +363,32 @@ impl_register_keystroke_listener (PortableServer_Servant     servant,
        fprintf (stderr, "registering keystroke listener %p with maskVal %lu\n",
                 (void *) l, (unsigned long) mask->value);
 #endif
+        /* TODO: change this to an enum, indicating if event can be consumed */
+       if (is_synchronous)
        _controller_register_device_listener(controller, l, mask, DEVICE_TYPE_KBD, ev);
+       else
+       ; /* register with toolkit instead */   
+}
+/*
+ * CORBA Accessibility::DeviceEventController::deregisterKeystrokeListener
+ *     method implementation
+ */
+static void
+impl_deregister_keystroke_listener (PortableServer_Servant     servant,
+                                   const Accessibility_KeystrokeListener l,
+                                   const Accessibility_KeySet *keys,
+                                   const Accessibility_ControllerEventMask *mask,
+                                   const Accessibility_KeyEventTypeSeq *type,
+                                   const CORBA_boolean is_synchronous,
+                                   CORBA_Environment         *ev)
+{
+       DeviceEventController *controller = DEVICE_EVENT_CONTROLLER (
+               bonobo_object_from_servant (servant));
+#ifdef SPI_DEBUG
+       fprintf (stderr, "deregistering keystroke listener %p with maskVal %lu\n",
+                (void *) l, (unsigned long) mask->value);
+#endif
+       _controller_deregister_device_listener(controller, l, mask, DEVICE_TYPE_KBD, ev);
 }
 
 /*
@@ -407,6 +422,9 @@ impl_generate_key_event (PortableServer_Servant     servant,
 #ifdef SPI_DEBUG
        fprintf (stderr, "synthesizing keystroke %ld\n", (long) keyEventID);
 #endif
+       /* TODO: hide/wrap/remove X dependency */
+       XTestFakeKeyEvent (GDK_DISPLAY(), (unsigned int) keyEventID, True, CurrentTime);
+       XTestFakeKeyEvent (GDK_DISPLAY(), (unsigned int) keyEventID, False, CurrentTime);
 }
 
 /*
@@ -435,6 +453,7 @@ device_event_controller_class_init (DeviceEventControllerClass *klass)
         object_class->finalize = device_event_controller_object_finalize;
 
         epv->registerKeystrokeListener = impl_register_keystroke_listener;
+        epv->deregisterKeystrokeListener = impl_deregister_keystroke_listener;
 /*        epv->registerMouseListener = impl_register_mouse_listener; */
         epv->generateKeyEvent = impl_generate_key_event;
         epv->generateMouseEvent = impl_generate_mouse_event;
@@ -445,7 +464,7 @@ static void
 device_event_controller_init (DeviceEventController *device_event_controller)
 {
   device_event_controller->key_listeners = NULL;
-  device_event_controller->key_listeners = NULL;
+  device_event_controller->mouse_listeners = NULL;
   device_event_controller->keymask_list = NULL;
   kbd_registered = _controller_register_with_devices (device_event_controller);
 }
index 68736c9..d897260 100644 (file)
@@ -81,13 +81,15 @@ void   keystroke_listener_remove_callback (KeystrokeListener *listener,
 /*
  * CORBA Accessibility::KeystrokeListener::keyEvent method implementation
  */
-
 static CORBA_boolean
 impl_key_event (PortableServer_Servant     servant,
                const Accessibility_KeyStroke *key,
                CORBA_Environment         *ev)
 {
-#ifdef SPI_DEBUG
+  KeystrokeListener *listener = KEYSTROKE_LISTENER (bonobo_object_from_servant (servant));
+  GList *callbacks = listener->callbacks;
+  gboolean was_consumed = FALSE;
+#ifdef SPI_KEYEVENT_DEBUG
   if (ev->_major != CORBA_NO_EXCEPTION) {
     fprintf(stderr,
             ("Accessibility app error: exception during keystroke notification: %s\n"),
@@ -101,6 +103,13 @@ impl_key_event (PortableServer_Servant     servant,
            (char) toupper((int) key->keyID) : (char) tolower((int) key->keyID));
   }
 #endif
+  while (callbacks)
+  {
+         BooleanKeystrokeListenerCB cb = (BooleanKeystrokeListenerCB) callbacks->data;
+         was_consumed = (*cb) (key) || was_consumed;
+         callbacks = g_list_next (callbacks);
+  }
+  return was_consumed;
 }
 
 static void
index 14622fd..ce196c5 100644 (file)
@@ -140,13 +140,13 @@ compare_corba_objects (gconstpointer p1, gconstpointer p2)
 {
   CORBA_Environment ev;
   gint retval;
-  retval = !CORBA_Object_is_equivalent ((CORBA_Object) p1, (CORBA_Object) p2, &ev);
 
 #ifdef SPI_DEBUG
-  fprintf (stderr, "comparing %p to %p; result %d\n",
-          p1, p2,
-          retval);
+  fprintf (stderr, "comparing %p to %p\n",
+          p1, p2);
 #endif
+  
+  retval = !CORBA_Object_is_equivalent ((CORBA_Object) p1, (CORBA_Object) p2, &ev);
   return retval;  
 }
 
@@ -189,6 +189,13 @@ compare_listener_hash (gconstpointer p1, gconstpointer p2)
   return (((ListenerStruct *)p2)->event_type_hash - ((ListenerStruct *)p1)->event_type_hash);
 }
 
+static gint
+compare_listener_corbaref (gconstpointer p1, gconstpointer p2)
+{
+  return compare_corba_objects (((ListenerStruct *)p2)->listener,
+                                ((ListenerStruct *)p1)->listener);
+}
+
 static void
 parse_event_type (EventTypeStruct *etype, char *event_name)
 {
@@ -264,7 +271,7 @@ impl_accessibility_registry_deregister_application (PortableServer_Servant serva
                                                     CORBA_Environment * ev)
 {
   Registry *registry = REGISTRY (bonobo_object_from_servant (servant));
-  GList *list = g_list_find_custom (registry->desktop->applications, application, compare_corba_objects);
+  GList *list = g_list_find_custom (registry->desktop->applications, &application, compare_corba_objects);
 
 #ifdef SPI_DEBUG
   gint i;
@@ -344,7 +351,11 @@ impl_accessibility_registry_deregister_global_event_listener_all (
                                                     CORBA_Environment      *ev)
 {
   Registry *registry = REGISTRY (bonobo_object_from_servant (servant));
-  GList *list = g_list_find_custom (registry->object_listeners, listener, compare_corba_objects);
+  ListenerStruct *ls = g_malloc (sizeof (ListenerStruct));
+  GList *list;
+  ls->listener = listener;  
+  list = g_list_find_custom (registry->object_listeners, ls,
+                            compare_listener_corbaref);
 
   /*
    * TODO : de-register with toolkit if the last instance of a listener
@@ -355,14 +366,14 @@ impl_accessibility_registry_deregister_global_event_listener_all (
     {
       fprintf (stderr, "deregistering listener\n");
       registry->object_listeners = g_list_delete_link (registry->object_listeners, list);
-      list = g_list_find_custom (registry->object_listeners, listener, compare_corba_objects);
+      list = g_list_find_custom (registry->object_listeners, ls, compare_listener_corbaref);
     }
-  list = g_list_find_custom (registry->toolkit_listeners, listener, compare_corba_objects);
+  list = g_list_find_custom (registry->toolkit_listeners, ls, compare_listener_corbaref);
   while (list)
     {
       fprintf (stderr, "deregistering listener\n");
       registry->toolkit_listeners = g_list_delete_link (registry->toolkit_listeners, list);
-      list = g_list_find_custom (registry->toolkit_listeners, listener, compare_corba_objects);
+      list = g_list_find_custom (registry->toolkit_listeners, ls, compare_listener_corbaref);
     }
 }
 
index 2aa2246..07e1aa6 100644 (file)
@@ -8,7 +8,7 @@ INCLUDES = -I$(top_srcdir)          \
 
 registryd_SOURCES = registryd.c
 
-LDADD = ../libspi/libspi.la $(REGISTRYD_LIBS)
+LDADD = ../libspi/libspi.la -lXtst $(REGISTRYD_LIBS) 
 
 serverinfodir = $(libdir)/bonobo/servers
 serverinfo_DATA = Accessibility_Registry.server
index 8966fda..f96d7b0 100644 (file)
@@ -30,6 +30,7 @@
 #endif
 
 #include <X11/Xlib.h>
+#include <X11/extensions/XTest.h>
 #include <config.h>
 #include <gdk/gdkx.h> /* TODO: hide dependency (wrap in single porting file) */
 #include <gdk/gdkwindow.h>
@@ -53,6 +54,10 @@ static GObjectClass *device_event_controller_parent_class;
 
 static gboolean kbd_registered = FALSE;
 
+static Display *display;
+
+static Window root_window;
+
 typedef enum {
   DEVICE_TYPE_KBD,
   DEVICE_TYPE_MOUSE,
@@ -90,11 +95,13 @@ _compare_corba_objects (gconstpointer p1, gconstpointer p2)
 static gint
 _eventmask_compare_value (gconstpointer p1, gconstpointer p2)
 {
+    long d;
     if (!p1 || !p2)
        return (gint) (p1?1:(p2?-1:0));
     else
-       return ((long)((Accessibility_ControllerEventMask*)p2)->value) -
+       d = ((long)((Accessibility_ControllerEventMask*)p2)->value) -
                ((long)((Accessibility_ControllerEventMask*)p1)->value);
+    return (gint) d;
 }
 
 static void
@@ -104,7 +111,7 @@ _controller_register_device_listener (DeviceEventController *controller,
                                      DeviceTypeCategory type,
                                      CORBA_Environment *ev)
 {
-  Accessibility_ControllerEventMask *mask_ptr;
+  Accessibility_ControllerEventMask *mask_ptr = NULL;
   
   switch (type) {
   case DEVICE_TYPE_KBD:
@@ -156,17 +163,21 @@ _controller_deregister_device_listener (DeviceEventController *controller,
       list_ptr = g_list_find_custom (controller->key_listeners, l, _compare_corba_objects);
       if (list_ptr)
          controller->key_listeners = g_list_remove (controller->key_listeners, list_ptr);
-      
-      mask_ptr = (Accessibility_ControllerEventMask *)
+      list_ptr = (GList *)
                  g_list_find_custom (controller->keymask_list, (gpointer) mask,
                                     _eventmask_compare_value);
-      if (mask_ptr)
+      if (list_ptr)
+        {
+         mask_ptr = (Accessibility_ControllerEventMask *) list_ptr->data;
+          if (mask_ptr)
              --mask_ptr->refcount;
-      if (!mask_ptr->refcount)
-      {
-          controller->keymask_list = g_list_remove (controller->keymask_list, mask_ptr);
-          ;  /* TODO: release any key grabs that are in place for this key mask */
-      }
+          if (!mask_ptr->refcount)
+            {
+             controller->keymask_list =
+                     g_list_remove (controller->keymask_list, mask_ptr);
+             ;  /* TODO: release any key grabs that are in place for this key mask */
+           }
+       }
       break;
   case DEVICE_TYPE_MOUSE:
 /*    controller->mouse_listeners = g_list_append (controller->mouse_listeners,
@@ -181,35 +192,28 @@ static gboolean
 _controller_register_with_devices (DeviceEventController *controller)
 {
   gboolean retval = FALSE;
-  Display *default_display;
-  Window root_window;
 
-  default_display = GDK_DISPLAY();
-  root_window = GDK_ROOT_WINDOW();  
   /* calls to device-specific implementations and routines go here */
   /* register with: keyboard hardware code handler */
   /* register with: (translated) keystroke handler */
 #ifdef SPI_DEBUG
-  fprintf (stderr, "About to request events on window %ld of display %p\n",
-          (unsigned long) root_window, default_display);
+  fprintf (stderr, "About to request events on window %ld of display %x\n",
+          (unsigned long) GDK_ROOT_WINDOW(), GDK_DISPLAY());
 #endif
-  XSelectInput (default_display,
-               root_window,
-               KeyPressMask);
-  XSelectInput (default_display,
+  /* We must open a new connection to the server to avoid clashing with the GDK event loop */
+  display = XOpenDisplay (getenv ("DISPLAY"));
+  root_window = DefaultRootWindow (display);           
+  XSelectInput (display,
                root_window,
-               KeyReleaseMask);
+               KeyPressMask | KeyReleaseMask);
   /* register with: mouse hardware device handler? */
   /* register with: mouse event handler */
   return retval;
 }
 
-static gboolean _check_key_event (DeviceEventController *controller)
+static gboolean
+_check_key_event (DeviceEventController *controller)
 {
-#ifdef SPI_DEBUG
-       static Accessibility_ControllerEventMask shiftlock_mask =
-               {(CORBA_unsigned_long) LockMask, (CORBA_unsigned_short) 1};
-#endif
        static gboolean initialized = FALSE;
        static gboolean is_active = FALSE;
        XEvent *x_event = g_new0 (XEvent, 1);
@@ -221,89 +225,75 @@ static gboolean _check_key_event (DeviceEventController *controller)
        int n_listeners = g_list_length (controller->key_listeners);
        Accessibility_KeyStroke key_event;
        static CORBA_Environment ev;
-       
+
        if (!initialized)
        {
-               initialized = TRUE;
-               CORBA_exception_init (&ev);
+         initialized = TRUE;
+         CORBA_exception_init (&ev);
        }
 
-/*        if (!XPending(GDK_DISPLAY())) return TRUE; */
-
-       /*
-        * the call to XPending seemed like a good idea, why did it
-        * wreak such havoc?
-        */
-
-       XPeekEvent (GDK_DISPLAY(), x_event);
-       if (x_event->type == KeyPress)
-       {
-           x_key_event = (XKeyEvent *)x_event;
-           keysym = XLookupKeysym (x_key_event, 0);
-           key_event.keyID = (CORBA_long)(keysym);
-           key_event.type = Accessibility_KEY_PRESSED;
-           key_event.modifiers = (CORBA_unsigned_short)(x_key_event->state);
-#if defined SPI_KEYEVENT_DEBUG
+       while (XPending(display))
+         {
+           XNextEvent (display, x_event);
+           if (x_event->type == KeyPress)
+             {
+               x_key_event = (XKeyEvent *)x_event;
+               keysym = XLookupKeysym (x_key_event, 0);
+               key_event.keyID = (CORBA_long)(keysym);
+               key_event.keycode = (CORBA_short) x_key_event->keycode;
+               key_event.type = Accessibility_KEY_PRESSED;
+               key_event.modifiers = (CORBA_unsigned_short)(x_key_event->state);
+#ifdef SPI_KEYEVENT_DEBUG
            fprintf (stderr,
                     "Key %lu pressed (%c), modifiers %d\n",
                     (unsigned long) keysym,
-                    (char) keysym,
+                    keysym ? (int) keysym : '*',
                     (int) x_key_event->state);
-#elif defined SPI_DEBUG
+#endif
+#ifdef SPI_DEBUG
            fprintf(stderr, "%s%c",
                    (x_key_event->state & Mod1Mask)?"Alt-":"",
                    ((x_key_event->state & ShiftMask)^(x_key_event->state & LockMask))?
                    (char) toupper((int) keysym) : (char) tolower((int)keysym));
 #endif /* SPI_DEBUG */
-       }
-       else
-       {
+             }
+           else
+           {
 #ifdef SPI_KEYEVENT_DEBUG
-               fprintf (stderr, "other event, type %d\n", (int) x_event->type);
-#endif
-       }
-       /* relay to listeners, and decide whether to consume it or not */
-       for (i=0; i<n_listeners && !is_consumed; ++i)
-       {
-         Accessibility_KeystrokeListener ls;
-         ls = (Accessibility_KeystrokeListener)
-                       g_list_nth_data (controller->key_listeners, i);
-         if (!CORBA_Object_is_nil(ls, &ev))
-         {
-           is_consumed = Accessibility_KeystrokeListener_keyEvent (ls, &key_event, &ev);
-         }             
-       }
-       if (is_consumed) XNextEvent (GDK_DISPLAY(), x_event);
-       XAllowEvents (GDK_DISPLAY(), ReplayKeyboard, CurrentTime);
-/*
- *  I haven't figure out how to make this work correctly yet :-(
- *
- *     XGrabKeyboard (GDK_DISPLAY(), GDK_ROOT_WINDOW(), True,
- *                    GrabModeAsync, GrabModeSync, CurrentTime);
- *      XAllowEvents (GDK_DISPLAY(), SyncKeyboard, CurrentTime);
- *
- *
- * ControlMask grabs are broken, must be in use already.
- *
- */
-       
-/* Always grab ShiftLock in DEBUG mode */
-#ifdef SPI_DEBUG
-       if (!controller->keymask_list)
-           controller->keymask_list =
-               g_list_append (controller->keymask_list, &shiftlock_mask);
+                   fprintf (stderr, "other event, type %d\n", (int) x_event->type);
 #endif
+           }
+           /* relay to listeners, and decide whether to consume it or not */
+           for (i=0; i<n_listeners && !is_consumed; ++i)
+           {
+                   Accessibility_KeystrokeListener ls;
+                   ls = (Accessibility_KeystrokeListener)
+                           g_list_nth_data (controller->key_listeners, i);
+                   if (!CORBA_Object_is_nil(ls, &ev))
+                   {
+                           is_consumed = Accessibility_KeystrokeListener_keyEvent (ls, &key_event, &ev);
+                   }           
+           }
+           if (is_consumed)
+           {
+             XAllowEvents (display, SyncKeyboard, CurrentTime);
+           }
+           else
+           {
+             XAllowEvents (display, ReplayKeyboard, CurrentTime);
+           }
+         }
+       XUngrabKey (display, AnyKey, AnyModifier, root_window);
        return _controller_grab_keyboard (controller);
 }
 
 static gboolean
 _controller_grab_keyboard (DeviceEventController *controller)
 {
-       Display *display = GDK_DISPLAY();
-       Window root_window = GDK_ROOT_WINDOW();
        GList *maskList = controller->keymask_list;
        int i;
-       int last_mask = g_list_length (maskList);
+       int last_mask;
+       last_mask = g_list_length (maskList);
 
 /*
  * masks known to work with default RH 7.1: 
@@ -326,9 +316,6 @@ _controller_grab_keyboard (DeviceEventController *controller)
 #endif
                if (!(maskVal & ControlMask))
                {
-#ifdef SPI_KEYEVENT_DEBUG
-                       fprintf (stderr, "grabbing for mod %lu\n", (unsigned long) maskVal);
-#endif
                        XGrabKey (display,
                                  AnyKey,
                                  maskVal,
@@ -364,7 +351,10 @@ device_event_controller_object_finalize (GObject *object)
 static void
 impl_register_keystroke_listener (PortableServer_Servant     servant,
                                  const Accessibility_KeystrokeListener l,
+                                 const Accessibility_KeySet *keys,
                                  const Accessibility_ControllerEventMask *mask,
+                                 const Accessibility_KeyEventTypeSeq *type,
+                                 const CORBA_boolean is_synchronous,
                                  CORBA_Environment         *ev)
 {
        DeviceEventController *controller = DEVICE_EVENT_CONTROLLER (
@@ -373,7 +363,32 @@ impl_register_keystroke_listener (PortableServer_Servant     servant,
        fprintf (stderr, "registering keystroke listener %p with maskVal %lu\n",
                 (void *) l, (unsigned long) mask->value);
 #endif
+        /* TODO: change this to an enum, indicating if event can be consumed */
+       if (is_synchronous)
        _controller_register_device_listener(controller, l, mask, DEVICE_TYPE_KBD, ev);
+       else
+       ; /* register with toolkit instead */   
+}
+/*
+ * CORBA Accessibility::DeviceEventController::deregisterKeystrokeListener
+ *     method implementation
+ */
+static void
+impl_deregister_keystroke_listener (PortableServer_Servant     servant,
+                                   const Accessibility_KeystrokeListener l,
+                                   const Accessibility_KeySet *keys,
+                                   const Accessibility_ControllerEventMask *mask,
+                                   const Accessibility_KeyEventTypeSeq *type,
+                                   const CORBA_boolean is_synchronous,
+                                   CORBA_Environment         *ev)
+{
+       DeviceEventController *controller = DEVICE_EVENT_CONTROLLER (
+               bonobo_object_from_servant (servant));
+#ifdef SPI_DEBUG
+       fprintf (stderr, "deregistering keystroke listener %p with maskVal %lu\n",
+                (void *) l, (unsigned long) mask->value);
+#endif
+       _controller_deregister_device_listener(controller, l, mask, DEVICE_TYPE_KBD, ev);
 }
 
 /*
@@ -407,6 +422,9 @@ impl_generate_key_event (PortableServer_Servant     servant,
 #ifdef SPI_DEBUG
        fprintf (stderr, "synthesizing keystroke %ld\n", (long) keyEventID);
 #endif
+       /* TODO: hide/wrap/remove X dependency */
+       XTestFakeKeyEvent (GDK_DISPLAY(), (unsigned int) keyEventID, True, CurrentTime);
+       XTestFakeKeyEvent (GDK_DISPLAY(), (unsigned int) keyEventID, False, CurrentTime);
 }
 
 /*
@@ -435,6 +453,7 @@ device_event_controller_class_init (DeviceEventControllerClass *klass)
         object_class->finalize = device_event_controller_object_finalize;
 
         epv->registerKeystrokeListener = impl_register_keystroke_listener;
+        epv->deregisterKeystrokeListener = impl_deregister_keystroke_listener;
 /*        epv->registerMouseListener = impl_register_mouse_listener; */
         epv->generateKeyEvent = impl_generate_key_event;
         epv->generateMouseEvent = impl_generate_mouse_event;
@@ -445,7 +464,7 @@ static void
 device_event_controller_init (DeviceEventController *device_event_controller)
 {
   device_event_controller->key_listeners = NULL;
-  device_event_controller->key_listeners = NULL;
+  device_event_controller->mouse_listeners = NULL;
   device_event_controller->keymask_list = NULL;
   kbd_registered = _controller_register_with_devices (device_event_controller);
 }
index 880c006..ba2c770 100644 (file)
@@ -54,7 +54,7 @@ main (int argc,
 #endif
   
         gdk_init(&argc, &argv);
-       g_idle_add (registry->kbd_event_hook, registry);
+        g_timeout_add_full (G_PRIORITY_HIGH_IDLE, 200, registry->kbd_event_hook, registry, NULL);
 /*     keyevent_source =
                g_source_new (registry->kbd_event_hook, sizeof (GSourceFunc));
                g_source_attach (keyevent_source, g_main_context_default());*/
index 14622fd..ce196c5 100644 (file)
@@ -140,13 +140,13 @@ compare_corba_objects (gconstpointer p1, gconstpointer p2)
 {
   CORBA_Environment ev;
   gint retval;
-  retval = !CORBA_Object_is_equivalent ((CORBA_Object) p1, (CORBA_Object) p2, &ev);
 
 #ifdef SPI_DEBUG
-  fprintf (stderr, "comparing %p to %p; result %d\n",
-          p1, p2,
-          retval);
+  fprintf (stderr, "comparing %p to %p\n",
+          p1, p2);
 #endif
+  
+  retval = !CORBA_Object_is_equivalent ((CORBA_Object) p1, (CORBA_Object) p2, &ev);
   return retval;  
 }
 
@@ -189,6 +189,13 @@ compare_listener_hash (gconstpointer p1, gconstpointer p2)
   return (((ListenerStruct *)p2)->event_type_hash - ((ListenerStruct *)p1)->event_type_hash);
 }
 
+static gint
+compare_listener_corbaref (gconstpointer p1, gconstpointer p2)
+{
+  return compare_corba_objects (((ListenerStruct *)p2)->listener,
+                                ((ListenerStruct *)p1)->listener);
+}
+
 static void
 parse_event_type (EventTypeStruct *etype, char *event_name)
 {
@@ -264,7 +271,7 @@ impl_accessibility_registry_deregister_application (PortableServer_Servant serva
                                                     CORBA_Environment * ev)
 {
   Registry *registry = REGISTRY (bonobo_object_from_servant (servant));
-  GList *list = g_list_find_custom (registry->desktop->applications, application, compare_corba_objects);
+  GList *list = g_list_find_custom (registry->desktop->applications, &application, compare_corba_objects);
 
 #ifdef SPI_DEBUG
   gint i;
@@ -344,7 +351,11 @@ impl_accessibility_registry_deregister_global_event_listener_all (
                                                     CORBA_Environment      *ev)
 {
   Registry *registry = REGISTRY (bonobo_object_from_servant (servant));
-  GList *list = g_list_find_custom (registry->object_listeners, listener, compare_corba_objects);
+  ListenerStruct *ls = g_malloc (sizeof (ListenerStruct));
+  GList *list;
+  ls->listener = listener;  
+  list = g_list_find_custom (registry->object_listeners, ls,
+                            compare_listener_corbaref);
 
   /*
    * TODO : de-register with toolkit if the last instance of a listener
@@ -355,14 +366,14 @@ impl_accessibility_registry_deregister_global_event_listener_all (
     {
       fprintf (stderr, "deregistering listener\n");
       registry->object_listeners = g_list_delete_link (registry->object_listeners, list);
-      list = g_list_find_custom (registry->object_listeners, listener, compare_corba_objects);
+      list = g_list_find_custom (registry->object_listeners, ls, compare_listener_corbaref);
     }
-  list = g_list_find_custom (registry->toolkit_listeners, listener, compare_corba_objects);
+  list = g_list_find_custom (registry->toolkit_listeners, ls, compare_listener_corbaref);
   while (list)
     {
       fprintf (stderr, "deregistering listener\n");
       registry->toolkit_listeners = g_list_delete_link (registry->toolkit_listeners, list);
-      list = g_list_find_custom (registry->toolkit_listeners, listener, compare_corba_objects);
+      list = g_list_find_custom (registry->toolkit_listeners, ls, compare_listener_corbaref);
     }
 }
 
index 880c006..ba2c770 100644 (file)
@@ -54,7 +54,7 @@ main (int argc,
 #endif
   
         gdk_init(&argc, &argv);
-       g_idle_add (registry->kbd_event_hook, registry);
+        g_timeout_add_full (G_PRIORITY_HIGH_IDLE, 200, registry->kbd_event_hook, registry, NULL);
 /*     keyevent_source =
                g_source_new (registry->kbd_event_hook, sizeof (GSourceFunc));
                g_source_attach (keyevent_source, g_main_context_default());*/
index 749bcf1..16c16f1 100644 (file)
@@ -39,6 +39,11 @@ static boolean use_magnifier = FALSE;
 static boolean use_festival = FALSE;
 static boolean festival_chatty = FALSE;
 
+static AccessibleEventListener *focus_listener;
+static AccessibleEventListener *property_listener;
+static AccessibleEventListener *button_listener;
+static KeystrokeListener *key_listener;
+
 int
 main(int argc, char **argv)
 {
@@ -47,10 +52,6 @@ main(int argc, char **argv)
   int n_apps;
   Accessible *desktop;
   Accessible *application;
-  AccessibleEventListener *focus_listener;
-  AccessibleEventListener *property_listener;
-  AccessibleEventListener *button_listener;
-  KeystrokeListener *key_listener;
 
   if ((argc > 1) && (!strncmp(argv[1],"-h",2)))
   {
@@ -83,12 +84,17 @@ main(int argc, char **argv)
     }
 
   /* prepare the keyboard snoopers */
-  /* key_listener = createKeystrokeListener(report_key_event);
-     registerKeystrokeListener(key_listener, KEYMASK_SHIFT); */
+  key_listener = createKeystrokeListener(report_key_event);
+  /* will listen only to Alt-key combinations */
+  registerKeystrokeListener(key_listener,
+                           (KeySet *) ALL_KEYS,
+                           KEYMASK_ALT,
+                           (unsigned long) ( KeyPress | KeyRelease),
+                           KEYLISTENER_CANCONSUME);
 
   get_environment_vars();
 
-  SPI_event_main(FALSE);
+  SPI_event_main(TRUE);
 }
 
 static void
@@ -131,7 +137,7 @@ report_focussed_accessible (Accessible *obj, boolean shutup_previous_speech)
       fprintf (stderr, "Bounding box: (%ld, %ld) ; (%ld, %ld)\n",
                x, y, x+width, y+height);
       if (use_magnifier) {
-             magnifier_set_roi (x, y, width, height);        
+             magnifier_set_roi ((short) 0, x, y, width, height);
       }
     }
   /* if this is a text object, speak the first sentence. */
@@ -190,12 +196,49 @@ check_property_change (void *p)
   }
 }
 
+static void
+simple_at_exit()
+{
+  deregisterGlobalEventListenerAll (focus_listener);
+  deregisterGlobalEventListenerAll (property_listener);
+  deregisterGlobalEventListenerAll (button_listener);
+  deregisterKeystrokeListener (key_listener, KEYMASK_ALT );
+  
+  SPI_exit ();
+}
+
+static boolean
+is_command_key (KeyStroke *key)
+{
+  switch (key->keyID)
+    {
+    case 'Q':
+    case 'q':
+           simple_at_exit(); 
+           return TRUE; /* not reached */
+    case 'M':
+    case 'm':
+           use_magnifier = ! use_magnifier;
+           return TRUE;
+    case 'F':
+    case 'f':
+           use_festival = ! use_festival;
+           return TRUE;
+    default:
+           return FALSE;
+    }
+}
+
 static boolean
 report_key_event (void *p)
 {
   KeyStroke *key = (KeyStroke *) p;
-  fprintf (stderr, ".");
-  return FALSE;
+  fprintf(stderr, "KeyEvent %s%c (keycode %d)\n",
+         (key->modifiers & KEYMASK_ALT)?"Alt-":"",
+         ((key->modifiers & KEYMASK_SHIFT)^(key->modifiers & KEYMASK_SHIFTLOCK))?
+         (char) toupper((int) key->keyID) : (char) tolower((int) key->keyID),
+         (int) key->keycode);
+  return is_command_key (key);
 }
 
 static int _festival_init ()
index d585c61..76a49ce 100644 (file)
@@ -30,9 +30,12 @@ module Accessibility {
   interface Magnifier : Bonobo::Unknown {
 
     /**
-     * #attribute MagFactor: a float indicating the current x and y magnification ratio.
+     * void setMagFactor: sets the current x and y magnification ratio.
+     * @zoom_region: the index of the affected zoom region.
+     * @magX: the magnification factor in the x direction for the specified region. 
+     * @magY: the magnification factor in the x direction for the specified region. 
      **/
-    attribute float MagFactor;
+    oneway void setMagFactor (in short zoom_region, in float magX, in float magY);
 
     /**
      * #attribute SourceDisplay: a @string containing the X display name
@@ -49,15 +52,97 @@ module Accessibility {
     /**
      * oneway void setROI:
      * Sets the region of interest for the magnifier.
+     * @zoom_region: the index of the affected zoom region.
      * @x1: the minimum X coordinate of the ROI bounding box
      * @x2: the maximum X coordinate of the ROI bounding box
      * @y1: the minimum Y coordinate of the ROI bounding box
      * @y2: the maximum Y coordinate of the ROI bounding box
      **/
-    oneway void setROI (in long x1, in long y1, in long x2, in long y2);
+    oneway void setROI (in short zoom_region, 
+                       in long x1, in long y1, in long x2, in long y2);
+
+    /**
+     * oneway void setROI:
+     * Sets the region of interest for the zoom region.
+     * If the zoom region was previously 'unmanaged', this associates
+     * it with the ROI.
+     * @zoom_region: the index of the affected zoom region.
+     * @x1: the minimum X coordinate of the ROI bounding box
+     * @x2: the maximum X coordinate of the ROI bounding box
+     * @y1: the minimum Y coordinate of the ROI bounding box
+     * @y2: the maximum Y coordinate of the ROI bounding box
+     **/
+    oneway void markDirty (in short zoom_region,
+                          in long x1, in long y1, in long x2, in long y2); 
+
+    /**
+     * oneway void markUnmanaged:
+     * Mark a zoom region as 'unmanaged', meaning that it should not
+     * attempt to get pixels from the source display but will have its
+     * pixels drawn by a client.
+     * @zoom_region: the index of the affected zoom region.
+     **/
+    oneway void markUnmanaged (in short zoom_region);
+
+    /**
+     * short createZoomRegion:
+     * Creates a new zoom region for the magnifier.
+     * The new region is initially unmanaged'.
+     * @zx: the scale factor in the x direction for the new zoom region
+     * @zy: the scale factor in the y direction for the new zoom region
+     * @x1: the minimum X coordinate of the zoomed area bounding box
+     * @x2: the maximum X coordinate of the zoomed area bounding box
+     * @y1: the minimum Y coordinate of the zoomed area bounding box
+     * @y2: the maximum Y coordinate of the zoomed area bounding box
+     **/
+    short createZoomRegion (in float zx, in float zy,
+                           in long x1, in long y1, 
+                           in long x2, in long y2); 
+
+    /**
+     * boolean getZoomRegionParams:
+     * Queries a specific zoom region for its parameters.
+     * returns: FALSE if the specified zoom region does not exist.
+     * @zoom_region: the index specifying which zoom region to query.
+     * @zx: the scale factor in the x direction for the new zoom region
+     * @zy: the scale factor in the y direction for the new zoom region
+     * @x1: the minimum X coordinate of the zoomed area bounding box
+     * @x2: the maximum X coordinate of the zoomed area bounding box
+     * @y1: the minimum Y coordinate of the zoomed area bounding box
+     * @y2: the maximum Y coordinate of the zoomed area bounding box
+     **/
+    boolean getZoomRegionParams (in short zoom_region,
+                                out float zx, out float zy,
+                                out long x1,  out long y1,
+                                out long x2,  out long y2); 
+
+    /**
+     * void resizeZoomRegion:
+     * Resizes the specified zoom region on the target display.
+     * @zoom_region: the index of the affected zoom region.
+     * @x1: the minimum X coordinate of the zoomed area bounding box
+     * @x2: the maximum X coordinate of the zoomed area bounding box
+     * @y1: the minimum Y coordinate of the zoomed area bounding box
+     * @y2: the maximum Y coordinate of the zoomed area bounding box
+     **/
+    oneway void resizeZoomRegion (in short zoom_region,
+                                 in long x1, in long y1, 
+                                 in long x2, in long y2);
+
+    /** 
+     * void destroyZoomRegion:
+     * Remove the specified zoom region from the magnifier.
+     **/
+    oneway void destroyZoomRegion (in short zoom_region);
+
+    /** 
+     * void clearAllZoomRegions: 
+     * Clears and destroys all currently defined zoom regions.
+     **/
+    void clearAllZoomRegions ();
 
     /** 
-     * void exit:
+     * void exit: 
      * Unmap the current magnifier from the display.
      **/
     void exit ();
index 7849991..f707a80 100644 (file)
@@ -42,28 +42,30 @@ get_magnifier()
 }
 
 void
-magnifier_set_roi(int x, int y, int w, int h)
+magnifier_set_roi(int zoom_region, int x, int y, int w, int h)
 {
   Accessibility_Magnifier magnifier = get_magnifier();
 
   if (magnifier)
        Accessibility_Magnifier_setROI (magnifier,
-                                     (const CORBA_long) x,
-                                     (const CORBA_long) y,
-                                     (const CORBA_long) x+w,
-                                     (const CORBA_long) y+h,
-                                     &ev);
+                                      (const CORBA_short) zoom_region,
+                                      (const CORBA_long) x,
+                                      (const CORBA_long) y,
+                                      (const CORBA_long) x+w,
+                                      (const CORBA_long) y+h,
+                                      &ev);
 }
 
 void
-magnifier_set_magnification (float mag_factor)
+magnifier_set_magnification (int zoom_region, float mag_factor_x, float mag_factor_y)
 {
   Accessibility_Magnifier magnifier = get_magnifier();
 
   if (magnifier)
-       Accessibility_Magnifier__set_MagFactor (magnifier,
-                                              (const CORBA_short)
-                                                  ((short) mag_factor),
-                                              &ev);
+       Accessibility_Magnifier_setMagFactor (magnifier,
+                                            (const CORBA_short) zoom_region,
+                                            ((CORBA_float) mag_factor_x),
+                                            ((CORBA_float) mag_factor_y),
+                                            &ev);
 }
 
index 1287bdb..8bf6c5d 100644 (file)
@@ -26,8 +26,8 @@ extern "C" {
 #endif /* __cplusplus */
 
 Accessibility_Magnifier get_magnifier(void);
-void magnifier_set_roi (int x1, int y1, int x2, int y2);
-void magnifier_set_magnification (float mag_factor);
+void magnifier_set_roi (int zoom_region, int x1, int y1, int x2, int y2);
+void magnifier_set_magnification (int zoom_region, float mag_factor_x, float mag_factor_y);
 
 #ifdef __cplusplus
 }
index 5fde4fd..39c63ce 100644 (file)
@@ -21,7 +21,8 @@ int main(int argc, char ** argv){
 
   else {
          printf ("setting mag factor to %f\n", (float) atof (argv[1]));
-         magnifier_set_magnification ((float) atof (argv[1]));
+         magnifier_set_magnification (0, (float) atof (argv[1]),
+                                      (float) atof (argv[1]));
   }
   sleep (4);
   return 0;
@@ -64,12 +65,13 @@ get_magnifier()
 }
 
 void
-magnifier_set_roi(int x, int y, int w, int h)
+magnifier_set_roi(int zoom_region, int x, int y, int w, int h)
 {
   Accessibility_Magnifier magnifier = get_magnifier();
 
   if (magnifier)
        Accessibility_Magnifier_setROI (magnifier,
+                                     (const CORBA_short) zoom_region,
                                      (const CORBA_long) x,
                                      (const CORBA_long) y,
                                      (const CORBA_long) x+w,
@@ -78,14 +80,15 @@ magnifier_set_roi(int x, int y, int w, int h)
 }
 
 void
-magnifier_set_magnification (float mag_factor)
+magnifier_set_magnification (int zoom_region, float mag_factor_x, float mag_factor_y)
 {
   Accessibility_Magnifier magnifier = get_magnifier();
 
   if (magnifier)
-       Accessibility_Magnifier__set_MagFactor (magnifier,
-                                              (const CORBA_short)
-                                                  ((short) mag_factor),
-                                              &ev);
+       Accessibility_Magnifier_setMagFactor (magnifier,
+                                            (const CORBA_short) zoom_region,
+                                            (const CORBA_float) mag_factor_x,
+                                            (const CORBA_float) mag_factor_y,
+                                            &ev);
 }
 
index a8619ab..18ba82e 100644 (file)
@@ -32,9 +32,11 @@ void parse_message(char *msg, MagnifierData *data){
   type = atoi((char*)&msg[1]);
   switch (type){
        case FACTOR :
-           old_factor = data->factor;
-           data->factor = get_num(msg);
-           printf("FACTOR = %d\n",data->factor);
+           old_factor_x = data->factor_x;
+           data->factor_x = get_num(msg);
+           old_factor_y = data->factor_y;
+           data->factor_y = get_num(msg);
+           printf("FACTOR = %d\n",data->factor_x);
            break;
        case CONTRAST :
            data->contrast = get_num(msg);
@@ -109,8 +111,8 @@ int display_image(gpointer data)
                   DisplayHeight(mag_data->target_display,screen_num),
                   0,
                   0,
-                  mag_data->factor,
-                  mag_data->factor,
+                  mag_data->factor_x,
+                  mag_data->factor_y,
                   GDK_INTERP_NEAREST);
   
   gdk_pixbuf_render_to_drawable (scaled_image,
@@ -139,17 +141,17 @@ void update_image(MagnifierData *mag_data)
   total_width = DisplayWidth (mag_data->source_display,screen_num);
   total_height = DisplayHeight(mag_data->source_display,screen_num);
 
-  x = mag_data->center.x - mag_data->mag_width/mag_data->factor/2;
-  y = mag_data->center.y - mag_data->mag_height/mag_data->factor/2;
+  x = mag_data->center.x - mag_data->mag_width/mag_data->factor_x/2;
+  y = mag_data->center.y - mag_data->mag_height/mag_data->factor_y/2;
 
-  if(mag_data->center.x < mag_data->mag_width/mag_data->factor/2)
+  if(mag_data->center.x < mag_data->mag_width/mag_data->factor_x/2)
     x = 0;
-  if(mag_data->center.x > (total_width - mag_data->mag_width/mag_data->factor/2))
-    x = total_width - mag_data->mag_width/mag_data->factor;
-  if(mag_data->center.y < mag_data->mag_height/mag_data->factor/2)
+  if(mag_data->center.x > (total_width - mag_data->mag_width/mag_data->factor_x/2))
+    x = total_width - mag_data->mag_width/mag_data->factor_x;
+  if(mag_data->center.y < mag_data->mag_height/mag_data->factor_y/2)
     y = 0;
-  if(mag_data->center.y > (total_height - mag_data->mag_height/mag_data->factor/2))
-    y = total_height - mag_data->mag_height/mag_data->factor;
+  if(mag_data->center.y > (total_height - mag_data->mag_height/mag_data->factor_y/2))
+    y = total_height - mag_data->mag_height/mag_data->factor_y;
   if(x < 0)
     x = 0;
   if(y < 0)
@@ -163,13 +165,14 @@ void update_image(MagnifierData *mag_data)
                                        total_height,
                                        total_width);
 */
-  if(mag_data->factor != old_factor){
+  if(mag_data->factor_x != old_factor_x || mag_data->factor_y != old_factor_y){
     g_object_unref((GObject *)image);
     image = gdk_pixbuf_new (GDK_COLORSPACE_RGB,FALSE, 8,
-                               DisplayWidth (mag_data->target_display,screen_num)/mag_data->factor,
-                               DisplayHeight(mag_data->target_display,screen_num)/mag_data->factor);
+                               DisplayWidth (mag_data->target_display,screen_num)/mag_data->factor_x,
+                               DisplayHeight(mag_data->target_display,screen_num)/mag_data->factor_y);
     /* yes, use target display above, since the size of the area grabbed depends on the target */
-    old_factor = mag_data->factor;
+    old_factor_x = mag_data->factor_x;
+    old_factor_y = mag_data->factor_y;
   }
   get_root_image(image_root_window,
                 image,
@@ -1123,12 +1126,14 @@ static cfunc convert_map[] = {
 };
 
 static void
-rgbconvert (XImage *image, guchar *pixels, int rowstride, int alpha, xlib_colormap *cmap)
+rgbconvert (XImage *image, guchar *pixels, int rowstride, int alpha, xlib_colormap *cmap,
+           MagnifierData *mag_data)
 {
-       int index = (image->byte_order == MSBFirst) | (alpha != 0) << 1;
-       int bank=5;             /* default fallback converter */
-       Visual *v = cmap->visual;
-
+  int index = (image->byte_order == MSBFirst) | (alpha != 0) << 1;
+  int bank=5;          /* default fallback converter */
+  Visual *v = cmap->visual;
+  if (mag_data->fast_rgb_convert)
+    {    
        switch (v->class) {
                                /* I assume this is right for static & greyscale's too? */
        case StaticGray:
@@ -1168,6 +1173,7 @@ rgbconvert (XImage *image, guchar *pixels, int rowstride, int alpha, xlib_colorm
                /* always use the slow version */
                break;
        }
+    }
 
        if (bank==5) {
                convert_real_slow(image, pixels, rowstride, cmap, alpha);
@@ -1177,12 +1183,10 @@ rgbconvert (XImage *image, guchar *pixels, int rowstride, int alpha, xlib_colorm
        }
 }
 
-    
-
-void get_root_image(Window src,GdkPixbuf *dest, int src_x, int src_y, MagnifierData *mag_data)  {
+void get_root_image(Window src, GdkPixbuf *dest, int src_x, int src_y, MagnifierData *mag_data)  {
        XImage *image;
-       int width = mag_data->mag_width/mag_data->factor;
-       int height = mag_data->mag_height/mag_data->factor;
+       int width = mag_data->mag_width/mag_data->factor_x;
+       int height = mag_data->mag_height/mag_data->factor_y;
 
        /* Get Image in ZPixmap format (packed bits). */
        image = XGetImage (mag_data->source_display, src, src_x, src_y,
@@ -1198,7 +1202,12 @@ void get_root_image(Window src,GdkPixbuf *dest, int src_x, int src_y, MagnifierD
        rgbconvert (image, gdk_pixbuf_get_pixels(dest),
                    gdk_pixbuf_get_rowstride(dest),
                    gdk_pixbuf_get_has_alpha(dest),
-                   x_cmap);
+                   x_cmap,
+                   mag_data);
+
+       /* would like to use GDK routine, but since we don't have multi-head
+          yet, we have to use X */
+
        XDestroyImage (image);
 }
 
index a816a8b..624aab0 100644 (file)
@@ -35,16 +35,19 @@ GdkPixbuf*  image;
 GdkPixbuf*  scaled_image;
 Window     image_root_window;
 int        screen_num;
-int         old_factor;
+int         old_factor_x;
+int         old_factor_y;
 xlib_colormap * x_cmap;
 
 typedef struct _MagnifierData {
        int mag_width;
        int mag_height;
-       int factor;
+       int factor_x;
+       int factor_y;
        point center;
        int follow_mouse;
        int color_inverted;
+       int fast_rgb_convert;
        int contrast;
        GtkWidget *output_window;
        void *source_display;
index aa13e7a..506848f 100644 (file)
 struct sockaddr_un mag_server = { AF_UNIX ,  "/tmp/magnifier_socket" };
 
 typedef struct {
+       GdkRectangle extents;
+       GdkRectangle roi;
+       float zoom_x;
+       float zoom_y;
+       int contrast;
+       gboolean is_managed;
+       gboolean is_dirty;
+} ZoomRegionData;
+
+typedef struct {
        gchar *target_display;
        gchar *source_display;
        int   vertical_split;
@@ -23,8 +33,10 @@ typedef struct {
        int   mouse_follow;
        int   invert_image;
        float zoom_factor;
-       int   refresh_time;
+       int   min_refresh_time;
        int   no_bonobo;
+       int   fast_cmap_convert;
+       GList *zoom_regions;
 } MagnifierOptions;
 
 static MagnifierOptions global_options = { ":0.0",
@@ -37,6 +49,7 @@ static MagnifierOptions global_options = { ":0.0",
                                           0,
                                           2.0,
                                           200,
+                                          0,
                                           0
                                          };
 
@@ -47,9 +60,10 @@ struct poptOption magnifier_options [] = {
        {"horizontal", 'h', POPT_ARG_NONE, &global_options.horizontal_split, 'h', "split screen horizontally (if target display = source display)", NULL},
        {"dual-head", 'd', POPT_ARG_NONE, &global_options.dual_head, 'd', "dual-head display mode (maps magnifier to second display)", NULL},
        {"mouse follow", 'm', POPT_ARG_NONE, &global_options.mouse_follow, 'm', "track mouse movements", NULL},
-       {"refresh time", 'r', POPT_ARG_NONE, &global_options.refresh_time, 'r', "refresh time for mouse follow and idle, in ms", NULL},
+       {"refresh time", 'r', POPT_ARG_NONE, &global_options.min_refresh_time, 'r', "minimum refresh time for mouse follow and idle, in ms", NULL},
        {"zoom (scale) factor", 'z', POPT_ARG_FLOAT, &global_options.zoom_factor, 'z', "zoom (scale) factor used to magnify source display", NULL}, 
 /*     {"invert image", 'i', POPT_ARG_NONE, &global_options.invert_image, 'i', "invert the image colormap", NULL}, */
+       {"fast-colormap-conversion", 'c', POPT_ARG_NONE, &global_options.fast_cmap_convert, 'c', "use faster colormap conversion algorithm (fails for 6 bit color)", NULL}, 
        {"no-bonobo", '\0', POPT_ARG_NONE, &global_options.no_bonobo, '\0', "don't use bonobo for controls, use sockets", NULL},
        {NULL, 0, 0, NULL, 0, 0}
 };
@@ -101,11 +115,12 @@ int main (int argc, char** argv){
          global_options.mouse_follow;
   magnifier->mag_data->color_inverted =
          global_options.invert_image;
-  magnifier->mag_data->factor =
+  magnifier->mag_data->factor_x =
     (int) global_options.zoom_factor; 
-
-  /* TODO: enable fractional magnifications ? */
+  magnifier->mag_data->factor_y =
+    (int) global_options.zoom_factor;
   
+  /* TODO: enable fractional magnifications ? */
   if (global_options.target_display) {
     snprintf (env_string, (size_t) (ENV_STRING_MAX_SIZE-1), "DISPLAY=%s", global_options.target_display);
     putenv (env_string);
@@ -194,7 +209,7 @@ int main (int argc, char** argv){
   gdk_window_set_functions(window->window, 0);
   gdk_window_raise(window->window);
   
-  gtk_timeout_add(global_options.refresh_time, display_image, magnifier->mag_data);
+  gtk_timeout_add(global_options.min_refresh_time, display_image, magnifier->mag_data);
 
   obj_id = "OAFIID:Accessibility_Util_Magnifier:proto0.1";
 
@@ -281,6 +296,7 @@ impl_magnifier_goto (PortableServer_Servant servant,
 
 static void
 impl_magnifier_set_roi (PortableServer_Servant servant,
+                       const CORBA_short zoom_region,
                        const CORBA_long x1,
                        const CORBA_long y1,
                        const CORBA_long x2,
@@ -294,11 +310,78 @@ impl_magnifier_set_roi (PortableServer_Servant servant,
 
 static void
 impl_magnifier_set_mag_factor (PortableServer_Servant servant,
-                              const CORBA_float mag_factor,
+                              const CORBA_short zoom_region,
+                              const CORBA_float mag_factor_x,
+                              const CORBA_float mag_factor_y,
                               CORBA_Environment *ev)
 {
   Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
-  magnifier->mag_data->factor = (float) mag_factor;
+  magnifier->mag_data->factor_x = (float) mag_factor_x;
+  magnifier->mag_data->factor_y = (float) mag_factor_y;
+}
+
+static void
+impl_magnifier_mark_dirty (PortableServer_Servant servant,
+                          const CORBA_short zoom_region,
+                          CORBA_Environment *ev)
+{
+  Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
+}
+
+static void
+impl_magnifier_mark_unmanaged (PortableServer_Servant servant,
+                              const CORBA_short zoom_region,
+                              CORBA_Environment *ev)
+{
+  Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
+}
+
+static CORBA_short
+impl_magnifier_create_zoom_region (PortableServer_Servant servant,
+                                  const CORBA_float zx,
+                                  const CORBA_float zy,
+                                  const CORBA_long x1,
+                                  const CORBA_long y1,
+                                  const CORBA_long x2,
+                                  const CORBA_long y2,
+                                  CORBA_Environment *ev)
+{
+  Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
+  return -1;
+}
+
+static CORBA_boolean
+impl_magnifier_get_zoom_region_params (PortableServer_Servant _servant,
+                                      const CORBA_short zoom_region,
+                                      CORBA_float * zx,
+                                      CORBA_float * zy, CORBA_long * x1,
+                                      CORBA_long * y1, CORBA_long * x2,
+                                      CORBA_long * y2,
+                                      CORBA_Environment * ev)
+{
+       return CORBA_FALSE;
+}
+
+static void
+impl_magnifier_resize_zoom_region (PortableServer_Servant _servant,
+                                  const CORBA_short zoom_region,
+                                  const CORBA_long x1, const CORBA_long y1,
+                                  const CORBA_long x2, const CORBA_long y2,
+                                  CORBA_Environment * ev)
+{
+}
+
+static void
+impl_magnifier_destroy_zoom_region (PortableServer_Servant _servant,
+                                   const CORBA_short zoom_region,
+                                   CORBA_Environment * ev)
+{
+}
+
+static void
+impl_magnifier_clear_all_zoom_regions (PortableServer_Servant _servant,
+                                      CORBA_Environment * ev)
+{
 }
 
 static void
@@ -318,7 +401,14 @@ magnifier_class_init (MagnifierClass *klass)
         epv->_set_SourceDisplay = impl_magnifier_set_source_display;
        epv->_set_TargetDisplay = impl_magnifier_set_target_display;
        epv->setROI = impl_magnifier_set_roi;
-        epv->_set_MagFactor = impl_magnifier_set_mag_factor;
+        epv->setMagFactor = impl_magnifier_set_mag_factor;
+        epv->markDirty = impl_magnifier_mark_dirty;
+        epv->markUnmanaged = impl_magnifier_mark_unmanaged;
+       epv->createZoomRegion = impl_magnifier_create_zoom_region;
+       epv->getZoomRegionParams = impl_magnifier_get_zoom_region_params;
+       epv->resizeZoomRegion = impl_magnifier_resize_zoom_region;
+       epv->destroyZoomRegion = impl_magnifier_destroy_zoom_region;
+       epv->clearAllZoomRegions = impl_magnifier_clear_all_zoom_regions;
        epv->exit = impl_magnifier_exit;
 }
 
@@ -326,9 +416,11 @@ static void
 magnifier_init (Magnifier *magnifier)
 {
   magnifier->mag_data = (MagnifierData *) g_new0 (MagnifierData, 1);
-  magnifier->mag_data->factor = 2;
+  magnifier->mag_data->factor_x = 2;
+  magnifier->mag_data->factor_y = 2;
   magnifier->mag_data->contrast = 0;
   magnifier->mag_data->color_inverted = FALSE;
+  magnifier->mag_data->fast_rgb_convert = FALSE;
   magnifier->mag_data->center.x = 0;
   magnifier->mag_data->center.y = 0;
 }