Bugfix for keygrab regression (registryd was holding keygrabs after they should have...
[platform/core/uifw/at-spi2-atk.git] / registryd / deviceeventcontroller.c
index 04586e0..3f7731c 100644 (file)
 /* 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;
 
@@ -309,6 +312,19 @@ 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");
+    }
+  else 
+    {
+      (*x_default_error_handler) (display, error);
+    }
+}
+
 static void
 spi_controller_register_with_devices (SpiDEController *controller)
 {
@@ -321,6 +337,8 @@ spi_controller_register_with_devices (SpiDEController *controller)
   gdk_window_set_events (gdk_get_default_root_window (),
                         GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
 
+  x_default_error_handler = XSetErrorHandler (_spi_controller_device_error_handler);
+
   XSelectInput (GDK_DISPLAY (),
                DefaultRootWindow (GDK_DISPLAY ()),
                KeyPressMask | KeyReleaseMask);
@@ -597,6 +615,9 @@ spi_controller_update_key_grabs (SpiDEController           *controller,
        }
       else if (grab_mask->pending_remove)
         {
+#ifdef SPI_DEBUG
+      fprintf (stderr, "ungrabbing, mask=%x\n", grab_mask->mod_mask);
+#endif
          XUngrabKey (GDK_DISPLAY (),
                      grab_mask->key_val,
                      grab_mask->mod_mask,
@@ -606,6 +627,10 @@ spi_controller_update_key_grabs (SpiDEController           *controller,
        }
       else if (grab_mask->pending_add || re_issue_grab)
         {
+
+#ifdef SPI_DEBUG
+         fprintf (stderr, "grab with mask %x\n", grab_mask->mod_mask);
+#endif
           XGrabKey (GDK_DISPLAY (),
                    grab_mask->key_val,
                    grab_mask->mod_mask,
@@ -648,6 +673,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 (GDK_DISPLAY (), AnyKey, AnyModifier, DefaultRootWindow (GDK_DISPLAY ()));
        
   spi_device_event_controller_parent_class->finalize (object);
 }
@@ -683,7 +709,7 @@ typedef struct {
        DEControllerKeyListener *key_listener;
 } RemoveKeyListenerClosure;
 
-static SpiReEnterantContinue
+static SpiReEntrantContinue
 remove_key_listener_cb (GList * const *list,
                        gpointer       user_data)
 {
@@ -693,11 +719,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 +769,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);