actor: Move event chain emission into ClutterActor

By moving the function that builds the event emission chain we can avoid
a bunch of checks and function calls.
This commit is contained in:
Emmanuele Bassi 2012-06-24 09:58:12 +01:00
parent 67cbb56ab8
commit 9b7287e897
3 changed files with 84 additions and 56 deletions

View File

@ -298,6 +298,9 @@ void _clutter_actor_shader_post_paint (ClutterActor *actor);
ClutterActorAlign _clutter_actor_get_effective_x_align (ClutterActor *self);
void _clutter_actor_handle_event (ClutterActor *actor,
const ClutterEvent *event);
G_END_DECLS
#endif /* __CLUTTER_ACTOR_PRIVATE_H__ */

View File

@ -18913,3 +18913,55 @@ clutter_actor_get_content_repeat (ClutterActor *self)
return self->priv->content_repeat;
}
void
_clutter_actor_handle_event (ClutterActor *self,
const ClutterEvent *event)
{
GPtrArray *event_tree;
ClutterActor *iter;
gboolean is_key_event;
gint i = 0;
/* XXX - for historical reasons that are now lost in the mists of time,
* key events are delivered regardless of whether an actor is set as
* reactive; this should be changed for 2.0.
*/
is_key_event = event->type == CLUTTER_KEY_PRESS ||
event->type == CLUTTER_KEY_RELEASE;
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 */
is_key_event) /* or this is a key event */
{
/* 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));
}
iter = parent;
}
/* 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);
}

View File

@ -97,7 +97,7 @@
#include <glib/gi18n-lib.h>
#include <locale.h>
#include "clutter-actor.h"
#include "clutter-actor-private.h"
#include "clutter-backend-private.h"
#include "clutter-config.h"
#include "clutter-debug.h"
@ -2241,15 +2241,10 @@ event_click_count_generate (ClutterEvent *event)
}
static inline void
emit_event (ClutterEvent *event,
gboolean is_key_event)
emit_event_chain (ClutterEvent *event)
{
static gboolean lock = FALSE;
GPtrArray *event_tree = NULL;
ClutterActor *actor;
gint i = 0;
if (event->any.source == NULL)
{
CLUTTER_NOTE (EVENT, "No source set, discarding event");
@ -2265,42 +2260,7 @@ emit_event (ClutterEvent *event,
lock = TRUE;
event_tree = g_ptr_array_sized_new (64);
actor = event->any.source;
/* Build 'tree' of emitters for the event */
while (actor)
{
ClutterActor *parent;
parent = clutter_actor_get_parent (actor);
if (clutter_actor_get_reactive (actor) ||
parent == NULL || /* stage gets all events */
is_key_event) /* keyboard events are always emitted */
{
g_ptr_array_add (event_tree, g_object_ref (actor));
}
actor = parent;
}
/* Capture */
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 */
for (i = 0; i < event_tree->len; i++)
if (clutter_actor_event (g_ptr_array_index (event_tree, i), event, FALSE))
goto done;
done:
for (i = 0; i < event_tree->len; i++)
g_object_unref (g_ptr_array_index (event_tree, i));
g_ptr_array_free (event_tree, TRUE);
_clutter_actor_handle_event (event->any.source, event);
lock = FALSE;
}
@ -2320,7 +2280,7 @@ emit_pointer_event (ClutterEvent *event,
(device == NULL || device->pointer_grab_actor == NULL))
{
/* no grab, time to capture and bubble */
emit_event (event, FALSE);
emit_event_chain (event);
}
else
{
@ -2341,19 +2301,23 @@ static inline void
emit_touch_event (ClutterEvent *event,
ClutterInputDevice *device)
{
ClutterActor *grab_actor;
ClutterActor *grab_actor = NULL;
if ((device->sequence_grab_actors != NULL) &&
((grab_actor = g_hash_table_lookup (device->sequence_grab_actors,
event->touch.sequence)) != NULL))
if (device->sequence_grab_actors != NULL)
{
/* sequence grab */
grab_actor = g_hash_table_lookup (device->sequence_grab_actors,
event->touch.sequence);
}
if (grab_actor != NULL)
{
/* per-device sequence grab */
clutter_actor_event (grab_actor, event, FALSE);
}
else
{
/* no grab, time to capture and bubble */
emit_event (event, FALSE);
emit_event_chain (event);
}
}
@ -2366,16 +2330,19 @@ emit_keyboard_event (ClutterEvent *event,
if (context->keyboard_grab_actor == NULL &&
(device == NULL || device->keyboard_grab_actor == NULL))
{
emit_event (event, TRUE);
/* no grab, time to capture and bubble */
emit_event_chain (event);
}
else
{
if (context->keyboard_grab_actor != NULL)
{
/* global key grab */
clutter_actor_event (context->keyboard_grab_actor, event, FALSE);
}
else if (device != NULL && device->keyboard_grab_actor != NULL)
{
/* per-device key grab */
clutter_actor_event (context->keyboard_grab_actor, event, FALSE);
}
}
@ -2725,14 +2692,20 @@ _clutter_process_event (ClutterEvent *event)
stage = CLUTTER_ACTOR (event->any.stage);
if (stage == NULL)
{
CLUTTER_NOTE (EVENT, "Discarding event withou a stage set");
return;
}
CLUTTER_NOTE (EVENT, "Event received");
/* keep a pointer to the event and time, so that we don't need to
* add an event parameter to all signals that can be emitted within
* an event chain
*/
context->last_event_time = clutter_event_get_time (event);
context->current_event = event;
_clutter_process_event_details (stage, context, event);
context->current_event = NULL;
}