Added boolean return types for methods in Component, Selection,
[platform/core/uifw/at-spi2-atk.git] / registryd / deviceeventcontroller.c
index 04586e0..3054e6a 100644 (file)
@@ -24,7 +24,7 @@
 
 #include <config.h>
 
-#undef SPI_DEBUG
+#define  SPI_DEBUG
 
 #include <string.h>
 #include <ctype.h>
 /* A pointer to our parent object class */
 static GObjectClass *spi_device_event_controller_parent_class;
 
+int (*x_default_error_handler) (Display *display, XErrorEvent *error_event);
+
 typedef enum {
   SPI_DEVICE_TYPE_KBD,
+  SPI_DEVICE_TYPE_MOUSE,
   SPI_DEVICE_TYPE_LAST_DEFINED
 } SpiDeviceTypeCategory;
 
@@ -86,12 +89,14 @@ static void     spi_controller_register_device_listener       (SpiDEController
 static void     spi_device_event_controller_forward_key_event (SpiDEController           *controller,
                                                               const XEvent              *event);
 
+#define spi_get_display() GDK_DISPLAY()
+
 /* Private methods */
 
 static KeyCode
 keycode_for_keysym (long keysym)
 {
-  return XKeysymToKeycode (GDK_DISPLAY (), (KeySym) keysym);
+  return XKeysymToKeycode (spi_get_display (), (KeySym) keysym);
 }
 
 static DEControllerGrabMask *
@@ -210,7 +215,10 @@ _deregister_keygrab (SpiDEController      *controller,
       DEControllerGrabMask *cur_mask = l->data;
 
       cur_mask->ref_count--;
-      cur_mask->pending_remove = TRUE;
+      if (cur_mask->ref_count <= 0)
+        {
+          cur_mask->pending_remove = TRUE;
+       }
     }
   else
     {
@@ -242,7 +250,7 @@ handle_keygrab (SpiDEController         *controller,
          /* X Grabs require keycodes, not keysyms */
          if (key_val >= 0)
            {
-             key_val = XKeysymToKeycode (GDK_DISPLAY (), (KeySym) key_val);
+             key_val = XKeysymToKeycode (spi_get_display (), (KeySym) key_val);
            }
          grab_mask.key_val = key_val;
 
@@ -309,6 +317,20 @@ global_filter_fn (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
   return GDK_FILTER_CONTINUE;
 }
 
+int
+_spi_controller_device_error_handler (Display *display, XErrorEvent *error)
+{
+  if (error->error_code == BadAccess) 
+    {  
+      g_message ("Could not complete key grab: grab already in use.\n");
+      return 0;
+    }
+  else 
+    {
+      return (*x_default_error_handler) (display, error);
+    }
+}
+
 static void
 spi_controller_register_with_devices (SpiDEController *controller)
 {
@@ -321,9 +343,7 @@ spi_controller_register_with_devices (SpiDEController *controller)
   gdk_window_set_events (gdk_get_default_root_window (),
                         GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
 
-  XSelectInput (GDK_DISPLAY (),
-               DefaultRootWindow (GDK_DISPLAY ()),
-               KeyPressMask | KeyReleaseMask);
+  x_default_error_handler = XSetErrorHandler (_spi_controller_device_error_handler);
 }
 
 static gboolean
@@ -480,7 +500,10 @@ spi_notify_keylisteners (GList                          **key_listeners,
     }
 
   g_slist_free (notify);
-  
+
+#ifdef SPI_DEBUG
+  if (is_consumed) g_message ("consumed\n");
+#endif
   return is_consumed;
 }
 
@@ -577,6 +600,7 @@ spi_controller_update_key_grabs (SpiDEController           *controller,
       next = l->next;
 
       re_issue_grab = recv &&
+/*           (recv->type == Accessibility_KEY_RELEASED) && - (?) */
              (recv->modifiers & grab_mask->mod_mask) &&
              (grab_mask->key_val == keycode_for_keysym (recv->id));
 
@@ -597,7 +621,10 @@ spi_controller_update_key_grabs (SpiDEController           *controller,
        }
       else if (grab_mask->pending_remove)
         {
-         XUngrabKey (GDK_DISPLAY (),
+#ifdef SPI_DEBUG
+      fprintf (stderr, "ungrabbing, mask=%x\n", grab_mask->mod_mask);
+#endif
+         XUngrabKey (spi_get_display (),
                      grab_mask->key_val,
                      grab_mask->mod_mask,
                      gdk_x11_get_default_root_xwindow ());
@@ -606,7 +633,11 @@ spi_controller_update_key_grabs (SpiDEController           *controller,
        }
       else if (grab_mask->pending_add || re_issue_grab)
         {
-          XGrabKey (GDK_DISPLAY (),
+
+#ifdef SPI_DEBUG
+         fprintf (stderr, "grab with mask %x\n", grab_mask->mod_mask);
+#endif
+          XGrabKey (spi_get_display (),
                    grab_mask->key_val,
                    grab_mask->mod_mask,
                    gdk_x11_get_default_root_xwindow (),
@@ -648,6 +679,7 @@ spi_device_event_controller_object_finalize (GObject *object)
   fprintf(stderr, "spi_device_event_controller_object_finalize called\n");
 #endif
   /* disconnect any special listeners, get rid of outstanding keygrabs */
+  XUngrabKey (spi_get_display (), AnyKey, AnyModifier, DefaultRootWindow (spi_get_display ()));
        
   spi_device_event_controller_parent_class->finalize (object);
 }
@@ -683,7 +715,7 @@ typedef struct {
        DEControllerKeyListener *key_listener;
 } RemoveKeyListenerClosure;
 
-static SpiReEnterantContinue
+static SpiReEntrantContinue
 remove_key_listener_cb (GList * const *list,
                        gpointer       user_data)
 {
@@ -693,11 +725,29 @@ remove_key_listener_cb (GList * const *list,
   if (CORBA_Object_is_equivalent (ctx->key_listener->listener.object,
                                  key_listener->listener.object, ctx->ev))
     {
-      spi_re_enterant_list_delete_link (list);
+      spi_re_entrant_list_delete_link (list);
       spi_dec_key_listener_free (key_listener, ctx->ev);
     }
 
-  return SPI_RE_ENTERANT_CONTINUE;
+  return SPI_RE_ENTRANT_CONTINUE;
+}
+
+static SpiReEntrantContinue
+copy_key_listener_cb (GList * const *list,
+                     gpointer       user_data)
+{
+  DEControllerKeyListener  *key_listener = (*list)->data;
+  RemoveKeyListenerClosure *ctx = user_data;
+
+  if (CORBA_Object_is_equivalent (ctx->key_listener->listener.object,
+                                 key_listener->listener.object, ctx->ev))
+    {
+      /* TODO: FIXME aggregate keys in case the listener is registered twice */
+      CORBA_free (ctx->key_listener->keys);        
+      ctx->key_listener->keys = ORBit_copy_value (key_listener->keys, TC_Accessibility_KeySet);
+    }
+
+  return SPI_RE_ENTRANT_CONTINUE;
 }
 
 /*
@@ -725,12 +775,19 @@ impl_deregister_keystroke_listener (PortableServer_Servant                  serv
           (void *) l, (unsigned long) mask->value);
 #endif
 
-  spi_controller_deregister_global_keygrabs (controller, key_listener);
-
   ctx.ev = ev;
   ctx.key_listener = key_listener;
 
-  spi_re_enterant_list_foreach (&controller->key_listeners,
+  /* special case, copy keyset from existing controller list entry */
+  if (keys->_length == 0) 
+    {
+      spi_re_entrant_list_foreach (&controller->key_listeners,
+                                 copy_key_listener_cb, &ctx);
+    }
+  
+  spi_controller_deregister_global_keygrabs (controller, key_listener);
+
+  spi_re_entrant_list_foreach (&controller->key_listeners,
                                remove_key_listener_cb, &ctx);
 
   spi_dec_key_listener_free (key_listener, ev);
@@ -768,17 +825,17 @@ impl_generate_keyboard_event (PortableServer_Servant           servant,
   switch (synth_type)
     {
       case Accessibility_KEY_PRESS:
-        XTestFakeKeyEvent (GDK_DISPLAY (), (unsigned int) keycode, True, CurrentTime);
+        XTestFakeKeyEvent (spi_get_display (), (unsigned int) keycode, True, CurrentTime);
        break;
       case Accessibility_KEY_PRESSRELEASE:
-       XTestFakeKeyEvent (GDK_DISPLAY (), (unsigned int) keycode, True, CurrentTime);
+       XTestFakeKeyEvent (spi_get_display (), (unsigned int) keycode, True, CurrentTime);
       case Accessibility_KEY_RELEASE:
-       XTestFakeKeyEvent (GDK_DISPLAY (), (unsigned int) keycode, False, CurrentTime);
+       XTestFakeKeyEvent (spi_get_display (), (unsigned int) keycode, False, CurrentTime);
        break;
       case Accessibility_KEY_SYM:
        key_synth_code = keycode_for_keysym (keycode);
-       XTestFakeKeyEvent (GDK_DISPLAY (), (unsigned int) key_synth_code, True, CurrentTime);
-       XTestFakeKeyEvent (GDK_DISPLAY (), (unsigned int) key_synth_code, False, CurrentTime);
+       XTestFakeKeyEvent (spi_get_display (), (unsigned int) key_synth_code, True, CurrentTime);
+       XTestFakeKeyEvent (spi_get_display (), (unsigned int) key_synth_code, False, CurrentTime);
        break;
       case Accessibility_KEY_STRING:
        fprintf (stderr, "Not yet implemented\n");
@@ -798,11 +855,58 @@ impl_generate_mouse_event (PortableServer_Servant servant,
                           const CORBA_char      *eventName,
                           CORBA_Environment     *ev)
 {
+  int button;
+  gboolean error = FALSE;
+  Display *display = spi_get_display ();
 #ifdef SPI_DEBUG
   fprintf (stderr, "generating mouse %s event at %ld, %ld\n",
           eventName, (long int) x, (long int) y);
 #endif
-  g_warning ("not yet implemented");
+  g_message ("mouse event synthesis\n");
+  switch (eventName[0])
+    {
+      case 'b':
+        switch (eventName[1])
+         {
+         /* TODO: check number of buttons before parsing */
+         case '1':
+                   button = 1;
+                   break;
+         case '2':
+                 button = 2;
+                 break;
+         case '3':
+                 button = 3;
+                 break;
+         default:
+                 error = TRUE;
+         }
+       if (!error)
+         {
+           if (x != -1 && y != -1)
+             {
+               XTestFakeMotionEvent (display, DefaultScreen (display),
+                                     x, y, 0);
+             }
+           XTestFakeButtonEvent (display, button, !(eventName[2] == 'r'), 0);
+           if (eventName[2] == 'c')
+             XTestFakeButtonEvent (display, button, FALSE, 1);
+           else if (eventName[2] == 'd')
+             {
+             XTestFakeButtonEvent (display, button, FALSE, 1);
+             XTestFakeButtonEvent (display, button, TRUE, 2);
+             XTestFakeButtonEvent (display, button, FALSE, 3);
+             }
+         }
+       break;
+      case 'r': /* relative motion */ 
+       XTestFakeRelativeMotionEvent (display, x, y, 0);
+        break;
+      case 'a': /* absolute motion */
+       XTestFakeMotionEvent (display, DefaultScreen (display),
+                             x, y, 0);
+        break;
+    }
 }
 
 /* Accessibility::DEController::notifyListenersSync */
@@ -883,6 +987,9 @@ spi_device_event_controller_forward_key_event (SpiDEController *controller,
   CORBA_exception_init (&ev);
 
   key_event = spi_keystroke_from_x_key_event ((XKeyEvent *) event);
+
+  spi_controller_update_key_grabs (controller, &key_event);
+
   /* relay to listeners, and decide whether to consume it or not */
   is_consumed = spi_notify_keylisteners (
     &controller->key_listeners, &key_event, CORBA_TRUE, &ev);
@@ -891,14 +998,12 @@ spi_device_event_controller_forward_key_event (SpiDEController *controller,
 
   if (is_consumed)
     {
-      XAllowEvents (GDK_DISPLAY (), AsyncKeyboard, CurrentTime);
+      XAllowEvents (spi_get_display (), AsyncKeyboard, CurrentTime);
     }
   else
     {
-      XAllowEvents (GDK_DISPLAY (), ReplayKeyboard, CurrentTime);
+      XAllowEvents (spi_get_display (), ReplayKeyboard, CurrentTime);
     }
-
-  spi_controller_update_key_grabs (controller, &key_event);
 }
 
 SpiDEController *