[clutter] Clean up grab implementation



commit b6dd306998e626cbc86051dc1237894d515aa3dd
Author: Emmanuele Bassi <ebassi linux intel com>
Date:   Mon Oct 10 16:45:20 2011 +0100

    Clean up grab implementation
    
    The grab API is a relic of Clutter 0.6, and hasn't been through proper
    vetting in a *long* time â mostly due to the fact that we don't really
    like grabs, and point to the ::captured-event as a way to implement
    "soft grabs" in toolkits and applications.
    
    The implementation of full and device grabs uses weak references on
    actors instead of using the ::destroy signal, which is meant exactly for
    the case of releasing pointers to actors when they are disposed.
    
    The API naming scheme is also fairly broken, especially for
    device-related grabs.
    
    Finally, keyboard device grabs are just not implemented.
    
    We can, in one go, clean up this mess and deprecate a bunch of badly
    named API by introducing generic device grab/ungrab methods on
    ClutterInputDevice, and re-implement the current API on top of them.

 clutter/clutter-device-manager-private.h |    1 +
 clutter/clutter-input-device.h           |    5 +
 clutter/clutter-main.c                   |  268 ++++++++++++++++++++++-------
 clutter/clutter-main.h                   |   10 +-
 4 files changed, 215 insertions(+), 69 deletions(-)
---
diff --git a/clutter/clutter-device-manager-private.h b/clutter/clutter-device-manager-private.h
index 223cdde..4ae5940 100644
--- a/clutter/clutter-device-manager-private.h
+++ b/clutter/clutter-device-manager-private.h
@@ -75,6 +75,7 @@ struct _ClutterInputDevice
 
   /* the actor that has a grab in place for the device */
   ClutterActor *pointer_grab_actor;
+  ClutterActor *keyboard_grab_actor;
 
   /* the current click count */
   gint click_count;
diff --git a/clutter/clutter-input-device.h b/clutter/clutter-input-device.h
index 7b3a75b..0128920 100644
--- a/clutter/clutter-input-device.h
+++ b/clutter/clutter-input-device.h
@@ -167,6 +167,11 @@ void                    clutter_input_device_update_from_event  (ClutterInputDev
                                                                  ClutterEvent        *event,
                                                                  gboolean             update_stage);
 
+void                    clutter_input_device_grab               (ClutterInputDevice  *device,
+                                                                 ClutterActor        *actor);
+void                    clutter_input_device_ungrab             (ClutterInputDevice  *device);
+ClutterActor *          clutter_input_device_get_grabbed_actor  (ClutterInputDevice  *device);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_INPUT_DEVICE_H__ */
diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c
index 7ef9edb..f6f5806 100644
--- a/clutter/clutter-main.c
+++ b/clutter/clutter-main.c
@@ -2007,14 +2007,27 @@ emit_pointer_event (ClutterEvent       *event,
 }
 
 static inline void
-emit_keyboard_event (ClutterEvent *event)
+emit_keyboard_event (ClutterEvent       *event,
+                     ClutterInputDevice *device)
 {
   ClutterMainContext *context = _clutter_context_get_default ();
 
-  if (context->keyboard_grab_actor == NULL)
-    emit_event (event, TRUE);
+  if (context->keyboard_grab_actor == NULL &&
+      (device == NULL || device->keyboard_grab_actor == NULL))
+    {
+      emit_event (event, FALSE);
+    }
   else
-    clutter_actor_event (context->keyboard_grab_actor, event, FALSE);
+    {
+      if (context->keyboard_grab_actor != NULL)
+        {
+          clutter_actor_event (context->keyboard_grab_actor, event, FALSE);
+        }
+      else if (device != NULL && device->keyboard_grab_actor != NULL)
+        {
+          clutter_actor_event (context->keyboard_grab_actor, event, FALSE);
+        }
+    }
 }
 
 static gboolean
@@ -2102,7 +2115,7 @@ _clutter_process_event_details (ClutterActor        *stage,
                 }
             }
 
-          emit_keyboard_event (event);
+          emit_keyboard_event (event, device);
         }
         break;
 
@@ -2411,23 +2424,34 @@ clutter_set_default_frame_rate (guint frames_per_sec)
 
 
 static void
-on_pointer_grab_weak_notify (gpointer data,
-                             GObject *where_the_object_was)
+on_grab_actor_destroy (ClutterActor       *actor,
+                       ClutterInputDevice *device)
 {
-  ClutterInputDevice *dev = (ClutterInputDevice *)data;
-  ClutterMainContext *context;
+  if (device == NULL)
+    {
+      ClutterMainContext *context = _clutter_context_get_default ();
 
-  context = _clutter_context_get_default ();
+      if (context->pointer_grab_actor == actor)
+        clutter_ungrab_pointer ();
 
-  if (dev)
-    {
-      dev->pointer_grab_actor = NULL;
-      clutter_ungrab_pointer_for_device (dev->id);
+      if (context->keyboard_grab_actor == actor)
+        clutter_ungrab_keyboard ();
+
+      return;
     }
-  else
+
+  switch (device->device_type)
     {
-      context->pointer_grab_actor = NULL;
-      clutter_ungrab_pointer ();
+    case CLUTTER_POINTER_DEVICE:
+      device->pointer_grab_actor = NULL;
+      break;
+
+    case CLUTTER_KEYBOARD_DEVICE:
+      device->keyboard_grab_actor = NULL;
+      break;
+
+    default:
+      g_assert_not_reached ();
     }
 }
 
@@ -2446,8 +2470,10 @@ on_pointer_grab_weak_notify (gpointer data,
  * using the #ClutterActor::captured-event signal should always be the
  * preferred way to intercept event delivery to reactive actors.</para></note>
  *
- * If you wish to grab all the pointer events for a specific input device,
- * you should use clutter_grab_pointer_for_device().
+ * This function should rarely be used.
+ *
+ * If a grab is required, you are strongly encouraged to use a specific
+ * input device by calling clutter_input_device_grab().
  *
  * Since: 0.6
  */
@@ -2463,22 +2489,150 @@ clutter_grab_pointer (ClutterActor *actor)
   if (context->pointer_grab_actor == actor)
     return;
 
-  if (context->pointer_grab_actor)
+  if (context->pointer_grab_actor != NULL)
     {
-      g_object_weak_unref (G_OBJECT (context->pointer_grab_actor),
-			   on_pointer_grab_weak_notify,
-			   NULL);
+      g_signal_handlers_disconnect_by_func (context->pointer_grab_actor,
+                                            G_CALLBACK (on_grab_actor_destroy),
+                                            NULL);
       context->pointer_grab_actor = NULL;
     }
 
-  if (actor)
+  if (actor != NULL)
     {
       context->pointer_grab_actor = actor;
 
-      g_object_weak_ref (G_OBJECT (actor),
-			 on_pointer_grab_weak_notify,
-			 NULL);
+      g_signal_connect (context->pointer_grab_actor, "destroy",
+                        G_CALLBACK (on_grab_actor_destroy),
+                        NULL);
+    }
+}
+
+/**
+ * clutter_input_device_grab:
+ * @device: a #ClutterInputDevice
+ * @actor: a #ClutterActor
+ *
+ * Acquires a grab on @actor for the given @device.
+ *
+ * Any event coming from @device will be delivered to @actor, bypassing
+ * the usual event delivery mechanism, until the grab is released by
+ * calling clutter_input_device_ungrab().
+ *
+ * The grab is client-side: even if the windowing system used by the Clutter
+ * backend has the concept of "device grabs", Clutter will not use them.
+ *
+ * Only #ClutterInputDevice of types %CLUTTER_POINTER_DEVICE and
+ * %CLUTTER_KEYBOARD_DEVICE can hold a grab.
+ *
+ * Since: 1.10
+ */
+void
+clutter_input_device_grab (ClutterInputDevice *device,
+                           ClutterActor       *actor)
+{
+  ClutterActor **grab_actor;
+
+  g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
+  g_return_if_fail (CLUTTER_IS_ACTOR (actor));
+
+  switch (device->device_type)
+    {
+    case CLUTTER_POINTER_DEVICE:
+      grab_actor = &(device->pointer_grab_actor);
+      break;
+
+    case CLUTTER_KEYBOARD_DEVICE:
+      grab_actor = &(device->keyboard_grab_actor);
+      break;
+
+    default:
+      g_critical ("Only pointer and keyboard devices can grab an actor");
+      return;
+    }
+
+  if (*grab_actor != NULL)
+    {
+      g_signal_handlers_disconnect_by_func (*grab_actor,
+                                            G_CALLBACK (on_grab_actor_destroy),
+                                            device);
+    }
+
+  *grab_actor = actor;
+
+  g_signal_connect (*grab_actor,
+                    "destroy",
+                    G_CALLBACK (on_grab_actor_destroy),
+                    device);
+}
+
+/**
+ * clutter_input_device_ungrab:
+ * @device: a #ClutterInputDevice
+ *
+ * Releases the grab on the @device, if one is in place.
+ *
+ * Since: 1.10
+ */
+void
+clutter_input_device_ungrab (ClutterInputDevice *device)
+{
+  ClutterActor **grab_actor;
+
+  g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
+
+  switch (device->device_type)
+    {
+    case CLUTTER_POINTER_DEVICE:
+      grab_actor = &(device->pointer_grab_actor);
+      break;
+
+    case CLUTTER_KEYBOARD_DEVICE:
+      grab_actor = &(device->keyboard_grab_actor);
+      break;
+
+    default:
+      return;
+    }
+
+  if (*grab_actor == NULL)
+    return;
+
+  g_signal_handlers_disconnect_by_func (*grab_actor,
+                                        G_CALLBACK (on_grab_actor_destroy),
+                                        device);
+
+  *grab_actor = NULL;
+}
+
+/**
+ * clutter_input_device_get_grabbed_actor:
+ * @device: a #ClutterInputDevice
+ *
+ * Retrieves a pointer to the #ClutterActor currently grabbing all
+ * the events coming from @device.
+ *
+ * Return value: (transfer none): a #ClutterActor, or %NULL
+ *
+ * Since: 1.10
+ */
+ClutterActor *
+clutter_input_device_get_grabbed_actor (ClutterInputDevice *device)
+{
+  g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
+
+  switch (device->device_type)
+    {
+    case CLUTTER_POINTER_DEVICE:
+      return device->pointer_grab_actor;
+
+    case CLUTTER_KEYBOARD_DEVICE:
+      return device->keyboard_grab_actor;
+
+    default:
+      g_critical ("Only pointer and keyboard devices can grab an actor");
     }
+
+  return NULL;
 }
 
 /**
@@ -2491,6 +2645,8 @@ clutter_grab_pointer (ClutterActor *actor)
  * If @id is -1 then this function is equivalent to clutter_grab_pointer().
  *
  * Since: 0.8
+ *
+ * Deprecated: 1.10: Use clutter_input_device_grab() instead.
  */
 void
 clutter_grab_pointer_for_device (ClutterActor *actor,
@@ -2503,7 +2659,11 @@ clutter_grab_pointer_for_device (ClutterActor *actor,
   /* essentially a global grab */
   if (id_ == -1)
     {
-      clutter_grab_pointer (actor);
+      if (actor == NULL)
+        clutter_ungrab_pointer ();
+      else
+        clutter_grab_pointer (actor);
+
       return;
     }
 
@@ -2511,25 +2671,13 @@ clutter_grab_pointer_for_device (ClutterActor *actor,
   if (dev == NULL)
     return;
 
-  if (dev->pointer_grab_actor == actor)
+  if (dev->device_type != CLUTTER_POINTER_DEVICE)
     return;
 
-  if (dev->pointer_grab_actor)
-    {
-      g_object_weak_unref (G_OBJECT (dev->pointer_grab_actor),
-                           on_pointer_grab_weak_notify,
-                           dev);
-      dev->pointer_grab_actor = NULL;
-    }
-
-  if (actor)
-    {
-      dev->pointer_grab_actor = actor;
-
-      g_object_weak_ref (G_OBJECT (actor),
-                         on_pointer_grab_weak_notify,
-                         dev);
-    }
+  if (actor == NULL)
+    clutter_input_device_ungrab (dev);
+  else
+    clutter_input_device_grab (dev, actor);
 }
 
 
@@ -2553,6 +2701,8 @@ clutter_ungrab_pointer (void)
  * Removes an existing grab of the pointer events for device @id_.
  *
  * Since: 0.8
+ *
+ * Deprecated: 1.10: Use clutter_input_device_ungrab() instead.
  */
 void
 clutter_ungrab_pointer_for_device (gint id_)
@@ -2580,18 +2730,6 @@ clutter_get_pointer_grab (void)
 }
 
 
-static void
-on_keyboard_grab_weak_notify (gpointer data,
-                              GObject *where_the_object_was)
-{
-  ClutterMainContext *context;
-
-  context = _clutter_context_get_default ();
-  context->keyboard_grab_actor = NULL;
-
-  clutter_ungrab_keyboard ();
-}
-
 /**
  * clutter_grab_keyboard:
  * @actor: a #ClutterActor
@@ -2622,21 +2760,21 @@ clutter_grab_keyboard (ClutterActor *actor)
   if (context->keyboard_grab_actor == actor)
     return;
 
-  if (context->keyboard_grab_actor)
+  if (context->keyboard_grab_actor != NULL)
     {
-      g_object_weak_unref (G_OBJECT (context->keyboard_grab_actor),
-			   on_keyboard_grab_weak_notify,
-			   NULL);
+      g_signal_handlers_disconnect_by_func (context->keyboard_grab_actor,
+                                            G_CALLBACK (on_grab_actor_destroy),
+                                            NULL);
       context->keyboard_grab_actor = NULL;
     }
 
-  if (actor)
+  if (actor != NULL)
     {
       context->keyboard_grab_actor = actor;
 
-      g_object_weak_ref (G_OBJECT (actor),
-			 on_keyboard_grab_weak_notify,
-			 NULL);
+      g_signal_connect (context->keyboard_grab_actor, "destroy",
+                        G_CALLBACK (on_grab_actor_destroy),
+                        NULL);
     }
 }
 
diff --git a/clutter/clutter-main.h b/clutter/clutter-main.h
index 3ddc263..34328e8 100644
--- a/clutter/clutter-main.h
+++ b/clutter/clutter-main.h
@@ -96,7 +96,7 @@ void             clutter_main                       (void);
 void             clutter_main_quit                  (void);
 gint             clutter_main_level                 (void);
 
-#ifndef CLUTTER_DISABLE_DEPRECATED
+#if !defined(CLUTTER_DISABLE_DEPRECATED) || defined(CLUTTER_COMPILATION)
 void             clutter_redraw                     (ClutterStage *stage)
                                                     G_GNUC_DEPRECATED_FOR (clutter_stage_ensure_redraw);
 #endif
@@ -110,7 +110,7 @@ gulong           clutter_get_timestamp              (void);
 gboolean         clutter_get_accessibility_enabled  (void);
 
 /* Threading functions */
-#ifndef CLUTTER_DISABLE_DEPRECATED
+#if !defined(CLUTTER_DISABLE_DEPRECATED) || defined(CLUTTER_COMPILATION)
 void             clutter_threads_init                  (void);
 #endif
 
@@ -133,7 +133,7 @@ guint            clutter_threads_add_timeout_full      (gint           priority,
                                                         gpointer       data,
                                                         GDestroyNotify notify);
 
-#ifndef CLUTTER_DISABLE_DEPRECATED
+#if !defined(CLUTTER_DISABLE_DEPRECATED) || defined(CLUTTER_COMPILATION)
 guint            clutter_threads_add_frame_source      (guint          fps,
 						        GSourceFunc    func,
 						        gpointer       data);
@@ -149,7 +149,7 @@ guint            clutter_threads_add_repaint_func      (GSourceFunc    func,
                                                         GDestroyNotify notify);
 void             clutter_threads_remove_repaint_func   (guint          handle_id);
 
-#ifndef CLUTTER_DISABLE_DEPRECATED
+#if !defined(CLUTTER_DISABLE_DEPRECATED) || defined(CLUTTER_COMPILATION)
 void             clutter_set_motion_events_enabled   (gboolean enable);
 gboolean         clutter_get_motion_events_enabled   (void);
 #endif /* CLUTTER_DISABLE_DEPRECATED */
@@ -171,9 +171,11 @@ ClutterFontFlags clutter_get_font_flags              (void);
 
 ClutterInputDevice *clutter_get_input_device_for_id  (gint id_);
 
+#if !defined(CLUTTER_DISABLE_DEPRECATED) || defined(CLUTTER_COMPILATION)
 void             clutter_grab_pointer_for_device     (ClutterActor  *actor,
                                                       gint           id_);
 void             clutter_ungrab_pointer_for_device   (gint id_);
+#endif
 
 PangoFontMap *   clutter_get_font_map                (void);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]