[mutter/wip/verdre/device-actors-stage: 1/3] clutter/stage: Add infrastructure to track devices and their actors




commit 4f196afef9cba0561d7d531d248185c00a132cdc
Author: Jonas Dreßler <verdre v0yd nl>
Date:   Thu Oct 15 16:39:00 2020 +0200

    clutter/stage: Add infrastructure to track devices and their actors
    
    For the input thread to get to its full potential we need to move the
    tracking of actors associated with input devices out of
    ClutterInputDevice. We're going to move it into ClutterStage instead.
    
    So start that by adding the infrastructure to ClutterStage to keep track
    of those things. It consists of two hashtables which associate devices
    and touch sequences with actors, those hashtables get updated using
    clutter_stage_associate_actor_device() and can be queried by calling
    clutter_stage_get_device_actor(), which will replace
    clutter_input_device_get_actor().

 clutter/clutter/clutter-stage-private.h |   5 ++
 clutter/clutter/clutter-stage.c         | 146 ++++++++++++++++++++++++++++++++
 clutter/clutter/clutter-stage.h         |   5 ++
 3 files changed, 156 insertions(+)
---
diff --git a/clutter/clutter/clutter-stage-private.h b/clutter/clutter/clutter-stage-private.h
index ef5ce1da49..4860d50240 100644
--- a/clutter/clutter/clutter-stage-private.h
+++ b/clutter/clutter/clutter-stage-private.h
@@ -149,6 +149,11 @@ GList * clutter_stage_get_views_for_rect (ClutterStage          *stage,
 
 void clutter_stage_set_actor_needs_immediate_relayout (ClutterStage *stage);
 
+void clutter_stage_associate_actor_device (ClutterStage         *stage,
+                                           ClutterActor         *actor,
+                                           ClutterInputDevice   *device,
+                                           ClutterEventSequence *sequence);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_STAGE_PRIVATE_H__ */
diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c
index 075e809140..9ee0dfdb61 100644
--- a/clutter/clutter/clutter-stage.c
+++ b/clutter/clutter/clutter-stage.c
@@ -142,6 +142,9 @@ struct _ClutterStagePrivate
   gboolean needs_update_devices;
   gboolean pending_finish_queue_redraws;
 
+  GHashTable *device_actors;
+  GHashTable *sequence_actors;
+
   guint redraw_pending         : 1;
   guint throttle_motion_events : 1;
   guint min_size_changed       : 1;
@@ -1701,6 +1704,9 @@ clutter_stage_finalize (GObject *object)
   g_queue_foreach (priv->event_queue, (GFunc) clutter_event_free, NULL);
   g_queue_free (priv->event_queue);
 
+  g_hash_table_destroy (priv->device_actors);
+  g_hash_table_destroy (priv->sequence_actors);
+
   g_free (priv->title);
 
   g_array_free (priv->paint_volume_stack, TRUE);
@@ -2004,6 +2010,9 @@ clutter_stage_init (ClutterStage *self)
   priv->sync_delay = -1;
   priv->motion_events_enabled = TRUE;
 
+  priv->device_actors = g_hash_table_new_full (NULL, NULL, NULL, g_free);
+  priv->sequence_actors = g_hash_table_new_full (NULL, NULL, NULL, g_free);
+
   clutter_actor_set_background_color (CLUTTER_ACTOR (self),
                                       &default_stage_color);
 
@@ -3856,3 +3865,140 @@ clutter_stage_set_actor_needs_immediate_relayout (ClutterStage *stage)
 
   priv->actor_needs_immediate_relayout = TRUE;
 }
+
+typedef struct _DeviceActorEntry
+{
+  ClutterStage *stage;
+  ClutterInputDevice *device;
+  ClutterEventSequence *sequence;
+  ClutterActor *actor;
+} DeviceActorEntry;
+
+static void
+on_device_actor_destroy (ClutterActor     *actor,
+                         DeviceActorEntry *entry)
+{
+  ClutterStage *self = entry->stage;
+  ClutterStagePrivate *priv = self->priv;
+
+  /* We simply remove the entry from the hashtable without calling
+   * clutter_stage_associate_actor_device() since there's no need to
+   * unset has_pointer or to disconnect signals.
+   */
+  if (entry->sequence != NULL)
+    g_hash_table_remove (priv->sequence_actors, entry->sequence);
+  else
+    g_hash_table_remove (priv->device_actors, entry->device);
+}
+
+static void
+on_device_actor_reactive_changed (ClutterActor       *actor,
+                                  GParamSpec         *pspec,
+                                  DeviceActorEntry *entry)
+{
+// FIXME: we probably want to trigger a repick in this case
+
+  if (!clutter_actor_get_reactive (actor))
+    clutter_stage_associate_actor_device (entry->stage,
+                                          NULL,
+                                          entry->device,
+                                          entry->sequence);
+
+}
+
+void
+clutter_stage_associate_actor_device (ClutterStage         *self,
+                                      ClutterActor         *actor,
+                                      ClutterInputDevice   *device,
+                                      ClutterEventSequence *sequence)
+{
+  ClutterStagePrivate *priv = self->priv;
+  DeviceActorEntry *old_entry = NULL;
+
+  g_assert (sequence != NULL || device != NULL);
+
+  if (sequence != NULL)
+    {
+      g_hash_table_steal_extended (priv->sequence_actors, sequence,
+                                   NULL, (gpointer) &old_entry);
+    }
+  else
+    {
+      g_hash_table_steal_extended (priv->device_actors, device,
+                                   NULL, (gpointer) &old_entry);
+    }
+
+
+  if (old_entry)
+    {
+      ClutterActor *old_actor = old_entry->actor;
+
+      g_signal_handlers_disconnect_by_func (old_actor,
+                                            G_CALLBACK (on_device_actor_destroy),
+                                            old_entry);
+      g_signal_handlers_disconnect_by_func (old_actor,
+                                            G_CALLBACK (on_device_actor_reactive_changed),
+                                            old_entry);
+
+      _clutter_actor_set_has_pointer (old_actor, FALSE);
+
+      g_clear_pointer (&old_entry, g_free);
+    }
+
+  if (actor)
+    {
+      DeviceActorEntry *new_entry = g_new0 (DeviceActorEntry, 1);
+
+      new_entry->stage = self;
+      new_entry->device = device;
+      new_entry->sequence = sequence;
+      new_entry->actor = actor;
+
+      if (sequence != NULL)
+        g_hash_table_insert (priv->sequence_actors, sequence, new_entry);
+      else
+        g_hash_table_insert (priv->device_actors, device, new_entry);
+
+      g_signal_connect (actor, "destroy",
+                        G_CALLBACK (on_device_actor_destroy), new_entry);
+      g_signal_connect (actor, "notify::reactive",
+                        G_CALLBACK (on_device_actor_reactive_changed), new_entry);
+
+      _clutter_actor_set_has_pointer (actor, TRUE);
+    }
+
+}
+
+/**
+ * clutter_stage_get_device_actor:
+ * @stage: a #ClutterStage
+ * @device: a #ClutterInputDevice
+ * @sequence: (allow-none): an optional #ClutterEventSequence
+ *
+ * Retrieves the #ClutterActor underneath the pointer or touchpoint
+ * of @device and @sequence.
+ *
+ * Return value: (transfer none): a pointer to the #ClutterActor or %NULL
+ */
+ClutterActor *
+clutter_stage_get_device_actor (ClutterStage         *stage,
+                                ClutterInputDevice   *device,
+                                ClutterEventSequence *sequence)
+{
+  ClutterStagePrivate *priv = stage->priv;
+  DeviceActorEntry *entry = NULL;
+
+  g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
+
+  if (sequence != NULL)
+    entry = g_hash_table_lookup (priv->sequence_actors, sequence);
+  else if (device != NULL)
+    entry = g_hash_table_lookup (priv->device_actors, device);
+  else
+    g_assert_not_reached ();
+
+  if (entry)
+    return entry->actor;
+
+  return NULL;
+}
diff --git a/clutter/clutter/clutter-stage.h b/clutter/clutter/clutter-stage.h
index 7d94b68c38..bfacc715ec 100644
--- a/clutter/clutter/clutter-stage.h
+++ b/clutter/clutter/clutter-stage.h
@@ -236,6 +236,11 @@ ClutterStageView * clutter_stage_get_view_at (ClutterStage *stage,
                                               float         x,
                                               float         y);
 
+CLUTTER_EXPORT
+ClutterActor * clutter_stage_get_device_actor (ClutterStage         *stage,
+                                               ClutterInputDevice   *device,
+                                               ClutterEventSequence *sequence);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_STAGE_H__ */


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