diff options
author | Jonas Dreßler <verdre@v0yd.nl> | 2020-10-15 16:39:00 +0200 |
---|---|---|
committer | Jonas Dreßler <verdre@v0yd.nl> | 2020-10-15 16:39:00 +0200 |
commit | 4f196afef9cba0561d7d531d248185c00a132cdc (patch) | |
tree | 98ff4d52b251de178d10a71d9e8d855ebb3ea11f | |
parent | f097e3d768738e69a6ec97c97cfa7880ae2a9d70 (diff) | |
download | mutter-4f196afef9cba0561d7d531d248185c00a132cdc.tar.gz |
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().
-rw-r--r-- | clutter/clutter/clutter-stage-private.h | 5 | ||||
-rw-r--r-- | clutter/clutter/clutter-stage.c | 146 | ||||
-rw-r--r-- | clutter/clutter/clutter-stage.h | 5 |
3 files changed, 156 insertions, 0 deletions
diff --git a/clutter/clutter/clutter-stage-private.h b/clutter/clutter/clutter-stage-private.h index ef5ce1da4..4860d5024 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 075e80914..9ee0dfdb6 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 7d94b68c3..bfacc715e 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__ */ |