summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Dreßler <verdre@v0yd.nl>2020-10-15 16:39:00 +0200
committerJonas Dreßler <verdre@v0yd.nl>2020-12-18 15:09:48 +0100
commit98a5cb37d9159737f8f1af4196420db90bfcf879 (patch)
treefe633d1767c3f8ea357eddbee61a0b62e1832f29
parent0a456b4808eb9ccbcedf8020948254d07d4027e4 (diff)
downloadmutter-98a5cb37d9159737f8f1af4196420db90bfcf879.tar.gz
clutter/stage: Add infrastructure to track devices and their actors
With the introduction of the input thread, we want to avoid modifying ClutterInputDevices from the main thread, since they're owned and updated by the thread. There's one part of ClutterInputDevice that's still modified from the main thread though, that is device-actors of pointer devices, and we're going to move that state-tracking 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_update_device_entry() and clutter_stage_remove_device_entry(), they can be queried by calling clutter_stage_get_device_actor(), which will replace clutter_input_device_get_actor(). clutter_stage_get_device_coords() is added and made available in clutter-mutter.h because we need to get the coordinates when repicking in meta_wayland_pointer_repick(). Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1633>
-rw-r--r--clutter/clutter/clutter-mutter.h6
-rw-r--r--clutter/clutter/clutter-stage-private.h10
-rw-r--r--clutter/clutter/clutter-stage.c202
-rw-r--r--clutter/clutter/clutter-stage.h5
4 files changed, 223 insertions, 0 deletions
diff --git a/clutter/clutter/clutter-mutter.h b/clutter/clutter/clutter-mutter.h
index 9c75ad6a2..6e1f43930 100644
--- a/clutter/clutter/clutter-mutter.h
+++ b/clutter/clutter/clutter-mutter.h
@@ -75,6 +75,12 @@ CLUTTER_EXPORT
gboolean clutter_seat_handle_event_post (ClutterSeat *seat,
const ClutterEvent *event);
+CLUTTER_EXPORT
+void clutter_stage_get_device_coords (ClutterStage *stage,
+ ClutterInputDevice *device,
+ ClutterEventSequence *sequence,
+ graphene_point_t *coords);
+
#undef __CLUTTER_H_INSIDE__
#endif /* __CLUTTER_MUTTER_H__ */
diff --git a/clutter/clutter/clutter-stage-private.h b/clutter/clutter/clutter-stage-private.h
index 47fef4395..8f7ff3135 100644
--- a/clutter/clutter/clutter-stage-private.h
+++ b/clutter/clutter/clutter-stage-private.h
@@ -128,6 +128,16 @@ GList * clutter_stage_get_views_for_rect (ClutterStage *stage,
void clutter_stage_set_actor_needs_immediate_relayout (ClutterStage *stage);
+void clutter_stage_update_device_entry (ClutterStage *self,
+ ClutterInputDevice *device,
+ ClutterEventSequence *sequence,
+ graphene_point_t coords,
+ ClutterActor *actor);
+
+void clutter_stage_remove_device_entry (ClutterStage *self,
+ 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 626193e2a..4222d76aa 100644
--- a/clutter/clutter/clutter-stage.c
+++ b/clutter/clutter/clutter-stage.c
@@ -98,6 +98,15 @@ typedef struct _PickClipRecord
graphene_point_t vertex[4];
} PickClipRecord;
+typedef struct _PointerDeviceEntry
+{
+ ClutterStage *stage;
+ ClutterInputDevice *device;
+ ClutterEventSequence *sequence;
+ graphene_point_t coords;
+ ClutterActor *current_actor;
+} PointerDeviceEntry;
+
struct _ClutterStagePrivate
{
/* the stage implementation */
@@ -126,6 +135,9 @@ struct _ClutterStagePrivate
gboolean needs_update_devices;
gboolean pending_finish_queue_redraws;
+ GHashTable *pointer_devices;
+ GHashTable *touch_sequences;
+
guint throttle_motion_events : 1;
guint min_size_changed : 1;
guint motion_events_enabled : 1;
@@ -165,6 +177,7 @@ static guint stage_signals[LAST_SIGNAL] = { 0, };
static const ClutterColor default_stage_color = { 255, 255, 255, 255 };
static void free_queue_redraw_entry (QueueRedrawEntry *entry);
+static void free_pointer_device_entry (PointerDeviceEntry *entry);
static void capture_view_into (ClutterStage *stage,
gboolean paint,
ClutterStageView *view,
@@ -1301,6 +1314,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->pointer_devices);
+ g_hash_table_destroy (priv->touch_sequences);
+
g_free (priv->title);
g_array_free (priv->paint_volume_stack, TRUE);
@@ -1596,6 +1612,13 @@ clutter_stage_init (ClutterStage *self)
priv->sync_delay = -1;
priv->motion_events_enabled = TRUE;
+ priv->pointer_devices =
+ g_hash_table_new_full (NULL, NULL,
+ NULL, (GDestroyNotify) free_pointer_device_entry);
+ priv->touch_sequences =
+ g_hash_table_new_full (NULL, NULL,
+ NULL, (GDestroyNotify) free_pointer_device_entry);
+
clutter_actor_set_background_color (CLUTTER_ACTOR (self),
&default_stage_color);
@@ -3392,3 +3415,182 @@ clutter_stage_set_actor_needs_immediate_relayout (ClutterStage *stage)
priv->actor_needs_immediate_relayout = TRUE;
}
+
+static void
+on_device_actor_reactive_changed (ClutterActor *actor,
+ GParamSpec *pspec,
+ PointerDeviceEntry *entry)
+{
+}
+
+static void
+on_device_actor_destroyed (ClutterActor *actor,
+ PointerDeviceEntry *entry)
+{
+ /* Simply unset the current_actor pointer here, there's no need to
+ * unset has_pointer or to disconnect any signals because the actor
+ * is gone anyway.
+ * Also, as soon as the next repaint happens, a repick should be triggered
+ * and the PointerDeviceEntry will get updated again, so no need to
+ * trigger a repick here.
+ */
+ entry->current_actor = NULL;
+}
+
+static void
+free_pointer_device_entry (PointerDeviceEntry *entry)
+{
+ if (entry->current_actor)
+ {
+ ClutterActor *actor = entry->current_actor;
+
+ g_signal_handlers_disconnect_by_func (actor,
+ G_CALLBACK (on_device_actor_reactive_changed),
+ entry);
+ g_signal_handlers_disconnect_by_func (actor,
+ G_CALLBACK (on_device_actor_destroyed),
+ entry);
+
+ _clutter_actor_set_has_pointer (actor, FALSE);
+ }
+
+ g_free (entry);
+}
+
+void
+clutter_stage_update_device_entry (ClutterStage *self,
+ ClutterInputDevice *device,
+ ClutterEventSequence *sequence,
+ graphene_point_t coords,
+ ClutterActor *actor)
+{
+ ClutterStagePrivate *priv = self->priv;
+ PointerDeviceEntry *entry = NULL;
+
+ g_assert (device != NULL);
+
+ if (sequence != NULL)
+ entry = g_hash_table_lookup (priv->touch_sequences, sequence);
+ else
+ entry = g_hash_table_lookup (priv->pointer_devices, device);
+
+ if (!entry)
+ {
+ entry = g_new0 (PointerDeviceEntry, 1);
+
+ if (sequence != NULL)
+ g_hash_table_insert (priv->touch_sequences, sequence, entry);
+ else
+ g_hash_table_insert (priv->pointer_devices, device, entry);
+
+ entry->stage = self;
+ entry->device = device;
+ entry->sequence = sequence;
+ }
+
+ entry->coords = coords;
+
+ if (entry->current_actor != actor)
+ {
+ if (entry->current_actor)
+ {
+ ClutterActor *old_actor = entry->current_actor;
+
+ g_signal_handlers_disconnect_by_func (old_actor,
+ G_CALLBACK (on_device_actor_reactive_changed),
+ entry);
+ g_signal_handlers_disconnect_by_func (old_actor,
+ G_CALLBACK (on_device_actor_destroyed),
+ entry);
+
+ _clutter_actor_set_has_pointer (old_actor, FALSE);
+ }
+
+ entry->current_actor = actor;
+
+ if (actor)
+ {
+ g_signal_connect (actor, "notify::reactive",
+ G_CALLBACK (on_device_actor_reactive_changed), entry);
+ g_signal_connect (actor, "destroy",
+ G_CALLBACK (on_device_actor_destroyed), entry);
+
+ _clutter_actor_set_has_pointer (actor, TRUE);
+ }
+ }
+}
+
+void
+clutter_stage_remove_device_entry (ClutterStage *self,
+ ClutterInputDevice *device,
+ ClutterEventSequence *sequence)
+{
+ ClutterStagePrivate *priv = self->priv;
+ gboolean removed;
+
+ g_assert (device != NULL);
+
+ if (sequence != NULL)
+ removed = g_hash_table_remove (priv->touch_sequences, sequence);
+ else
+ removed = g_hash_table_remove (priv->pointer_devices, device);
+
+ g_assert (removed);
+}
+
+/**
+ * clutter_stage_get_device_actor:
+ * @stage: a #ClutterStage
+ * @device: a #ClutterInputDevice
+ * @sequence: (allow-none): an optional #ClutterEventSequence
+ *
+ * Retrieves the #ClutterActor underneath the pointer or touch point
+ * 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;
+ PointerDeviceEntry *entry = NULL;
+
+ g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
+ g_return_val_if_fail (device != NULL, NULL);
+
+ if (sequence != NULL)
+ entry = g_hash_table_lookup (priv->touch_sequences, sequence);
+ else
+ entry = g_hash_table_lookup (priv->pointer_devices, device);
+
+ if (entry)
+ return entry->current_actor;
+
+ return NULL;
+}
+
+/**
+ * clutter_stage_get_device_coords: (skip):
+ */
+void
+clutter_stage_get_device_coords (ClutterStage *stage,
+ ClutterInputDevice *device,
+ ClutterEventSequence *sequence,
+ graphene_point_t *coords)
+{
+ ClutterStagePrivate *priv = stage->priv;
+ PointerDeviceEntry *entry = NULL;
+
+ g_return_if_fail (CLUTTER_IS_STAGE (stage));
+ g_return_if_fail (device != NULL);
+
+ if (sequence != NULL)
+ entry = g_hash_table_lookup (priv->touch_sequences, sequence);
+ else
+ entry = g_hash_table_lookup (priv->pointer_devices, device);
+
+ if (entry && coords)
+ *coords = entry->coords;
+}
diff --git a/clutter/clutter/clutter-stage.h b/clutter/clutter/clutter-stage.h
index 59a4ad145..a3b72b46c 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__ */