mirror of
https://github.com/brl/mutter.git
synced 2024-12-23 03:22:04 +00:00
2007-10-10 Matthew Allum <mallum@openedhand.com>
* clutter/clutter-actor.c: * clutter/clutter-actor.h: * clutter/clutter-event.c: * clutter/clutter-main.c: * tests/test-events.c: Add basic W3 DOM event 'capture' like functionality.
This commit is contained in:
parent
a4b7abd18e
commit
6216ce659c
@ -1,3 +1,12 @@
|
|||||||
|
2007-10-10 Matthew Allum <mallum@openedhand.com>
|
||||||
|
|
||||||
|
* clutter/clutter-actor.c:
|
||||||
|
* clutter/clutter-actor.h:
|
||||||
|
* clutter/clutter-event.c:
|
||||||
|
* clutter/clutter-main.c:
|
||||||
|
* tests/test-events.c:
|
||||||
|
Add basic W3 DOM event 'capture' like functionality.
|
||||||
|
|
||||||
2007-10-10 Emmanuele Bassi <ebassi@openedhand.com>
|
2007-10-10 Emmanuele Bassi <ebassi@openedhand.com>
|
||||||
|
|
||||||
* clutter/clutter-script-private.h:
|
* clutter/clutter-script-private.h:
|
||||||
|
@ -106,6 +106,7 @@ enum
|
|||||||
PARENT_SET,
|
PARENT_SET,
|
||||||
|
|
||||||
EVENT,
|
EVENT,
|
||||||
|
EVENT_CAPTURED,
|
||||||
EVENT_AFTER,
|
EVENT_AFTER,
|
||||||
BUTTON_PRESS_EVENT,
|
BUTTON_PRESS_EVENT,
|
||||||
BUTTON_RELEASE_EVENT,
|
BUTTON_RELEASE_EVENT,
|
||||||
@ -117,7 +118,6 @@ enum
|
|||||||
FOCUS_OUT,
|
FOCUS_OUT,
|
||||||
ENTER_EVENT,
|
ENTER_EVENT,
|
||||||
LEAVE_EVENT,
|
LEAVE_EVENT,
|
||||||
|
|
||||||
LAST_SIGNAL
|
LAST_SIGNAL
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1469,9 +1469,10 @@ clutter_actor_class_init (ClutterActorClass *klass)
|
|||||||
G_TYPE_FROM_CLASS (object_class),
|
G_TYPE_FROM_CLASS (object_class),
|
||||||
G_SIGNAL_RUN_LAST,
|
G_SIGNAL_RUN_LAST,
|
||||||
G_STRUCT_OFFSET (ClutterActorClass, enter),
|
G_STRUCT_OFFSET (ClutterActorClass, enter),
|
||||||
NULL, NULL,
|
_clutter_boolean_handled_accumulator, NULL,
|
||||||
clutter_marshal_VOID__VOID,
|
clutter_marshal_BOOLEAN__BOXED,
|
||||||
G_TYPE_NONE, 0);
|
G_TYPE_BOOLEAN, 1,
|
||||||
|
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ClutterActor::leave:
|
* ClutterActor::leave:
|
||||||
@ -1486,10 +1487,28 @@ clutter_actor_class_init (ClutterActorClass *klass)
|
|||||||
G_TYPE_FROM_CLASS (object_class),
|
G_TYPE_FROM_CLASS (object_class),
|
||||||
G_SIGNAL_RUN_LAST,
|
G_SIGNAL_RUN_LAST,
|
||||||
G_STRUCT_OFFSET (ClutterActorClass, leave),
|
G_STRUCT_OFFSET (ClutterActorClass, leave),
|
||||||
NULL, NULL,
|
_clutter_boolean_handled_accumulator, NULL,
|
||||||
clutter_marshal_VOID__VOID,
|
clutter_marshal_BOOLEAN__BOXED,
|
||||||
G_TYPE_NONE, 0);
|
G_TYPE_BOOLEAN, 1,
|
||||||
|
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClutterActor::captured-event:
|
||||||
|
* @actor: the actor which the pointer has left
|
||||||
|
*
|
||||||
|
* The ::leave signal is emitted when the pointer leaves the @actor.
|
||||||
|
*
|
||||||
|
* Since: 0.6
|
||||||
|
*/
|
||||||
|
actor_signals[EVENT_CAPTURED] =
|
||||||
|
g_signal_new ("captured-event",
|
||||||
|
G_TYPE_FROM_CLASS (object_class),
|
||||||
|
G_SIGNAL_RUN_LAST,
|
||||||
|
G_STRUCT_OFFSET (ClutterActorClass, captured),
|
||||||
|
_clutter_boolean_handled_accumulator, NULL,
|
||||||
|
clutter_marshal_BOOLEAN__BOXED,
|
||||||
|
G_TYPE_BOOLEAN, 1,
|
||||||
|
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
|
||||||
|
|
||||||
klass->show = clutter_actor_real_show;
|
klass->show = clutter_actor_real_show;
|
||||||
klass->show_all = clutter_actor_show;
|
klass->show_all = clutter_actor_show;
|
||||||
@ -2977,6 +2996,7 @@ clutter_actor_lower_bottom (ClutterActor *self)
|
|||||||
* clutter_actor_event:
|
* clutter_actor_event:
|
||||||
* @actor: a #ClutterActor
|
* @actor: a #ClutterActor
|
||||||
* @event: a #ClutterEvent
|
* @event: a #ClutterEvent
|
||||||
|
* @capture: TRUE if event in in capture phase, FALSE otherwise.
|
||||||
*
|
*
|
||||||
* This function is used to emit an event on the main stage.
|
* This function is used to emit an event on the main stage.
|
||||||
* You should rarely need to use this function, except for
|
* You should rarely need to use this function, except for
|
||||||
@ -2988,7 +3008,8 @@ clutter_actor_lower_bottom (ClutterActor *self)
|
|||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
clutter_actor_event (ClutterActor *actor,
|
clutter_actor_event (ClutterActor *actor,
|
||||||
ClutterEvent *event)
|
ClutterEvent *event,
|
||||||
|
gboolean capture)
|
||||||
{
|
{
|
||||||
gboolean retval = TRUE;
|
gboolean retval = TRUE;
|
||||||
gint signal_num = -1;
|
gint signal_num = -1;
|
||||||
@ -2998,6 +3019,13 @@ clutter_actor_event (ClutterActor *actor,
|
|||||||
|
|
||||||
g_object_ref (actor);
|
g_object_ref (actor);
|
||||||
|
|
||||||
|
if (capture)
|
||||||
|
{
|
||||||
|
g_signal_emit (actor, actor_signals[EVENT_CAPTURED], 0,
|
||||||
|
event, &retval);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
|
g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
|
||||||
|
|
||||||
if (!retval)
|
if (!retval)
|
||||||
@ -3037,12 +3065,18 @@ clutter_actor_event (ClutterActor *actor,
|
|||||||
signal_num = -1;
|
signal_num = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signal_num != -1)
|
if (signal_num != -1)
|
||||||
g_signal_emit (actor, actor_signals[signal_num], 0, event, &retval);
|
g_signal_emit (actor, actor_signals[signal_num], 0,
|
||||||
|
event, &retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!retval)
|
||||||
g_signal_emit (actor, actor_signals[EVENT_AFTER], 0, event);
|
g_signal_emit (actor, actor_signals[EVENT_AFTER], 0, event);
|
||||||
|
|
||||||
|
out:
|
||||||
|
|
||||||
g_object_unref (actor);
|
g_object_unref (actor);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -211,6 +211,8 @@ struct _ClutterActorClass
|
|||||||
ClutterCrossingEvent *event);
|
ClutterCrossingEvent *event);
|
||||||
void (* leave) (ClutterActor *actor,
|
void (* leave) (ClutterActor *actor,
|
||||||
ClutterCrossingEvent *event);
|
ClutterCrossingEvent *event);
|
||||||
|
void (* captured) (ClutterActor *actor,
|
||||||
|
ClutterEvent *event);
|
||||||
void (* focus_in) (ClutterActor *actor);
|
void (* focus_in) (ClutterActor *actor);
|
||||||
void (* focus_out) (ClutterActor *actor);
|
void (* focus_out) (ClutterActor *actor);
|
||||||
|
|
||||||
@ -367,7 +369,8 @@ void clutter_actor_apply_transform_to_point (ClutterActor
|
|||||||
/* Per actor event handling - may change */
|
/* Per actor event handling - may change */
|
||||||
gboolean
|
gboolean
|
||||||
clutter_actor_event (ClutterActor *actor,
|
clutter_actor_event (ClutterActor *actor,
|
||||||
ClutterEvent *event);
|
ClutterEvent *event,
|
||||||
|
gboolean capture);
|
||||||
void
|
void
|
||||||
clutter_actor_set_reactive (ClutterActor *actor);
|
clutter_actor_set_reactive (ClutterActor *actor);
|
||||||
|
|
||||||
|
@ -379,10 +379,8 @@ clutter_event_free (ClutterEvent *event)
|
|||||||
if (G_LIKELY (event))
|
if (G_LIKELY (event))
|
||||||
{
|
{
|
||||||
ClutterActor *source = NULL;
|
ClutterActor *source = NULL;
|
||||||
|
if (event->type == CLUTTER_LEAVE || event->type == CLUTTER_ENTER)
|
||||||
source = clutter_event_get_source (event);
|
g_object_unref (event->crossing.related);
|
||||||
if (source)
|
|
||||||
g_object_unref (source);
|
|
||||||
g_slice_free (ClutterEvent, event);
|
g_slice_free (ClutterEvent, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1133,6 +1133,56 @@ event_click_count_generate (ClutterEvent *event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
deliver_event (ClutterEvent *event, ClutterActor *source)
|
||||||
|
{
|
||||||
|
#define MAX_EVENT_DEPTH 512
|
||||||
|
|
||||||
|
static ClutterActor **event_tree = NULL;
|
||||||
|
static gboolean lock = FALSE;
|
||||||
|
|
||||||
|
ClutterActor *actor;
|
||||||
|
gint i = 0, n_tree_events = 0;
|
||||||
|
|
||||||
|
g_return_if_fail (source != NULL);
|
||||||
|
g_return_if_fail (lock == FALSE);
|
||||||
|
|
||||||
|
lock = TRUE; /* Guard against reentrancy */
|
||||||
|
|
||||||
|
/* Sorry Mr Bassi. */
|
||||||
|
if (event_tree == NULL)
|
||||||
|
event_tree = g_new0(ClutterActor*, MAX_EVENT_DEPTH);
|
||||||
|
|
||||||
|
actor = source;
|
||||||
|
|
||||||
|
/* Build 'tree' of events */
|
||||||
|
while (actor && n_tree_events < MAX_EVENT_DEPTH)
|
||||||
|
{
|
||||||
|
if (clutter_actor_is_reactive (actor) ||
|
||||||
|
clutter_actor_get_parent (actor) == NULL)
|
||||||
|
event_tree[n_tree_events++] = g_object_ref (actor);
|
||||||
|
|
||||||
|
actor = clutter_actor_get_parent (actor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Capture */
|
||||||
|
for (i=n_tree_events-1; i >= 0; i--)
|
||||||
|
if (clutter_actor_event (event_tree[i], event, TRUE))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* Bubble */
|
||||||
|
for (i=0; i < n_tree_events; i++)
|
||||||
|
if (clutter_actor_event (event_tree[i], event, FALSE))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
done:
|
||||||
|
|
||||||
|
for (i=0; i < n_tree_events; i++)
|
||||||
|
g_object_unref (event_tree[i]);
|
||||||
|
|
||||||
|
lock = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clutter_do_event
|
* clutter_do_event
|
||||||
* @event: a #ClutterEvent.
|
* @event: a #ClutterEvent.
|
||||||
@ -1151,6 +1201,7 @@ clutter_do_event (ClutterEvent *event)
|
|||||||
ClutterMainContext *context;
|
ClutterMainContext *context;
|
||||||
ClutterBackend *backend;
|
ClutterBackend *backend;
|
||||||
ClutterActor *stage;
|
ClutterActor *stage;
|
||||||
|
|
||||||
static ClutterActor *motion_last_actor = NULL;
|
static ClutterActor *motion_last_actor = NULL;
|
||||||
|
|
||||||
context = clutter_context_get_default ();
|
context = clutter_context_get_default ();
|
||||||
@ -1175,18 +1226,7 @@ clutter_do_event (ClutterEvent *event)
|
|||||||
|
|
||||||
g_return_if_fail (actor != NULL);
|
g_return_if_fail (actor != NULL);
|
||||||
|
|
||||||
while (actor)
|
deliver_event (event, actor);
|
||||||
{
|
|
||||||
if (clutter_actor_is_reactive (actor) ||
|
|
||||||
clutter_actor_get_parent (actor) == NULL /* STAGE */ )
|
|
||||||
{
|
|
||||||
CLUTTER_NOTE (EVENT, "forwarding event to reactive actor");
|
|
||||||
if (clutter_actor_event (actor, event))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
actor = clutter_actor_get_parent (actor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CLUTTER_DESTROY_NOTIFY:
|
case CLUTTER_DESTROY_NOTIFY:
|
||||||
@ -1203,25 +1243,16 @@ clutter_do_event (ClutterEvent *event)
|
|||||||
|
|
||||||
g_return_if_fail (actor != NULL);
|
g_return_if_fail (actor != NULL);
|
||||||
|
|
||||||
event->key.source = g_object_ref (actor);
|
event->key.source = actor;
|
||||||
|
deliver_event (event, actor);
|
||||||
/* bubble up */
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (clutter_actor_event (actor, event))
|
|
||||||
break;
|
|
||||||
|
|
||||||
actor = clutter_actor_get_parent (actor);
|
|
||||||
}
|
|
||||||
while (actor != NULL);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CLUTTER_MOTION:
|
case CLUTTER_MOTION:
|
||||||
if (context->motion_events_per_actor == FALSE)
|
if (context->motion_events_per_actor == FALSE)
|
||||||
{
|
{
|
||||||
/* Only stage gets motion events */
|
/* Only stage gets motion events */
|
||||||
event->motion.source = g_object_ref (stage);
|
event->motion.source = stage;
|
||||||
clutter_actor_event (stage, event);
|
clutter_actor_event (stage, event, FALSE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CLUTTER_BUTTON_PRESS:
|
case CLUTTER_BUTTON_PRESS:
|
||||||
@ -1246,15 +1277,20 @@ clutter_do_event (ClutterEvent *event)
|
|||||||
x, y,
|
x, y,
|
||||||
CLUTTER_PICK_REACTIVE);
|
CLUTTER_PICK_REACTIVE);
|
||||||
|
|
||||||
|
/* FIXME: for an optimisation should check if there are
|
||||||
|
* actually any reactive actors and avoid the pick all togeather
|
||||||
|
* (signalling just the stage). Should be big help for gles.
|
||||||
|
*/
|
||||||
|
|
||||||
CLUTTER_NOTE (EVENT, "Reactive event received at %i, %i - actor: %p",
|
CLUTTER_NOTE (EVENT, "Reactive event received at %i, %i - actor: %p",
|
||||||
x, y, actor);
|
x, y, actor);
|
||||||
|
|
||||||
g_return_if_fail (actor != NULL);
|
g_return_if_fail (actor != NULL);
|
||||||
|
|
||||||
if (event->type == CLUTTER_SCROLL)
|
if (event->type == CLUTTER_SCROLL)
|
||||||
event->scroll.source = g_object_ref (actor);
|
event->scroll.source = actor;
|
||||||
else
|
else
|
||||||
event->button.source = g_object_ref (actor);
|
event->button.source = actor;
|
||||||
|
|
||||||
/* Motion enter leave events */
|
/* Motion enter leave events */
|
||||||
if (event->type == CLUTTER_MOTION)
|
if (event->type == CLUTTER_MOTION)
|
||||||
@ -1270,7 +1306,8 @@ clutter_do_event (ClutterEvent *event)
|
|||||||
cev.crossing.flags = 0;
|
cev.crossing.flags = 0;
|
||||||
cev.crossing.x = x;
|
cev.crossing.x = x;
|
||||||
cev.crossing.y = y;
|
cev.crossing.y = y;
|
||||||
cev.crossing.source = g_object_ref (motion_last_actor);
|
cev.crossing.source = motion_last_actor;
|
||||||
|
/* unref in free */
|
||||||
cev.crossing.related = g_object_ref (actor);
|
cev.crossing.related = g_object_ref (actor);
|
||||||
|
|
||||||
clutter_event_put (&cev); /* copys */
|
clutter_event_put (&cev); /* copys */
|
||||||
@ -1280,7 +1317,7 @@ clutter_do_event (ClutterEvent *event)
|
|||||||
cev.crossing.flags = 0;
|
cev.crossing.flags = 0;
|
||||||
cev.crossing.x = x;
|
cev.crossing.x = x;
|
||||||
cev.crossing.y = y;
|
cev.crossing.y = y;
|
||||||
cev.crossing.source = g_object_ref (actor);
|
cev.crossing.source = actor;
|
||||||
cev.crossing.related = g_object_ref (motion_last_actor);
|
cev.crossing.related = g_object_ref (motion_last_actor);
|
||||||
|
|
||||||
clutter_event_put (&cev);
|
clutter_event_put (&cev);
|
||||||
@ -1291,27 +1328,7 @@ clutter_do_event (ClutterEvent *event)
|
|||||||
else
|
else
|
||||||
event_click_count_generate (event);
|
event_click_count_generate (event);
|
||||||
|
|
||||||
/* Send the event to the actor and all parents always the
|
deliver_event (event, actor);
|
||||||
* stage.
|
|
||||||
*
|
|
||||||
* FIXME: for an optimisation should check if there are
|
|
||||||
* actually any reactive actors and avoid the pick all togeather
|
|
||||||
* (signalling just the stage). Should be big help for gles.
|
|
||||||
*
|
|
||||||
* FIXME: Actors be able to stop emission.
|
|
||||||
*/
|
|
||||||
while (actor)
|
|
||||||
{
|
|
||||||
if (clutter_actor_is_reactive (actor) ||
|
|
||||||
clutter_actor_get_parent (actor) == NULL /* STAGE */ )
|
|
||||||
{
|
|
||||||
CLUTTER_NOTE (EVENT, "forwarding event to reactive actor");
|
|
||||||
if (clutter_actor_event (actor, event))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
actor = clutter_actor_get_parent (actor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CLUTTER_STAGE_STATE:
|
case CLUTTER_STAGE_STATE:
|
||||||
|
@ -828,7 +828,7 @@ clutter_stage_event (ClutterStage *stage,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* emit raw event */
|
/* emit raw event */
|
||||||
if (clutter_actor_event (CLUTTER_ACTOR (stage), event))
|
if (clutter_actor_event (CLUTTER_ACTOR (stage), event, FALSE))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
if (event->stage_state.changed_mask & CLUTTER_STAGE_STATE_FULLSCREEN)
|
if (event->stage_state.changed_mask & CLUTTER_STAGE_STATE_FULLSCREEN)
|
||||||
|
@ -42,6 +42,18 @@ red_button_cb (ClutterActor *actor,
|
|||||||
IsMotion = TRUE;
|
IsMotion = TRUE;
|
||||||
|
|
||||||
clutter_enable_motion_events (IsMotion);
|
clutter_enable_motion_events (IsMotion);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
capture_cb (ClutterActor *actor,
|
||||||
|
ClutterEvent *event,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
printf("captured event for type '%s'\n", G_OBJECT_TYPE_NAME(actor));
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -152,6 +164,7 @@ main (int argc, char *argv[])
|
|||||||
|
|
||||||
stage = clutter_stage_get_default ();
|
stage = clutter_stage_get_default ();
|
||||||
g_signal_connect (stage, "event", G_CALLBACK (input_cb), "stage");
|
g_signal_connect (stage, "event", G_CALLBACK (input_cb), "stage");
|
||||||
|
|
||||||
g_signal_connect (stage, "fullscreen",
|
g_signal_connect (stage, "fullscreen",
|
||||||
G_CALLBACK (stage_state_cb), "fullscreen");
|
G_CALLBACK (stage_state_cb), "fullscreen");
|
||||||
g_signal_connect (stage, "unfullscreen",
|
g_signal_connect (stage, "unfullscreen",
|
||||||
@ -161,6 +174,8 @@ main (int argc, char *argv[])
|
|||||||
g_signal_connect (stage, "deactivate",
|
g_signal_connect (stage, "deactivate",
|
||||||
G_CALLBACK (stage_state_cb), "deactivate");
|
G_CALLBACK (stage_state_cb), "deactivate");
|
||||||
|
|
||||||
|
g_signal_connect (stage, "captured-event", G_CALLBACK (capture_cb), NULL);
|
||||||
|
|
||||||
focus_box = clutter_rectangle_new_with_color (&ncol);
|
focus_box = clutter_rectangle_new_with_color (&ncol);
|
||||||
clutter_container_add (CLUTTER_CONTAINER(stage), focus_box, NULL);
|
clutter_container_add (CLUTTER_CONTAINER(stage), focus_box, NULL);
|
||||||
|
|
||||||
@ -193,6 +208,8 @@ main (int argc, char *argv[])
|
|||||||
g_signal_connect (actor, "focus-in", G_CALLBACK (key_focus_in_cb),
|
g_signal_connect (actor, "focus-in", G_CALLBACK (key_focus_in_cb),
|
||||||
focus_box);
|
focus_box);
|
||||||
|
|
||||||
|
g_signal_connect (actor, "captured-event", G_CALLBACK (capture_cb), NULL);
|
||||||
|
|
||||||
actor = clutter_rectangle_new_with_color (&bcol);
|
actor = clutter_rectangle_new_with_color (&bcol);
|
||||||
clutter_actor_set_size (actor, 100, 100);
|
clutter_actor_set_size (actor, 100, 100);
|
||||||
clutter_actor_set_position (actor, 400, 100);
|
clutter_actor_set_position (actor, 400, 100);
|
||||||
|
Loading…
Reference in New Issue
Block a user