2007-10-01 Emmanuele Bassi <ebassi@openedhand.com>

* clutter/clutter-actor.[ch]: Remove the ::event-after signal
	class handler, as it's not meant to be overridden by sub-classes.

	(clutter_actor_class_init):
	Make every event-related signal return a boolean: return TRUE
	in a signal handler to block the emission. The value is accumulated
	automatically by the signal API.

	(clutter_actor_event): If ::event returns TRUE, skip to emitting
	::event-after. Return the value accumulated by the signal emission
	chain.

	* clutter/clutter-private.h: Rename _clutter_boolean_accumlator().

	* clutter/clutter-main.c (clutter_do_event): If clutter_actor_event()
	returns TRUE then stop the event emission chain from child to parent.

	* clutter/clutter-stage.c (clutter_stage_event): Behave like
	clutter_actor_event().

	(clutter_stage_get_key_focus),
	(clutter_stage_set_key_focus): Avoid a nasty circular reference
	issue: if the actor passed to set_key_focus is NULL then the stage
	has the key focus.

	* tests/test-events.c: Update the events test with the API
	changes.
This commit is contained in:
Emmanuele Bassi 2007-10-02 14:03:36 +00:00
parent 5b4b51ba7a
commit 090c1d11b4
7 changed files with 196 additions and 133 deletions

View File

@ -1,3 +1,33 @@
2007-10-01 Emmanuele Bassi <ebassi@openedhand.com>
* clutter/clutter-actor.[ch]: Remove the ::event-after signal
class handler, as it's not meant to be overridden by sub-classes.
(clutter_actor_class_init):
Make every event-related signal return a boolean: return TRUE
in a signal handler to block the emission. The value is accumulated
automatically by the signal API.
(clutter_actor_event): If ::event returns TRUE, skip to emitting
::event-after. Return the value accumulated by the signal emission
chain.
* clutter/clutter-private.h: Rename _clutter_boolean_accumlator().
* clutter/clutter-main.c (clutter_do_event): If clutter_actor_event()
returns TRUE then stop the event emission chain from child to parent.
* clutter/clutter-stage.c (clutter_stage_event): Behave like
clutter_actor_event().
(clutter_stage_get_key_focus),
(clutter_stage_set_key_focus): Avoid a nasty circular reference
issue: if the actor passed to set_key_focus is NULL then the stage
has the key focus.
* tests/test-events.c: Update the events test with the API
changes.
2007-10-01 Tomas Frydrych <tf@openedhand.com> 2007-10-01 Tomas Frydrych <tf@openedhand.com>
* clutter/clutter-actor.c: * clutter/clutter-actor.c:

View File

@ -1241,6 +1241,9 @@ clutter_actor_class_init (ClutterActorClass *klass)
* The ::event signal is emitted each time and event is received * The ::event signal is emitted each time and event is received
* by the @actor. * by the @actor.
* *
* Return value: %TRUE if the event has been handled by the actor,
* or %FALSE to continue the emission.
*
* Since: 0.6 * Since: 0.6
*/ */
actor_signals[EVENT] = actor_signals[EVENT] =
@ -1248,9 +1251,9 @@ 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, event), G_STRUCT_OFFSET (ClutterActorClass, event),
NULL, NULL, _clutter_boolean_handled_accumulator, NULL,
clutter_marshal_VOID__BOXED, clutter_marshal_BOOLEAN__BOXED,
G_TYPE_NONE, 1, G_TYPE_BOOLEAN, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/** /**
* ClutterActor::event-after: * ClutterActor::event-after:
@ -1265,8 +1268,8 @@ clutter_actor_class_init (ClutterActorClass *klass)
actor_signals[EVENT_AFTER] = actor_signals[EVENT_AFTER] =
g_signal_new ("event-after", g_signal_new ("event-after",
G_TYPE_FROM_CLASS (object_class), G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST, 0,
G_STRUCT_OFFSET (ClutterActorClass, event_after), 0,
NULL, NULL, NULL, NULL,
clutter_marshal_VOID__BOXED, clutter_marshal_VOID__BOXED,
G_TYPE_NONE, 1, G_TYPE_NONE, 1,
@ -1279,6 +1282,9 @@ clutter_actor_class_init (ClutterActorClass *klass)
* The ::button-press-event signal is emitted each time a mouse button * The ::button-press-event signal is emitted each time a mouse button
* is pressed on @actor. * is pressed on @actor.
* *
* Return value: %TRUE if the event has been handled by the actor,
* or %FALSE to continue the emission.
*
* Since: 0.6 * Since: 0.6
*/ */
actor_signals[BUTTON_PRESS_EVENT] = actor_signals[BUTTON_PRESS_EVENT] =
@ -1286,9 +1292,9 @@ 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, button_press_event), G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
NULL, NULL, _clutter_boolean_handled_accumulator, NULL,
clutter_marshal_VOID__BOXED, clutter_marshal_BOOLEAN__BOXED,
G_TYPE_NONE, 1, G_TYPE_BOOLEAN, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/** /**
* ClutterActor::button-release-event: * ClutterActor::button-release-event:
@ -1298,6 +1304,9 @@ clutter_actor_class_init (ClutterActorClass *klass)
* The ::button-release-event signal is emitted each time a mouse button * The ::button-release-event signal is emitted each time a mouse button
* is released on @actor. * is released on @actor.
* *
* Return value: %TRUE if the event has been handled by the actor,
* or %FALSE to continue the emission.
*
* Since: 0.6 * Since: 0.6
*/ */
actor_signals[BUTTON_RELEASE_EVENT] = actor_signals[BUTTON_RELEASE_EVENT] =
@ -1305,9 +1314,9 @@ 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, button_release_event), G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
NULL, NULL, _clutter_boolean_handled_accumulator, NULL,
clutter_marshal_VOID__BOXED, clutter_marshal_BOOLEAN__BOXED,
G_TYPE_NONE, 1, G_TYPE_BOOLEAN, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/** /**
* ClutterActor::scroll-event: * ClutterActor::scroll-event:
@ -1317,6 +1326,8 @@ clutter_actor_class_init (ClutterActorClass *klass)
* The ::scroll-event signal is emitted each time a the mouse is * The ::scroll-event signal is emitted each time a the mouse is
* scrolled on @actor * scrolled on @actor
* *
* Return value: %TRUE if the event has been handled by the actor,
* or %FALSE to continue the emission.
* *
* Since: 0.6 * Since: 0.6
*/ */
@ -1325,9 +1336,9 @@ 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, scroll_event), G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
NULL, NULL, _clutter_boolean_handled_accumulator, NULL,
clutter_marshal_VOID__BOXED, clutter_marshal_BOOLEAN__BOXED,
G_TYPE_NONE, 1, G_TYPE_BOOLEAN, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/** /**
* ClutterActor::key-press-event: * ClutterActor::key-press-event:
@ -1337,6 +1348,9 @@ clutter_actor_class_init (ClutterActorClass *klass)
* The ::key-press-event signal is emitted each time a keyboard button * The ::key-press-event signal is emitted each time a keyboard button
* is pressed on @actor. * is pressed on @actor.
* *
* Return value: %TRUE if the event has been handled by the actor,
* or %FALSE to continue the emission.
*
* Since: 0.6 * Since: 0.6
*/ */
actor_signals[KEY_PRESS_EVENT] = actor_signals[KEY_PRESS_EVENT] =
@ -1344,9 +1358,9 @@ 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, key_press_event), G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
NULL, NULL, _clutter_boolean_handled_accumulator, NULL,
clutter_marshal_VOID__BOXED, clutter_marshal_BOOLEAN__BOXED,
G_TYPE_NONE, 1, G_TYPE_BOOLEAN, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/** /**
* ClutterActor::key-release-event: * ClutterActor::key-release-event:
@ -1356,6 +1370,9 @@ clutter_actor_class_init (ClutterActorClass *klass)
* The ::key-release-event signal is emitted each time a keyboard button * The ::key-release-event signal is emitted each time a keyboard button
* is released on @actor. * is released on @actor.
* *
* Return value: %TRUE if the event has been handled by the actor,
* or %FALSE to continue the emission.
*
* Since: 0.6 * Since: 0.6
*/ */
actor_signals[KEY_RELEASE_EVENT] = actor_signals[KEY_RELEASE_EVENT] =
@ -1363,9 +1380,9 @@ 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, key_release_event), G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
NULL, NULL, _clutter_boolean_handled_accumulator, NULL,
clutter_marshal_VOID__BOXED, clutter_marshal_BOOLEAN__BOXED,
G_TYPE_NONE, 1, G_TYPE_BOOLEAN, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/** /**
* ClutterActor::motion-event: * ClutterActor::motion-event:
@ -1375,6 +1392,9 @@ clutter_actor_class_init (ClutterActorClass *klass)
* The ::motion-event signal is emitted each time the mouse pointer is * The ::motion-event signal is emitted each time the mouse pointer is
* moved on @actor. * moved on @actor.
* *
* Return value: %TRUE if the event has been handled by the actor,
* or %FALSE to continue the emission.
*
* Since: 0.6 * Since: 0.6
*/ */
actor_signals[MOTION_EVENT] = actor_signals[MOTION_EVENT] =
@ -1382,9 +1402,9 @@ 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, motion_event), G_STRUCT_OFFSET (ClutterActorClass, motion_event),
NULL, NULL, _clutter_boolean_handled_accumulator, NULL,
clutter_marshal_VOID__BOXED, clutter_marshal_BOOLEAN__BOXED,
G_TYPE_NONE, 1, G_TYPE_BOOLEAN, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/** /**
@ -2899,7 +2919,7 @@ gboolean
clutter_actor_event (ClutterActor *actor, clutter_actor_event (ClutterActor *actor,
ClutterEvent *event) ClutterEvent *event)
{ {
gboolean res = TRUE; gboolean retval = TRUE;
gint signal_num = -1; gint signal_num = -1;
g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE); g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
@ -2907,50 +2927,50 @@ clutter_actor_event (ClutterActor *actor,
g_object_ref (actor); g_object_ref (actor);
g_signal_emit (actor, actor_signals[EVENT], 0, event); g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
switch (event->type) if (!retval)
{ {
case CLUTTER_NOTHING: switch (event->type)
break; {
case CLUTTER_BUTTON_PRESS: case CLUTTER_NOTHING:
case CLUTTER_2BUTTON_PRESS: break;
case CLUTTER_3BUTTON_PRESS: case CLUTTER_BUTTON_PRESS:
signal_num = BUTTON_PRESS_EVENT; case CLUTTER_2BUTTON_PRESS:
break; case CLUTTER_3BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE: signal_num = BUTTON_PRESS_EVENT;
signal_num = BUTTON_RELEASE_EVENT; break;
break; case CLUTTER_BUTTON_RELEASE:
case CLUTTER_SCROLL: signal_num = BUTTON_RELEASE_EVENT;
signal_num = SCROLL_EVENT; break;
break; case CLUTTER_SCROLL:
case CLUTTER_KEY_PRESS: signal_num = SCROLL_EVENT;
signal_num = KEY_PRESS_EVENT; break;
break; case CLUTTER_KEY_PRESS:
case CLUTTER_KEY_RELEASE: signal_num = KEY_PRESS_EVENT;
signal_num = KEY_RELEASE_EVENT; break;
break; case CLUTTER_KEY_RELEASE:
case CLUTTER_MOTION: signal_num = KEY_RELEASE_EVENT;
signal_num = MOTION_EVENT; break;
break; case CLUTTER_MOTION:
case CLUTTER_DELETE: signal_num = MOTION_EVENT;
case CLUTTER_DESTROY_NOTIFY: break;
case CLUTTER_CLIENT_MESSAGE: case CLUTTER_DELETE:
default: case CLUTTER_DESTROY_NOTIFY:
signal_num = -1; case CLUTTER_CLIENT_MESSAGE:
break; default:
signal_num = -1;
break;
}
if (signal_num != -1)
g_signal_emit (actor, actor_signals[signal_num], 0, event, &retval);
} }
if (signal_num != -1) g_signal_emit (actor, actor_signals[EVENT_AFTER], 0, event);
{
g_signal_emit (actor, actor_signals[signal_num], 0, event);
g_signal_emit (actor, actor_signals[EVENT_AFTER], 0, event);
res = TRUE;
}
g_object_unref (actor); g_object_unref (actor);
return res; return retval;
} }
void void

View File

@ -193,24 +193,22 @@ struct _ClutterActorClass
const ClutterColor *color); const ClutterColor *color);
/* event signals */ /* event signals */
void (* event) (ClutterActor *actor, gboolean (* event) (ClutterActor *actor,
ClutterEvent *event); ClutterEvent *event);
void (* event_after) (ClutterActor *actor, gboolean (* button_press_event) (ClutterActor *actor,
ClutterEvent *event); ClutterButtonEvent *event);
void (* button_press_event) (ClutterActor *actor, gboolean (* button_release_event) (ClutterActor *actor,
ClutterButtonEvent *event); ClutterButtonEvent *event);
void (* button_release_event) (ClutterActor *actor, gboolean (* scroll_event) (ClutterActor *actor,
ClutterButtonEvent *event); ClutterScrollEvent *event);
void (* scroll_event) (ClutterActor *actor, gboolean (* key_press_event) (ClutterActor *actor,
ClutterScrollEvent *event); ClutterKeyEvent *event);
void (* key_press_event) (ClutterActor *actor, gboolean (* key_release_event) (ClutterActor *actor,
ClutterKeyEvent *event); ClutterKeyEvent *event);
void (* key_release_event) (ClutterActor *actor, gboolean (* motion_event) (ClutterActor *actor,
ClutterKeyEvent *event); ClutterMotionEvent *event);
void (* motion_event) (ClutterActor *actor, void (* focus_in) (ClutterActor *actor);
ClutterMotionEvent *event); void (* focus_out) (ClutterActor *actor);
void (* focus_in) (ClutterActor *actor);
void (* focus_out) (ClutterActor *actor);
/*< private >*/ /*< private >*/
/* padding for future expansion */ /* padding for future expansion */

View File

@ -237,12 +237,14 @@ 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 = g_object_ref (actor);
/* bubble up */ /* bubble up */
do do
{ {
clutter_actor_event (actor, event); if (clutter_actor_event (actor, event))
break;
actor = clutter_actor_get_parent (actor); actor = clutter_actor_get_parent (actor);
} }
while (actor != NULL); while (actor != NULL);
@ -252,7 +254,7 @@ clutter_do_event (ClutterEvent *event)
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 = g_object_ref (stage);
clutter_actor_event (stage, event); clutter_actor_event (stage, event);
break; break;
} }
@ -270,10 +272,9 @@ clutter_do_event (ClutterEvent *event)
/* Safety on - probably a release off stage ? /* Safety on - probably a release off stage ?
* FIXME: should likely deliver the release somehow - grabs ? * FIXME: should likely deliver the release somehow - grabs ?
*/ */
if (x > CLUTTER_STAGE_WIDTH() if (x > CLUTTER_STAGE_WIDTH () ||
|| y > CLUTTER_STAGE_HEIGHT() y > CLUTTER_STAGE_HEIGHT() ||
|| x < 0 x < 0 || y < 0)
|| y < 0)
break; break;
/* Map the event to a reactive actor */ /* Map the event to a reactive actor */
@ -285,9 +286,9 @@ clutter_do_event (ClutterEvent *event)
x, y, actor); x, y, actor);
if (event->type == CLUTTER_SCROLL) if (event->type == CLUTTER_SCROLL)
event->scroll.source = g_object_ref(actor); event->scroll.source = g_object_ref (actor);
else else
event->button.source = g_object_ref(actor); event->button.source = g_object_ref (actor);
/* Motion enter leave events */ /* Motion enter leave events */
if (event->type == CLUTTER_MOTION) if (event->type == CLUTTER_MOTION)
@ -317,7 +318,8 @@ clutter_do_event (ClutterEvent *event)
clutter_actor_get_parent (actor) == NULL /* STAGE */ ) clutter_actor_get_parent (actor) == NULL /* STAGE */ )
{ {
CLUTTER_NOTE (EVENT, "forwarding event to reactive actor"); CLUTTER_NOTE (EVENT, "forwarding event to reactive actor");
clutter_actor_event (actor, event); if (clutter_actor_event (actor, event))
break;
} }
actor = clutter_actor_get_parent (actor); actor = clutter_actor_get_parent (actor);
@ -326,14 +328,14 @@ clutter_do_event (ClutterEvent *event)
break; break;
case CLUTTER_STAGE_STATE: case CLUTTER_STAGE_STATE:
/* fullscreen / focus - forward to stage */ /* fullscreen / focus - forward to stage */
clutter_stage_event (CLUTTER_STAGE(stage), event); clutter_stage_event (CLUTTER_STAGE (stage), event);
break; break;
case CLUTTER_CLIENT_MESSAGE: case CLUTTER_CLIENT_MESSAGE:
break; break;
} }
} }
ClutterActor* ClutterActor *
_clutter_do_pick (ClutterStage *stage, _clutter_do_pick (ClutterStage *stage,
gint x, gint x,
gint y, gint y,
@ -369,7 +371,7 @@ _clutter_do_pick (ClutterStage *stage,
glReadPixels(x, viewport[3] - y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel); glReadPixels(x, viewport[3] - y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff) if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff)
return CLUTTER_ACTOR(stage); return CLUTTER_ACTOR (stage);
cogl_get_bitmasks (&r, &g, &b, NULL); cogl_get_bitmasks (&r, &g, &b, NULL);
@ -1196,10 +1198,10 @@ clutter_init (int *argc,
} }
gboolean gboolean
_clutter_boolean_accumulator (GSignalInvocationHint *ihint, _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint,
GValue *return_accu, GValue *return_accu,
const GValue *handler_return, const GValue *handler_return,
gpointer dummy) gpointer dummy)
{ {
gboolean continue_emission; gboolean continue_emission;
gboolean signal_handled; gboolean signal_handled;

View File

@ -97,12 +97,6 @@ ClutterMainContext *clutter_context_get_default (void);
#define CLUTTER_PARAM_READWRITE \ #define CLUTTER_PARAM_READWRITE \
G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |G_PARAM_STATIC_BLURB G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |G_PARAM_STATIC_BLURB
/* signal accumulators */
gboolean _clutter_boolean_accumulator (GSignalInvocationHint *ihint,
GValue *return_accu,
const GValue *handler_return,
gpointer dummy);
/* vfuncs implemnted by backend */ /* vfuncs implemnted by backend */
GType _clutter_backend_impl_get_type (void); GType _clutter_backend_impl_get_type (void);
@ -129,11 +123,20 @@ void _clutter_event_button_generate (ClutterBackend *backend,
void _clutter_feature_init (void); void _clutter_feature_init (void);
ClutterActor* _clutter_do_pick (ClutterStage *stage, ClutterActor *_clutter_do_pick (ClutterStage *stage,
gint x, gint x,
gint y, gint y,
ClutterPickMode mode); ClutterPickMode mode);
/* use this function as the accumulator if you have a signal with
* a G_TYPE_BOOLEAN return value; this will stop the emission as
* soon as one handler returns TRUE
*/
gboolean _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint,
GValue *return_accu,
const GValue *handler_return,
gpointer dummy);
/* Does this need to be private ? */ /* Does this need to be private ? */
void clutter_do_event (ClutterEvent *event); void clutter_do_event (ClutterEvent *event);

View File

@ -397,8 +397,7 @@ clutter_stage_init (ClutterStage *self)
clutter_actor_set_size (CLUTTER_ACTOR (self), 640, 480); clutter_actor_set_size (CLUTTER_ACTOR (self), 640, 480);
clutter_actor_set_reactive (CLUTTER_ACTOR (self)); clutter_actor_set_reactive (CLUTTER_ACTOR (self));
clutter_stage_set_key_focus (self, CLUTTER_ACTOR (self)); clutter_stage_set_key_focus (self, NULL);
} }
/** /**
@ -830,7 +829,8 @@ clutter_stage_event (ClutterStage *stage,
return FALSE; return FALSE;
/* emit raw event */ /* emit raw event */
clutter_actor_event (CLUTTER_ACTOR(stage), event); if (clutter_actor_event (CLUTTER_ACTOR (stage), event))
return TRUE;
if (event->stage_state.changed_mask & CLUTTER_STAGE_STATE_FULLSCREEN) if (event->stage_state.changed_mask & CLUTTER_STAGE_STATE_FULLSCREEN)
{ {
@ -904,7 +904,7 @@ on_key_focused_weak_notify (gpointer data,
GObject *where_the_object_was) GObject *where_the_object_was)
{ {
ClutterStagePrivate *priv; ClutterStagePrivate *priv;
ClutterStage *stage = CLUTTER_STAGE(data); ClutterStage *stage = CLUTTER_STAGE (data);
g_return_if_fail (CLUTTER_IS_STAGE (stage)); g_return_if_fail (CLUTTER_IS_STAGE (stage));
@ -914,12 +914,12 @@ on_key_focused_weak_notify (gpointer data,
/* focused actor has dissapeared - fall back to stage /* focused actor has dissapeared - fall back to stage
* FIXME: need some kind of signal dance/block here. * FIXME: need some kind of signal dance/block here.
*/ */
clutter_stage_set_key_focus (stage, CLUTTER_ACTOR(stage)); clutter_stage_set_key_focus (stage, NULL);
} }
void void
clutter_stage_set_key_focus (ClutterStage *stage, clutter_stage_set_key_focus (ClutterStage *stage,
ClutterActor *actor) ClutterActor *actor)
{ {
ClutterStagePrivate *priv; ClutterStagePrivate *priv;
@ -933,33 +933,38 @@ clutter_stage_set_key_focus (ClutterStage *stage,
if (priv->key_focused_actor) if (priv->key_focused_actor)
{ {
g_object_weak_unref (G_OBJECT(priv->key_focused_actor), g_object_weak_unref (G_OBJECT (priv->key_focused_actor),
on_key_focused_weak_notify, on_key_focused_weak_notify,
stage); stage);
g_signal_emit_by_name (G_OBJECT(priv->key_focused_actor), "focus-out"); g_signal_emit_by_name (priv->key_focused_actor, "focus-out");
}
priv->key_focused_actor = actor; priv->key_focused_actor = NULL;
}
else
g_signal_emit_by_name (stage, "focus-out");
if (actor) if (actor)
{ {
g_object_weak_ref (G_OBJECT(actor), priv->key_focused_actor = actor;
g_object_weak_ref (G_OBJECT (actor),
on_key_focused_weak_notify, on_key_focused_weak_notify,
stage); stage);
g_signal_emit_by_name (G_OBJECT(actor), "focus-in"); g_signal_emit_by_name (priv->key_focused_actor, "focus-in");
} }
else
g_signal_emit_by_name (stage, "focus-in");
} }
ClutterActor* ClutterActor *
clutter_stage_get_key_focus (ClutterStage *stage) clutter_stage_get_key_focus (ClutterStage *stage)
{ {
ClutterStagePrivate *priv;
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL); g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
priv = stage->priv; if (stage->priv->key_focused_actor)
return stage->priv->key_focused_actor;
return priv->key_focused_actor; return CLUTTER_ACTOR (stage);
} }

View File

@ -11,7 +11,7 @@ stage_state_cb (ClutterStage *stage,
printf("[stage signal] %s\n", detail); printf("[stage signal] %s\n", detail);
} }
static void static gboolean
blue_button_cb (ClutterActor *actor, blue_button_cb (ClutterActor *actor,
ClutterEvent *event, ClutterEvent *event,
gpointer data) gpointer data)
@ -26,9 +26,11 @@ blue_button_cb (ClutterActor *actor,
IsFullScreen = TRUE; IsFullScreen = TRUE;
g_object_set (stage, "fullscreen", IsFullScreen, NULL); g_object_set (stage, "fullscreen", IsFullScreen, NULL);
return FALSE;
} }
void static void
key_focus_in_cb (ClutterActor *actor, key_focus_in_cb (ClutterActor *actor,
gpointer data) gpointer data)
{ {
@ -40,7 +42,6 @@ key_focus_in_cb (ClutterActor *actor,
} }
else else
{ {
clutter_actor_show (focus_box);
clutter_actor_set_position (focus_box, clutter_actor_set_position (focus_box,
clutter_actor_get_x (actor) - 5, clutter_actor_get_x (actor) - 5,
clutter_actor_get_y (actor) - 5); clutter_actor_get_y (actor) - 5);
@ -48,15 +49,16 @@ key_focus_in_cb (ClutterActor *actor,
clutter_actor_set_size (focus_box, clutter_actor_set_size (focus_box,
clutter_actor_get_width (actor) + 10, clutter_actor_get_width (actor) + 10,
clutter_actor_get_height (actor) + 10); clutter_actor_get_height (actor) + 10);
clutter_actor_show (focus_box);
} }
} }
static void static gboolean
input_cb (ClutterActor *actor, input_cb (ClutterActor *actor,
ClutterEvent *event, ClutterEvent *event,
gpointer data) gpointer data)
{ {
ClutterStage *stage = CLUTTER_STAGE (clutter_stage_get_default ());
gchar keybuf[9], *source = (gchar*)data; gchar keybuf[9], *source = (gchar*)data;
int len = 0; int len = 0;
@ -88,9 +90,10 @@ input_cb (ClutterActor *actor,
break; break;
case CLUTTER_BUTTON_RELEASE: case CLUTTER_BUTTON_RELEASE:
printf("[%s] BUTTON RELEASE", source); printf("[%s] BUTTON RELEASE", source);
if (clutter_event_get_source (event) == actor) if (clutter_event_get_source (event) == CLUTTER_ACTOR (stage))
clutter_stage_set_key_focus clutter_stage_set_key_focus (stage, NULL);
(CLUTTER_STAGE(clutter_stage_get_default ()), actor); else if (clutter_event_get_source (event) == actor)
clutter_stage_set_key_focus (stage, actor);
break; break;
case CLUTTER_SCROLL: case CLUTTER_SCROLL:
printf("[%s] BUTTON SCROLL", source); printf("[%s] BUTTON SCROLL", source);
@ -113,8 +116,10 @@ input_cb (ClutterActor *actor,
if (clutter_event_get_source (event) == actor) if (clutter_event_get_source (event) == actor)
printf(" *source*"); printf(" *source*");
printf("\n"); printf("\n");
return FALSE;
} }
int int
@ -148,7 +153,7 @@ main (int argc, char *argv[])
clutter_actor_set_reactive (actor); clutter_actor_set_reactive (actor);
clutter_container_add (CLUTTER_CONTAINER(stage), actor, NULL); clutter_container_add (CLUTTER_CONTAINER (stage), actor, NULL);
g_signal_connect (actor, "event", G_CALLBACK (input_cb), "red box"); g_signal_connect (actor, "event", G_CALLBACK (input_cb), "red box");
g_signal_connect (actor, "focus-in", G_CALLBACK (key_focus_in_cb), g_signal_connect (actor, "focus-in", G_CALLBACK (key_focus_in_cb),
@ -162,7 +167,7 @@ main (int argc, char *argv[])
clutter_actor_set_reactive (actor); clutter_actor_set_reactive (actor);
clutter_container_add (CLUTTER_CONTAINER(stage), actor, NULL); clutter_container_add (CLUTTER_CONTAINER (stage), actor, NULL);
g_signal_connect (actor, "event", G_CALLBACK (input_cb), "green box"); g_signal_connect (actor, "event", G_CALLBACK (input_cb), "green box");
g_signal_connect (actor, "focus-in", G_CALLBACK (key_focus_in_cb), g_signal_connect (actor, "focus-in", G_CALLBACK (key_focus_in_cb),