clutter: Reuse GPtrArray for event emission
_clutter_actor_handle_event() currently allocates a new GPtrArray on the heap for every single event emission, let's avoid this by keeping an array around in ClutterStage and reusing that. This is moving the last few bits of event emission into ClutterStage, which will be useful when we introduce implicit grabbing in subsequent commits. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2342>
This commit is contained in:
parent
a62ae73478
commit
4358f8da7c
@ -246,10 +246,6 @@ void _clutter_actor_pop_clone_paint
|
|||||||
|
|
||||||
ClutterActorAlign _clutter_actor_get_effective_x_align (ClutterActor *self);
|
ClutterActorAlign _clutter_actor_get_effective_x_align (ClutterActor *self);
|
||||||
|
|
||||||
void _clutter_actor_handle_event (ClutterActor *actor,
|
|
||||||
ClutterActor *root,
|
|
||||||
const ClutterEvent *event);
|
|
||||||
|
|
||||||
void _clutter_actor_attach_clone (ClutterActor *actor,
|
void _clutter_actor_attach_clone (ClutterActor *actor,
|
||||||
ClutterActor *clone);
|
ClutterActor *clone);
|
||||||
void _clutter_actor_detach_clone (ClutterActor *actor,
|
void _clutter_actor_detach_clone (ClutterActor *actor,
|
||||||
@ -279,6 +275,10 @@ void clutter_actor_attach_grab (ClutterActor *actor,
|
|||||||
void clutter_actor_detach_grab (ClutterActor *actor,
|
void clutter_actor_detach_grab (ClutterActor *actor,
|
||||||
ClutterGrab *grab);
|
ClutterGrab *grab);
|
||||||
|
|
||||||
|
void clutter_actor_collect_event_actors (ClutterActor *self,
|
||||||
|
ClutterActor *deepmost,
|
||||||
|
GPtrArray *actors);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __CLUTTER_ACTOR_PRIVATE_H__ */
|
#endif /* __CLUTTER_ACTOR_PRIVATE_H__ */
|
||||||
|
@ -18527,68 +18527,6 @@ clutter_actor_get_color_state (ClutterActor *self)
|
|||||||
return self->priv->color_state;
|
return self->priv->color_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
_clutter_actor_handle_event (ClutterActor *self,
|
|
||||||
ClutterActor *root,
|
|
||||||
const ClutterEvent *event)
|
|
||||||
{
|
|
||||||
GPtrArray *event_tree;
|
|
||||||
ClutterActor *iter;
|
|
||||||
gboolean in_root = FALSE;
|
|
||||||
gint i = 0;
|
|
||||||
|
|
||||||
event_tree = g_ptr_array_sized_new (64);
|
|
||||||
g_ptr_array_set_free_func (event_tree, (GDestroyNotify) g_object_unref);
|
|
||||||
|
|
||||||
/* build the list of of emitters for the event */
|
|
||||||
iter = self;
|
|
||||||
while (iter != NULL)
|
|
||||||
{
|
|
||||||
ClutterActor *parent = iter->priv->parent;
|
|
||||||
|
|
||||||
if (CLUTTER_ACTOR_IS_REACTIVE (iter) || /* an actor must be reactive */
|
|
||||||
parent == NULL) /* unless it's the stage */
|
|
||||||
{
|
|
||||||
/* keep a reference on the actor, so that it remains valid
|
|
||||||
* for the duration of the signal emission
|
|
||||||
*/
|
|
||||||
g_ptr_array_add (event_tree, g_object_ref (iter));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iter == root)
|
|
||||||
{
|
|
||||||
in_root = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
iter = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The grab root conceptually extends infinitely in all
|
|
||||||
* directions, so it handles the events that fall outside of
|
|
||||||
* the actor.
|
|
||||||
*/
|
|
||||||
if (root && !in_root)
|
|
||||||
{
|
|
||||||
if (!clutter_actor_event (root, event, TRUE))
|
|
||||||
clutter_actor_event (root, event, FALSE);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Capture: from top-level downwards */
|
|
||||||
for (i = event_tree->len - 1; i >= 0; i--)
|
|
||||||
if (clutter_actor_event (g_ptr_array_index (event_tree, i), event, TRUE))
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
/* Bubble: from source upwards */
|
|
||||||
for (i = 0; i < event_tree->len; i++)
|
|
||||||
if (clutter_actor_event (g_ptr_array_index (event_tree, i), event, FALSE))
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
done:
|
|
||||||
g_ptr_array_free (event_tree, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clutter_actor_set_child_transform_internal (ClutterActor *self,
|
clutter_actor_set_child_transform_internal (ClutterActor *self,
|
||||||
const graphene_matrix_t *transform)
|
const graphene_matrix_t *transform)
|
||||||
@ -19218,3 +19156,42 @@ clutter_actor_detach_grab (ClutterActor *self,
|
|||||||
|
|
||||||
priv->grabs = g_list_remove (priv->grabs, grab);
|
priv->grabs = g_list_remove (priv->grabs, grab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
clutter_actor_collect_event_actors (ClutterActor *self,
|
||||||
|
ClutterActor *deepmost,
|
||||||
|
GPtrArray *actors)
|
||||||
|
{
|
||||||
|
ClutterActor *iter;
|
||||||
|
gboolean in_root = FALSE;
|
||||||
|
|
||||||
|
g_assert (actors->len == 0);
|
||||||
|
|
||||||
|
iter = deepmost;
|
||||||
|
while (iter != NULL)
|
||||||
|
{
|
||||||
|
ClutterActor *parent = iter->priv->parent;
|
||||||
|
|
||||||
|
if (CLUTTER_ACTOR_IS_REACTIVE (iter) || /* an actor must be reactive */
|
||||||
|
parent == NULL) /* unless it's the stage */
|
||||||
|
g_ptr_array_add (actors, g_object_ref (iter));
|
||||||
|
|
||||||
|
if (iter == self)
|
||||||
|
{
|
||||||
|
in_root = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The grab root conceptually extends infinitely in all
|
||||||
|
* directions, so it handles the events that fall outside of
|
||||||
|
* the actor.
|
||||||
|
*/
|
||||||
|
if (!in_root)
|
||||||
|
{
|
||||||
|
g_ptr_array_remove_range (actors, 0, actors->len);
|
||||||
|
g_ptr_array_add (actors, g_object_ref (self));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -121,6 +121,7 @@ struct _ClutterStagePrivate
|
|||||||
ClutterGrabState grab_state;
|
ClutterGrabState grab_state;
|
||||||
|
|
||||||
GQueue *event_queue;
|
GQueue *event_queue;
|
||||||
|
GPtrArray *cur_event_actors;
|
||||||
|
|
||||||
GArray *paint_volume_stack;
|
GArray *paint_volume_stack;
|
||||||
|
|
||||||
@ -1222,6 +1223,9 @@ clutter_stage_finalize (GObject *object)
|
|||||||
g_queue_foreach (priv->event_queue, (GFunc) clutter_event_free, NULL);
|
g_queue_foreach (priv->event_queue, (GFunc) clutter_event_free, NULL);
|
||||||
g_queue_free (priv->event_queue);
|
g_queue_free (priv->event_queue);
|
||||||
|
|
||||||
|
g_assert (priv->cur_event_actors->len == 0);
|
||||||
|
g_ptr_array_free (priv->cur_event_actors, TRUE);
|
||||||
|
|
||||||
g_hash_table_destroy (priv->pointer_devices);
|
g_hash_table_destroy (priv->pointer_devices);
|
||||||
g_hash_table_destroy (priv->touch_sequences);
|
g_hash_table_destroy (priv->touch_sequences);
|
||||||
|
|
||||||
@ -1574,6 +1578,9 @@ clutter_stage_init (ClutterStage *self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
priv->event_queue = g_queue_new ();
|
priv->event_queue = g_queue_new ();
|
||||||
|
priv->cur_event_actors = g_ptr_array_sized_new (32);
|
||||||
|
g_ptr_array_set_free_func (priv->cur_event_actors,
|
||||||
|
(GDestroyNotify) g_object_unref);
|
||||||
|
|
||||||
priv->pointer_devices =
|
priv->pointer_devices =
|
||||||
g_hash_table_new_full (NULL, NULL,
|
g_hash_table_new_full (NULL, NULL,
|
||||||
@ -3413,13 +3420,74 @@ create_crossing_event (ClutterStage *stage,
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
EVENT_NOT_HANDLED,
|
||||||
|
EVENT_HANDLED_BY_ACTOR
|
||||||
|
} EventHandledState;
|
||||||
|
|
||||||
|
static EventHandledState
|
||||||
|
emit_event (const ClutterEvent *event,
|
||||||
|
GPtrArray *actors)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Capture: from top-level downwards */
|
||||||
|
for (i = actors->len - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
ClutterActor *actor = g_ptr_array_index (actors, i);
|
||||||
|
|
||||||
|
if (clutter_actor_event (actor, event, TRUE))
|
||||||
|
return EVENT_HANDLED_BY_ACTOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bubble: from source upwards */
|
||||||
|
for (i = 0; i < actors->len; i++)
|
||||||
|
{
|
||||||
|
ClutterActor *actor = g_ptr_array_index (actors, i);
|
||||||
|
|
||||||
|
if (clutter_actor_event (actor, event, FALSE))
|
||||||
|
return EVENT_HANDLED_BY_ACTOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EVENT_NOT_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clutter_stage_emit_crossing_event (ClutterStage *self,
|
clutter_stage_emit_crossing_event (ClutterStage *self,
|
||||||
const ClutterEvent *event,
|
const ClutterEvent *event,
|
||||||
ClutterActor *deepmost,
|
ClutterActor *deepmost,
|
||||||
ClutterActor *topmost)
|
ClutterActor *topmost)
|
||||||
{
|
{
|
||||||
_clutter_actor_handle_event (deepmost, topmost, event);
|
ClutterStagePrivate *priv = self->priv;
|
||||||
|
gboolean in_event_emission;
|
||||||
|
GPtrArray *event_actors;
|
||||||
|
|
||||||
|
if (topmost == NULL)
|
||||||
|
topmost = CLUTTER_ACTOR (self);
|
||||||
|
|
||||||
|
/* Crossings can happen while we're in the middle of event emission
|
||||||
|
* (for example when an actor goes unmapped or gets grabbed), so we
|
||||||
|
* can't reuse our priv->cur_event_actors here, it might already be in use.
|
||||||
|
*/
|
||||||
|
in_event_emission = priv->cur_event_actors->len != 0;
|
||||||
|
|
||||||
|
if (in_event_emission)
|
||||||
|
{
|
||||||
|
event_actors = g_ptr_array_sized_new (32);
|
||||||
|
g_ptr_array_set_free_func (event_actors, g_object_unref);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
event_actors = g_ptr_array_ref (priv->cur_event_actors);
|
||||||
|
}
|
||||||
|
|
||||||
|
clutter_actor_collect_event_actors (topmost, deepmost, event_actors);
|
||||||
|
|
||||||
|
emit_event (event, event_actors);
|
||||||
|
|
||||||
|
g_ptr_array_remove_range (event_actors, 0, event_actors->len);
|
||||||
|
g_ptr_array_unref (event_actors);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -4028,7 +4096,7 @@ clutter_stage_emit_event (ClutterStage *self,
|
|||||||
ClutterInputDevice *device = clutter_event_get_device (event);
|
ClutterInputDevice *device = clutter_event_get_device (event);
|
||||||
ClutterEventSequence *sequence = clutter_event_get_event_sequence (event);
|
ClutterEventSequence *sequence = clutter_event_get_event_sequence (event);
|
||||||
PointerDeviceEntry *entry;
|
PointerDeviceEntry *entry;
|
||||||
ClutterActor *target_actor = NULL;
|
ClutterActor *target_actor = NULL, *seat_grab_actor = NULL;
|
||||||
|
|
||||||
if (sequence != NULL)
|
if (sequence != NULL)
|
||||||
entry = g_hash_table_lookup (priv->touch_sequences, sequence);
|
entry = g_hash_table_lookup (priv->touch_sequences, sequence);
|
||||||
@ -4094,8 +4162,12 @@ clutter_stage_emit_event (ClutterStage *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_assert (target_actor != NULL);
|
g_assert (target_actor != NULL);
|
||||||
|
seat_grab_actor = priv->topmost_grab ? priv->topmost_grab->actor : CLUTTER_ACTOR (self);
|
||||||
|
|
||||||
_clutter_actor_handle_event (target_actor,
|
clutter_actor_collect_event_actors (seat_grab_actor, target_actor, priv->cur_event_actors);
|
||||||
clutter_stage_get_grab_actor (self),
|
|
||||||
event);
|
emit_event (event, priv->cur_event_actors);
|
||||||
|
|
||||||
|
g_ptr_array_remove_range (priv->cur_event_actors, 0,
|
||||||
|
priv->cur_event_actors->len);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user