2007-08-13 Matthew Allum <mallum@openedhand.com>

* clutter/clutter-actor.c:
        * clutter/clutter-actor.h:
        * clutter/clutter-event.c:
        * clutter/clutter-event.h:
        * clutter/clutter-main.c:
        * clutter/clutter-main.h:
        * clutter/clutter-private.h:
        * clutter/clutter-stage.c:
        * clutter/clutter-stage.h:
        * clutter/clutter-types.h:
        Initial implementation of actors emmitting event signals (423);
        - Actors set_reactive() to receive mouse events.
          (call clutter_enable_motion_events() for per action motion events)
        - clutter_stage_set_key_focus () to direct key events.
        - Events bubble up to parents (ending at stage)
          (original source identified by clutter_event_get_source())
        TODO:
        - enter/leave notifys for actors.
        - stage specific events - fullscreen
        - grabs

        * tests/test-events.c:
        Extend a little to use new API

        * clutter/cogl/gl/cogl.c:
        * clutter/glx/clutter-backend-glx.c:
        Move get_proc_address into cogl and out of backend.
        (shaders will need it)

        * clutter/clutter-group.c: (clutter_group_real_lower):
        Fix a minor compile warning.

        * TODO:
        Sync up.
This commit is contained in:
Matthew Allum 2007-08-13 20:48:01 +00:00
parent e726ef9a2b
commit 8ad4dde16b
16 changed files with 913 additions and 398 deletions

View File

@ -1,3 +1,40 @@
2007-08-13 Matthew Allum <mallum@openedhand.com>
* clutter/clutter-actor.c:
* clutter/clutter-actor.h:
* clutter/clutter-event.c:
* clutter/clutter-event.h:
* clutter/clutter-main.c:
* clutter/clutter-main.h:
* clutter/clutter-private.h:
* clutter/clutter-stage.c:
* clutter/clutter-stage.h:
* clutter/clutter-types.h:
Initial implementation of actors emmitting event signals (423);
- Actors set_reactive() to receive mouse events.
(call clutter_enable_motion_events() for per action motion events)
- clutter_stage_set_key_focus () to direct key events.
- Events bubble up to parents (ending at stage)
(original source identified by clutter_event_get_source())
TODO:
- enter/leave notifys for actors.
- stage specific events - fullscreen
- grabs
* tests/test-events.c:
Extend a little to use new API
* clutter/cogl/gl/cogl.c:
* clutter/glx/clutter-backend-glx.c:
Move get_proc_address into cogl and out of backend.
(shaders will need it)
* clutter/clutter-group.c: (clutter_group_real_lower):
Fix a minor compile warning.
* TODO:
Sync up.
2007-08-13 Emmanuele Bassi <ebassi@openedhand.com> 2007-08-13 Emmanuele Bassi <ebassi@openedhand.com>
* clutter/clutter-container.[ch]: Add find_child_by_id(), * clutter/clutter-container.[ch]: Add find_child_by_id(),
@ -27,10 +64,16 @@
the per-timeout dispatch; this guarantees that the ref+unref of the per-timeout dispatch; this guarantees that the ref+unref of
the single timeouts are done under the main lock. the single timeouts are done under the main lock.
2007-08-12 Matthew Allum <mallum@openedhand.com>
* clutter/clutter-texture.c: (texture_upload_data):
Align texture data correctly for edge tiles.
(#422 - Neil Roberts)
2007-08-11 Matthew Allum <mallum@openedhand.com> 2007-08-11 Matthew Allum <mallum@openedhand.com>
* clutter/clutter-texture.c: * clutter/clutter-texture.c:
Fix typo in clutter_texture_get_pixbuf (#458, #442?, Neil Roberts). Fix typo in clutter_texture_get_pixbuf (#458, Neil Roberts).
Use take_object when getting pixbuf prop to avoid ref leak. (Neil Use take_object when getting pixbuf prop to avoid ref leak. (Neil
Roberts) Roberts)

39
TODO
View File

@ -1,31 +1,7 @@
TODO TODO
==== ====
Last updated 22/06/2007 Last updated 08/08/2007
0.4 (July 07)
==
Definetly:
- YUV texture data [DONE] premulled alpha texture data. (ma)
- Basic layout code. [DONE] (eb)
- Basic text entry [DONE] (np)
- Perspective setup [DONE] (ma)
- API doc fixups (all)
- main loop scheduling - paints vs timelimes vs events [DONE] ((ma, eb)
- ClutterProxyTexture (ma)
- event queue fixups [DONE} (eb)
- clutter_actor_get_vertices [Partly DONE?] (tf)
- fix up event queue [DONE] (eb)
Maybe:
- SDL event fixups [DONE - roughly]
- Application developers manual
- Lookat type functionality.
- Mipmaps for pango renderer to improving text scaling quality
0.6 0.6
=== ===
@ -41,10 +17,13 @@ Definetly:
- Very simple focus model - actors have a focus flag and if set emit - Very simple focus model - actors have a focus flag and if set emit
key events. key events.
- Motion events need to be explicitly enabled. - Motion events need to be explicitly enabled.
- Mipmaps for pango renderer to improving text scaling quality
- ClutterScore
- Class for chaining timelines togeather
Nice/Maybe: Nice/Maybe:
===========
- Lookat type functionality.
- Improve cogl massively to be be processing like. - Improve cogl massively to be be processing like.
- Gradient support ? - Gradient support ?
- Rectangle like props to all actors - Rectangle like props to all actors
@ -54,3 +33,11 @@ Nice/Maybe:
- ClutterBehaviourDepth (trivial) - ClutterBehaviourDepth (trivial)
- ClutterTextureAnimation (trivial) - ClutterTextureAnimation (trivial)
- Glitz backend over GLX (would cover above) - Glitz backend over GLX (would cover above)
(Also see bugzilla.o-hand.com bug with 0.6 milestones for more
detail/status on the above)
0.8
===
- ?

View File

@ -91,7 +91,16 @@ enum
HIDE, HIDE,
DESTROY, DESTROY,
PARENT_SET, PARENT_SET,
EVENT,
EVENT_AFTER,
BUTTON_PRESS_EVENT,
BUTTON_RELEASE_EVENT,
SCROLL_EVENT,
KEY_PRESS_EVENT,
KEY_RELEASE_EVENT,
MOTION_EVENT,
FOCUS_IN,
FOCUS_OUT,
LAST_SIGNAL LAST_SIGNAL
}; };
@ -193,6 +202,9 @@ clutter_actor_hide (ClutterActor *self)
{ {
g_object_ref (self); g_object_ref (self);
if (CLUTTER_ACTOR_IS_REACTIVE(self))
; /* FIXME: decrease global reactive count */
g_signal_emit (self, actor_signals[HIDE], 0); g_signal_emit (self, actor_signals[HIDE], 0);
g_object_notify (G_OBJECT (self), "visible"); g_object_notify (G_OBJECT (self), "visible");
@ -678,12 +690,16 @@ clutter_actor_paint (ClutterActor *self)
_clutter_actor_apply_modelview_transform (self); _clutter_actor_apply_modelview_transform (self);
if (G_UNLIKELY(context->pick_mode == TRUE)) if (G_UNLIKELY(context->pick_mode != CLUTTER_PICK_NONE))
{ {
gint r, g, b; gint r, g, b;
ClutterColor col; ClutterColor col;
guint32 id; guint32 id;
if (context->pick_mode == CLUTTER_PICK_ALL
|| (context->pick_mode == CLUTTER_PICK_REACTIVE
&& CLUTTER_ACTOR_IS_REACTIVE(self)))
{
id = clutter_actor_get_id (self); id = clutter_actor_get_id (self);
cogl_get_bitmasks (&r, &g, &b, NULL); cogl_get_bitmasks (&r, &g, &b, NULL);
@ -694,11 +710,13 @@ clutter_actor_paint (ClutterActor *self)
col.blue = (id & (0xff>>(8-b)))<<(8-b); col.blue = (id & (0xff>>(8-b)))<<(8-b);
col.alpha = 0xff; col.alpha = 0xff;
/* Actor will then paint silhouette of itself in supplied color. /* Actor will then paint silhouette of itself in supplied
* See clutter_stage_get_actor_at_pos() for where picking is enabled. * color. See clutter_stage_get_actor_at_pos() for where
* picking is enabled.
*/ */
clutter_actor_pick (self, &col); clutter_actor_pick (self, &col);
} }
}
else else
{ {
if (G_LIKELY(klass->paint)) if (G_LIKELY(klass->paint))
@ -1151,6 +1169,195 @@ clutter_actor_class_init (ClutterActorClass *klass)
G_TYPE_NONE, 1, G_TYPE_NONE, 1,
CLUTTER_TYPE_ACTOR); CLUTTER_TYPE_ACTOR);
/**
* ClutterActor::event:
* @actor: the actor which received the event
* @event: a #ClutterEvent
*
* The ::event signal is emitted each time and event is received
* by the @actor.
*
* Since: 0.6
*/
actor_signals[EVENT] =
g_signal_new ("event",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterActorClass, event),
NULL, NULL,
clutter_marshal_VOID__BOXED,
G_TYPE_NONE, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/**
* ClutterActor::event-after:
* @actor: the actor which received the event
* @event: a #ClutterEvent
*
* The ::event-after signal is emitted after each event, except for
* the "delete-event" is received by @actor.
*
* Since: 0.6
*/
actor_signals[EVENT_AFTER] =
g_signal_new ("event-after",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterActorClass, event_after),
NULL, NULL,
clutter_marshal_VOID__BOXED,
G_TYPE_NONE, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/**
* ClutterActor::button-press-event:
* @actor: the actor which received the event
* @event: a #ClutterButtonEvent
*
* The ::button-press-event signal is emitted each time a mouse button
* is pressed on @actor.
*
* Since: 0.6
*/
actor_signals[BUTTON_PRESS_EVENT] =
g_signal_new ("button-press-event",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
NULL, NULL,
clutter_marshal_VOID__BOXED,
G_TYPE_NONE, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/**
* ClutterActor::button-release-event:
* @actor: the actor which received the event
* @event: a #ClutterButtonEvent
*
* The ::button-release-event signal is emitted each time a mouse button
* is released on @actor.
*
* Since: 0.6
*/
actor_signals[BUTTON_RELEASE_EVENT] =
g_signal_new ("button-release-event",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
NULL, NULL,
clutter_marshal_VOID__BOXED,
G_TYPE_NONE, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/**
* ClutterActor::scroll-event:
* @actor: the actor which received the event
* @event: a #ClutterScrollEvent
*
* The ::scroll-event signal is emitted each time a the mouse is
* scrolled on @actor
*
*
* Since: 0.6
*/
actor_signals[SCROLL_EVENT] =
g_signal_new ("scroll-event",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
NULL, NULL,
clutter_marshal_VOID__BOXED,
G_TYPE_NONE, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/**
* ClutterActor::key-press-event:
* @actor: the actor which received the event
* @event: a #ClutterKeyEvent
*
* The ::key-press-event signal is emitted each time a keyboard button
* is pressed on @actor.
*
* Since: 0.6
*/
actor_signals[KEY_PRESS_EVENT] =
g_signal_new ("key-press-event",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
NULL, NULL,
clutter_marshal_VOID__BOXED,
G_TYPE_NONE, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/**
* ClutterActor::key-release-event:
* @actor: the actor which received the event
* @event: a #ClutterKeyEvent
*
* The ::key-release-event signal is emitted each time a keyboard button
* is released on @actor.
*
* Since: 0.6
*/
actor_signals[KEY_RELEASE_EVENT] =
g_signal_new ("key-release-event",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
NULL, NULL,
clutter_marshal_VOID__BOXED,
G_TYPE_NONE, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/**
* ClutterActor::motion-event:
* @actor: the actor which received the event
* @event: a #ClutterMotionEvent
*
* The ::motion-event signal is emitted each time the mouse pointer is
* moved on @actor.
*
* Since: 0.6
*/
actor_signals[MOTION_EVENT] =
g_signal_new ("motion-event",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterActorClass, motion_event),
NULL, NULL,
clutter_marshal_VOID__BOXED,
G_TYPE_NONE, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/**
* ClutterActor::focus-in:
* @actor: the actor which now has key focus
*
* The ::focus-in signal is emitted when @actor recieves key focus.
*
* Since: 0.6
*/
actor_signals[FOCUS_IN] =
g_signal_new ("focus-in",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterActorClass, focus_in),
NULL, NULL,
clutter_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/**
* ClutterActor::focus-out:
* @actor: the actor which now has key focus
*
* The ::focus-out signal is emitted when @actor loses key focus.
*
* Source: 0.6
*/
actor_signals[FOCUS_OUT] =
g_signal_new ("focus-out",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterActorClass, focus_out),
NULL, NULL,
clutter_marshal_VOID__VOID,
G_TYPE_NONE, 0);
klass->show = clutter_actor_real_show; klass->show = clutter_actor_real_show;
klass->show_all = clutter_actor_show; klass->show_all = clutter_actor_show;
klass->hide = clutter_actor_real_hide; klass->hide = clutter_actor_real_hide;
@ -2598,6 +2805,104 @@ clutter_actor_lower_bottom (ClutterActor *self)
clutter_actor_lower (self, NULL); clutter_actor_lower (self, NULL);
} }
/*
* Event handling
*/
/**
* clutter_actor_event:
* @actor: a #ClutterActor
* @event: a #ClutterEvent
*
* This function is used to emit an event on the main stage.
* You should rarely need to use this function, except for
* synthetising events.
*
* Return value: the return value from the signal emission
*
* Since: 0.4
*/
gboolean
clutter_actor_event (ClutterActor *actor,
ClutterEvent *event)
{
gboolean res = TRUE;
gint signal_num = -1;
g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
g_object_ref (actor);
g_signal_emit (actor, actor_signals[EVENT], 0, event);
switch (event->type)
{
case CLUTTER_NOTHING:
break;
case CLUTTER_BUTTON_PRESS:
case CLUTTER_2BUTTON_PRESS:
case CLUTTER_3BUTTON_PRESS:
signal_num = BUTTON_PRESS_EVENT;
break;
case CLUTTER_BUTTON_RELEASE:
signal_num = BUTTON_RELEASE_EVENT;
break;
case CLUTTER_SCROLL:
signal_num = SCROLL_EVENT;
break;
case CLUTTER_KEY_PRESS:
signal_num = KEY_PRESS_EVENT;
break;
case CLUTTER_KEY_RELEASE:
signal_num = KEY_RELEASE_EVENT;
break;
case CLUTTER_MOTION:
signal_num = MOTION_EVENT;
break;
case CLUTTER_DELETE:
signal_num = -1;
break;
case CLUTTER_DESTROY_NOTIFY:
signal_num = -1;
break;
case CLUTTER_CLIENT_MESSAGE:
signal_num = -1;
break;
default:
break;
}
if (signal_num != -1)
{
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);
return res;
}
void
clutter_actor_set_reactive (ClutterActor *actor)
{
CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
}
void
clutter_actor_unset_reactive (ClutterActor *actor)
{
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
}
gboolean
clutter_actor_is_reactive (ClutterActor *actor)
{
return CLUTTER_ACTOR_IS_REACTIVE(actor);
}
/* /*
* ClutterGemoetry * ClutterGemoetry
*/ */
@ -2618,7 +2923,8 @@ clutter_geometry_get_type (void)
static GType our_type = 0; static GType our_type = 0;
if (our_type == 0) if (our_type == 0)
our_type = g_boxed_type_register_static (g_intern_static_string ("ClutterGeometry"), our_type = g_boxed_type_register_static
(g_intern_static_string ("ClutterGeometry"),
(GBoxedCopyFunc) clutter_geometry_copy, (GBoxedCopyFunc) clutter_geometry_copy,
(GBoxedFreeFunc) g_free); (GBoxedFreeFunc) g_free);
@ -2645,7 +2951,8 @@ clutter_vertex_get_type (void)
static GType our_type = 0; static GType our_type = 0;
if (our_type == 0) if (our_type == 0)
our_type = g_boxed_type_register_static (g_intern_static_string ("ClutterVertex"), our_type = g_boxed_type_register_static
(g_intern_static_string ("ClutterVertex"),
(GBoxedCopyFunc) clutter_vertex_copy, (GBoxedCopyFunc) clutter_vertex_copy,
(GBoxedFreeFunc) g_free); (GBoxedFreeFunc) g_free);
@ -2671,7 +2978,8 @@ clutter_actor_box_get_type (void)
static GType our_type = 0; static GType our_type = 0;
if (our_type == 0) if (our_type == 0)
our_type = g_boxed_type_register_static (g_intern_static_string ("ClutterActorBox"), our_type = g_boxed_type_register_static
(g_intern_static_string ("ClutterActorBox"),
(GBoxedCopyFunc) clutter_actor_box_copy, (GBoxedCopyFunc) clutter_actor_box_copy,
(GBoxedFreeFunc) g_free); (GBoxedFreeFunc) g_free);
return our_type; return our_type;

View File

@ -33,6 +33,7 @@
#include <clutter/clutter-fixed.h> #include <clutter/clutter-fixed.h>
#include <clutter/clutter-types.h> #include <clutter/clutter-types.h>
#include <clutter/clutter-units.h> #include <clutter/clutter-units.h>
#include <clutter/clutter-event.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -57,8 +58,10 @@ G_BEGIN_DECLS
#define CLUTTER_ACTOR_IS_REALIZED(e) ((e)->flags & CLUTTER_ACTOR_REALIZED) #define CLUTTER_ACTOR_IS_REALIZED(e) ((e)->flags & CLUTTER_ACTOR_REALIZED)
#define CLUTTER_ACTOR_IS_VISIBLE(e) (CLUTTER_ACTOR_IS_MAPPED (e) && \ #define CLUTTER_ACTOR_IS_VISIBLE(e) (CLUTTER_ACTOR_IS_MAPPED (e) && \
CLUTTER_ACTOR_IS_REALIZED (e)) CLUTTER_ACTOR_IS_REALIZED (e))
#define CLUTTER_ACTOR_IS_REACTIVE(e) (((e)->flags & CLUTTER_ACTOR_REACTIVE))
/* && CLUTTER_ACTOR_IS_VISIBLE(e)) */
typedef struct _ClutterActor ClutterActor;
typedef struct _ClutterActorClass ClutterActorClass; typedef struct _ClutterActorClass ClutterActorClass;
typedef struct _ClutterActorBox ClutterActorBox; typedef struct _ClutterActorBox ClutterActorBox;
typedef struct _ClutterActorPrivate ClutterActorPrivate; typedef struct _ClutterActorPrivate ClutterActorPrivate;
@ -78,13 +81,16 @@ typedef void (*ClutterCallback) (ClutterActor *actor, gpointer data);
* @CLUTTER_ACTOR_MAPPED: the actor has been painted * @CLUTTER_ACTOR_MAPPED: the actor has been painted
* @CLUTTER_ACTOR_REALIZED: the resources associated to the actor have been * @CLUTTER_ACTOR_REALIZED: the resources associated to the actor have been
* allocated * allocated
* @CLUTTER_ACTOR_REACTIVE: the actor 'reacts' to mouse events emmitting event
* signals
* *
* Flags used to signal the state of an actor. * Flags used to signal the state of an actor.
*/ */
typedef enum typedef enum
{ {
CLUTTER_ACTOR_MAPPED = 1 << 1, CLUTTER_ACTOR_MAPPED = 1 << 1,
CLUTTER_ACTOR_REALIZED = 1 << 2 CLUTTER_ACTOR_REALIZED = 1 << 2,
CLUTTER_ACTOR_REACTIVE = 1 << 3
} ClutterActorFlags; } ClutterActorFlags;
/** /**
@ -186,6 +192,26 @@ struct _ClutterActorClass
void (* pick) (ClutterActor *actor, void (* pick) (ClutterActor *actor,
const ClutterColor *color); const ClutterColor *color);
/* event signals */
void (* event) (ClutterActor *actor,
ClutterEvent *event);
void (* event_after) (ClutterActor *actor,
ClutterEvent *event);
void (* button_press_event) (ClutterActor *actor,
ClutterButtonEvent *event);
void (* button_release_event) (ClutterActor *actor,
ClutterButtonEvent *event);
void (* scroll_event) (ClutterActor *actor,
ClutterScrollEvent *event);
void (* key_press_event) (ClutterActor *actor,
ClutterKeyEvent *event);
void (* key_release_event) (ClutterActor *actor,
ClutterKeyEvent *event);
void (* motion_event) (ClutterActor *actor,
ClutterMotionEvent *event);
void (* focus_in) (ClutterActor *actor);
void (* focus_out) (ClutterActor *actor);
/*< private >*/ /*< private >*/
/* padding for future expansion */ /* padding for future expansion */
gpointer _padding_dummy[32]; gpointer _padding_dummy[32];
@ -336,6 +362,20 @@ void clutter_actor_apply_transform_to_point (ClutterActor
ClutterVertex *point, ClutterVertex *point,
ClutterVertex *vertex); ClutterVertex *vertex);
/* Per actor event handling - may change */
gboolean
clutter_actor_event (ClutterActor *actor,
ClutterEvent *event);
void
clutter_actor_set_reactive (ClutterActor *actor);
void
clutter_actor_unset_reactive (ClutterActor *actor);
gboolean
clutter_actor_is_reactive (ClutterActor *actor);
G_END_DECLS G_END_DECLS
#endif /* _HAVE_CLUTTER_ACTOR_H */ #endif /* _HAVE_CLUTTER_ACTOR_H */

View File

@ -183,6 +183,49 @@ clutter_event_get_coords (ClutterEvent *event,
*y = event_y; *y = event_y;
} }
/**
* clutter_event_get_source:
* @event: a #ClutterEvent
*
* Retrieves the source #ClutterActor the event originated from, or
* NULL if the event has no source.
*
* Since: 0.6
*/
ClutterActor*
clutter_event_get_source (ClutterEvent *event)
{
ClutterActor *res = NULL;
gint event_x, event_y;
g_return_val_if_fail (event != NULL, NULL);
event_x = event_y = 0;
switch (event->type)
{
case CLUTTER_KEY_PRESS:
case CLUTTER_KEY_RELEASE:
res = event->key.source;
break;
case CLUTTER_BUTTON_PRESS:
case CLUTTER_2BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
res = event->button.source;
break;
case CLUTTER_MOTION:
res = event->motion.source;
break;
case CLUTTER_SCROLL:
res = event->scroll.source;
break;
default:
break;
}
return res;
}
/** /**
* clutter_button_event_button: * clutter_button_event_button:
* @buttev: a #ClutterButtonEvent * @buttev: a #ClutterButtonEvent

View File

@ -27,6 +27,7 @@
#define _HAVE_CLUTTER_EVENT_H #define _HAVE_CLUTTER_EVENT_H
#include <glib-object.h> #include <glib-object.h>
#include <clutter/clutter-types.h>
#define CLUTTER_TYPE_EVENT (clutter_event_get_type ()) #define CLUTTER_TYPE_EVENT (clutter_event_get_type ())
#define CLUTTER_PRIORITY_EVENTS (G_PRIORITY_DEFAULT) #define CLUTTER_PRIORITY_EVENTS (G_PRIORITY_DEFAULT)
@ -78,10 +79,12 @@ typedef enum
typedef enum typedef enum
{ {
CLUTTER_STAGE_STATE_FULLSCREEN, CLUTTER_STAGE_STATE_FULLSCREEN = (1<<1),
CLUTTER_STAGE_STATE_MAXIMIZED, CLUTTER_STAGE_STATE_OFFSCREEN = (1<<2),
CLUTTER_STAGE_STATE_MINIMIZED, CLUTTER_STAGE_STATE_POINTER_ENTER = (1<<3),
CLUTTER_STAGE_STATE_OFFSCREEN CLUTTER_STAGE_STATE_POINTER_LEAVE = (1<<4),
CLUTTER_STAGE_STATE_FOCUS_ACTIVATE = (1<<5),
CLUTTER_STAGE_STATE_FOCUS_DEACTIVATE = (1<<6),
} ClutterStageState; } ClutterStageState;
typedef union _ClutterEvent ClutterEvent; typedef union _ClutterEvent ClutterEvent;
@ -107,6 +110,7 @@ struct _ClutterKeyEvent
ClutterModifierType modifier_state; ClutterModifierType modifier_state;
guint keyval; guint keyval;
guint16 hardware_keycode; guint16 hardware_keycode;
ClutterActor *source;
}; };
struct _ClutterButtonEvent struct _ClutterButtonEvent
@ -119,6 +123,7 @@ struct _ClutterButtonEvent
guint32 button; guint32 button;
gdouble *axes; /* Future use */ gdouble *axes; /* Future use */
ClutterInputDevice *device; /* Future use */ ClutterInputDevice *device; /* Future use */
ClutterActor *source;
}; };
struct _ClutterMotionEvent struct _ClutterMotionEvent
@ -130,6 +135,7 @@ struct _ClutterMotionEvent
ClutterModifierType modifier_state; ClutterModifierType modifier_state;
gdouble *axes; /* Future use */ gdouble *axes; /* Future use */
ClutterInputDevice *device; /* Future use */ ClutterInputDevice *device; /* Future use */
ClutterActor *source;
}; };
struct _ClutterScrollEvent struct _ClutterScrollEvent
@ -142,6 +148,7 @@ struct _ClutterScrollEvent
ClutterModifierType modifier_state; ClutterModifierType modifier_state;
gdouble *axes; /* future use */ gdouble *axes; /* future use */
ClutterInputDevice *device; /* future use */ ClutterInputDevice *device; /* future use */
ClutterActor *source;
}; };
struct _ClutterStageStateEvent struct _ClutterStageStateEvent
@ -187,6 +194,8 @@ guint32 clutter_button_event_button (ClutterButtonEvent *buttev);
guint32 clutter_keysym_to_unicode (guint keyval); guint32 clutter_keysym_to_unicode (guint keyval);
ClutterActor* clutter_event_get_source (ClutterEvent *event);
G_END_DECLS G_END_DECLS
#endif #endif

View File

@ -368,7 +368,6 @@ clutter_group_real_lower (ClutterContainer *container,
{ {
ClutterGroup *self = CLUTTER_GROUP (container); ClutterGroup *self = CLUTTER_GROUP (container);
ClutterGroupPrivate *priv = self->priv; ClutterGroupPrivate *priv = self->priv;
gint pos;
priv->children = g_list_remove (priv->children, actor); priv->children = g_list_remove (priv->children, actor);

View File

@ -172,6 +172,23 @@ clutter_redraw (void)
CLUTTER_TIMESTAMP (SCHEDULER, "Redraw finish"); CLUTTER_TIMESTAMP (SCHEDULER, "Redraw finish");
} }
void
clutter_enable_motion_events (gboolean enable)
{
ClutterMainContext *context = clutter_context_get_default ();
context->motion_events_per_actor = enable;
}
gboolean
clutter_get_motion_events_enabled (void)
{
ClutterMainContext *context = clutter_context_get_default ();
return context->motion_events_per_actor;
}
/** /**
* clutter_do_event * clutter_do_event
* @event: a #ClutterEvent. * @event: a #ClutterEvent.
@ -186,6 +203,7 @@ clutter_do_event (ClutterEvent *event)
ClutterMainContext *context; ClutterMainContext *context;
ClutterBackend *backend; ClutterBackend *backend;
ClutterActor *stage; ClutterActor *stage;
static ClutterActor *motion_last_actor = NULL;
context = clutter_context_get_default (); context = clutter_context_get_default ();
backend = context->backend; backend = context->backend;
@ -195,6 +213,10 @@ clutter_do_event (ClutterEvent *event)
CLUTTER_TIMESTAMP (SCHEDULER, "Event recieved"); CLUTTER_TIMESTAMP (SCHEDULER, "Event recieved");
/* TODO:
*
*/
switch (event->type) switch (event->type)
{ {
case CLUTTER_NOTHING: case CLUTTER_NOTHING:
@ -202,27 +224,145 @@ clutter_do_event (ClutterEvent *event)
case CLUTTER_DESTROY_NOTIFY: case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_DELETE: case CLUTTER_DELETE:
/* FIXME: handle delete working in stage */
if (clutter_stage_event (CLUTTER_STAGE (stage), event)) if (clutter_stage_event (CLUTTER_STAGE (stage), event))
clutter_main_quit (); clutter_main_quit ();
break; break;
case CLUTTER_KEY_PRESS: case CLUTTER_KEY_PRESS:
case CLUTTER_KEY_RELEASE: case CLUTTER_KEY_RELEASE:
{
ClutterActor *actor = NULL;
actor = clutter_stage_get_key_focus (CLUTTER_STAGE(stage));
g_return_if_fail (actor != NULL);
/* FIXME: should we ref ? */
event->key.source = actor;
/* bubble up */
do
{
clutter_actor_event (actor, event);
actor = clutter_actor_get_parent(actor);
}
while (actor != NULL);
}
break;
case CLUTTER_MOTION: case CLUTTER_MOTION:
if (context->motion_events_per_actor == FALSE)
{
/* Only stage gets motion events */
event->motion.source = stage;
clutter_actor_event (stage, event);
break;
}
case CLUTTER_BUTTON_PRESS: case CLUTTER_BUTTON_PRESS:
case CLUTTER_2BUTTON_PRESS: case CLUTTER_2BUTTON_PRESS:
case CLUTTER_3BUTTON_PRESS: case CLUTTER_3BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE: case CLUTTER_BUTTON_RELEASE:
case CLUTTER_SCROLL: case CLUTTER_SCROLL:
clutter_stage_event (CLUTTER_STAGE (stage), event); {
break; ClutterActor *actor;
gint x,y;
clutter_event_get_coords (event, &x, &y);
/* Map the event to a reactive actor */
actor = _clutter_do_pick (CLUTTER_STAGE (stage),
x, y,
CLUTTER_PICK_REACTIVE);
CLUTTER_NOTE (EVENT, "Reactive event recieved at %ix%i - actor: %p",
x, y, actor);
if (event->type == CLUTTER_SCROLL)
event->scroll.source = actor;
else
event->button.source = actor;
/* Motion enter leave events */
if (event->type == CLUTTER_MOTION)
{
if (motion_last_actor != actor)
{
if (motion_last_actor)
; /* FIXME: leave_notify to motion_last_actor */
if (actor)
; /* FIXME: Enter notify to actor */
}
motion_last_actor = actor;
}
/* Send the event to the actor and all parents always the
* 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.
*/
while (actor)
{
if (clutter_actor_is_reactive (actor)
|| clutter_actor_get_parent(actor) == NULL /* STAGE */ )
{
CLUTTER_NOTE (EVENT, "forwarding event to reactive actor");
clutter_actor_event (actor, event);
}
actor = clutter_actor_get_parent(actor);
}
}
break;
case CLUTTER_STAGE_STATE: case CLUTTER_STAGE_STATE:
/* FIXME: fullscreen / focus / mouse - forward to stage */
break;
case CLUTTER_CLIENT_MESSAGE: case CLUTTER_CLIENT_MESSAGE:
break; break;
} }
} }
ClutterActor*
_clutter_do_pick (ClutterStage *stage,
gint x,
gint y,
ClutterPickMode mode)
{
ClutterMainContext *context;
guchar pixel[4];
GLint viewport[4];
ClutterColor white = { 0xff, 0xff, 0xff, 0xff };
guint32 id;
gint r,g,b;
context = clutter_context_get_default ();
cogl_paint_init (&white);
cogl_enable (0);
/* Render the entire scence in pick mode - just single colored silhouette's
* are drawn offscreen (as we never swap buffers)
*/
context->pick_mode = mode;
clutter_actor_paint (CLUTTER_ACTOR (stage));
context->pick_mode = CLUTTER_PICK_NONE;
/* Calls should work under both GL and GLES, note GLES needs RGBA */
glGetIntegerv(GL_VIEWPORT, viewport);
glReadPixels(x, viewport[3] - y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff)
return CLUTTER_ACTOR(stage);
cogl_get_bitmasks (&r, &g, &b, NULL);
/* Decode color back into an ID, taking into account fb depth */
id = pixel[2]>>(8-b) | pixel[1]<<b>>(8-g) | pixel[0]<<(g+b)>>(8-r);
return clutter_container_find_child_by_id (CLUTTER_CONTAINER (stage), id);
}
/** /**
* clutter_main_quit: * clutter_main_quit:
* *

View File

@ -100,6 +100,11 @@ guint clutter_threads_add_timeout_full (gint priority,
gpointer data, gpointer data,
GDestroyNotify notify); GDestroyNotify notify);
void clutter_enable_motion_events (gboolean enable);
gboolean clutter_get_motion_events_enabled (void);
G_END_DECLS G_END_DECLS
#endif /* _HAVE_CLUTTER_MAIN_H */ #endif /* _HAVE_CLUTTER_MAIN_H */

View File

@ -43,6 +43,24 @@
G_BEGIN_DECLS G_BEGIN_DECLS
typedef enum {
CLUTTER_ACTOR_UNUSED_FLAG = 0,
CLUTTER_ACTOR_IN_DESTRUCTION = 1 << 0,
CLUTTER_ACTOR_IS_TOPLEVEL = 1 << 1,
CLUTTER_ACTOR_IN_REPARENT = 1 << 2,
CLUTTER_ACTOR_SYNC_MATRICES = 1 << 3 /* Used by stage to indicate GL
* viewport / perspective etc
* needs (re)setting.
*/
} ClutterPrivateFlags;
typedef enum {
CLUTTER_PICK_NONE = 0,
CLUTTER_PICK_REACTIVE,
CLUTTER_PICK_ALL
} ClutterPickMode;
typedef struct _ClutterMainContext ClutterMainContext; typedef struct _ClutterMainContext ClutterMainContext;
struct _ClutterMainContext struct _ClutterMainContext
@ -58,28 +76,16 @@ struct _ClutterMainContext
guint update_idle; guint update_idle;
guint is_initialized : 1; guint is_initialized : 1;
guint pick_mode : 1; /* Indicates pick render mode */
GTimer *timer; /* Used for debugging scheduler */ GTimer *timer; /* Used for debugging scheduler */
ClutterPickMode pick_mode; /* Indicates pick render mode */
guint motion_events_per_actor : 1;
gint num_reactives; /* Num of reactive actors */
}; };
#define CLUTTER_CONTEXT() (clutter_context_get_default ()) #define CLUTTER_CONTEXT() (clutter_context_get_default ())
ClutterMainContext *clutter_context_get_default (void); ClutterMainContext *clutter_context_get_default (void);
const gchar *clutter_vblank_method (void);
typedef enum {
CLUTTER_ACTOR_UNUSED_FLAG = 0,
CLUTTER_ACTOR_IN_DESTRUCTION = 1 << 0,
CLUTTER_ACTOR_IS_TOPLEVEL = 1 << 1,
CLUTTER_ACTOR_IN_REPARENT = 1 << 2,
CLUTTER_ACTOR_SYNC_MATRICES = 1 << 3 /* Used by stage to indicate GL
* viewport / perspective etc
* needs (re)setting.
*/
} ClutterPrivateFlags;
#define CLUTTER_PRIVATE_FLAGS(a) (CLUTTER_ACTOR ((a))->private_flags) #define CLUTTER_PRIVATE_FLAGS(a) (CLUTTER_ACTOR ((a))->private_flags)
#define CLUTTER_SET_PRIVATE_FLAGS(a,f) G_STMT_START{ (CLUTTER_PRIVATE_FLAGS (a) |= (f)); }G_STMT_END #define CLUTTER_SET_PRIVATE_FLAGS(a,f) G_STMT_START{ (CLUTTER_PRIVATE_FLAGS (a) |= (f)); }G_STMT_END
#define CLUTTER_UNSET_PRIVATE_FLAGS(a,f) G_STMT_START{ (CLUTTER_PRIVATE_FLAGS (a) &= ~(f)); }G_STMT_END #define CLUTTER_UNSET_PRIVATE_FLAGS(a,f) G_STMT_START{ (CLUTTER_PRIVATE_FLAGS (a) &= ~(f)); }G_STMT_END
@ -123,6 +129,11 @@ void _clutter_event_button_generate (ClutterBackend *backend,
void _clutter_feature_init (void); void _clutter_feature_init (void);
ClutterActor* _clutter_do_pick (ClutterStage *stage,
gint x,
gint y,
ClutterPickMode mode);
/* 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

@ -64,6 +64,7 @@ struct _ClutterStagePrivate
guint is_user_resizable : 1; guint is_user_resizable : 1;
gchar *title; gchar *title;
ClutterActor *key_focused_actor;
}; };
enum enum
@ -81,16 +82,9 @@ enum
enum enum
{ {
EVENT,
EVENT_AFTER,
BUTTON_PRESS_EVENT,
BUTTON_RELEASE_EVENT,
SCROLL_EVENT,
KEY_PRESS_EVENT,
KEY_RELEASE_EVENT,
MOTION_EVENT,
STAGE_STATE_EVENT, STAGE_STATE_EVENT,
ACTIVATE_STAGE,
DEACTIVATE_STAGE,
LAST_SIGNAL LAST_SIGNAL
}; };
@ -286,145 +280,6 @@ clutter_stage_class_init (ClutterStageClass *klass)
NULL, NULL,
CLUTTER_PARAM_READWRITE)); CLUTTER_PARAM_READWRITE));
/**
* ClutterStage::event:
* @stage: the actor which received the event
* @event: a #ClutterEvent
*
* The ::event signal is emitted each time and event is received
* by the @stage.
*/
stage_signals[EVENT] =
g_signal_new ("event",
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterStageClass, event),
NULL, NULL,
clutter_marshal_VOID__BOXED,
G_TYPE_NONE, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/**
* ClutterStage::event-after:
* @stage: the actor which received the event
* @event: a #ClutterEvent
*
* The ::event-after signal is emitted after each event, except for
* the "delete-event" is received by @stage.
*/
stage_signals[EVENT_AFTER] =
g_signal_new ("event-after",
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterStageClass, event_after),
NULL, NULL,
clutter_marshal_VOID__BOXED,
G_TYPE_NONE, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/**
* ClutterStage::button-press-event:
* @stage: the actor which received the event
* @event: a #ClutterButtonEvent
*
* The ::button-press-event signal is emitted each time a mouse button
* is pressed on @stage.
*/
stage_signals[BUTTON_PRESS_EVENT] =
g_signal_new ("button-press-event",
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterStageClass, button_press_event),
NULL, NULL,
clutter_marshal_VOID__BOXED,
G_TYPE_NONE, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/**
* ClutterStage::button-release-event:
* @stage: the actor which received the event
* @event: a #ClutterButtonEvent
*
* The ::button-release-event signal is emitted each time a mouse button
* is released on @stage.
*/
stage_signals[BUTTON_RELEASE_EVENT] =
g_signal_new ("button-release-event",
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterStageClass, button_release_event),
NULL, NULL,
clutter_marshal_VOID__BOXED,
G_TYPE_NONE, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/**
* ClutterStage::scroll-event:
* @stage: the actor which received the event
* @event: a #ClutterScrollEvent
*
* The ::scroll-event signal is emitted each time a the mouse is
* scrolled on @stage
*
* Since: 0.4
*/
stage_signals[SCROLL_EVENT] =
g_signal_new ("scroll-event",
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterStageClass, scroll_event),
NULL, NULL,
clutter_marshal_VOID__BOXED,
G_TYPE_NONE, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/**
* ClutterStage::key-press-event:
* @stage: the actor which received the event
* @event: a #ClutterKeyEvent
*
* The ::key-press-event signal is emitted each time a keyboard button
* is pressed on @stage.
*/
stage_signals[KEY_PRESS_EVENT] =
g_signal_new ("key-press-event",
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterStageClass, key_press_event),
NULL, NULL,
clutter_marshal_VOID__BOXED,
G_TYPE_NONE, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/**
* ClutterStage::key-release-event:
* @stage: the actor which received the event
* @event: a #ClutterKeyEvent
*
* The ::key-release-event signal is emitted each time a keyboard button
* is released on @stage.
*/
stage_signals[KEY_RELEASE_EVENT] =
g_signal_new ("key-release-event",
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterStageClass, key_release_event),
NULL, NULL,
clutter_marshal_VOID__BOXED,
G_TYPE_NONE, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/**
* ClutterStage::motion-event:
* @stage: the actor which received the event
* @event: a #ClutterMotionEvent
*
* The ::motion-event signal is emitted each time the mouse pointer is
* moved on @stage.
*/
stage_signals[MOTION_EVENT] =
g_signal_new ("motion-event",
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterStageClass, motion_event),
NULL, NULL,
clutter_marshal_VOID__BOXED,
G_TYPE_NONE, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
g_type_class_add_private (gobject_class, sizeof (ClutterStagePrivate)); g_type_class_add_private (gobject_class, sizeof (ClutterStagePrivate));
} }
@ -454,6 +309,9 @@ clutter_stage_init (ClutterStage *self)
priv->perspective.z_far = CLUTTER_FLOAT_TO_FIXED (100.0); priv->perspective.z_far = CLUTTER_FLOAT_TO_FIXED (100.0);
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_stage_set_key_focus (self, CLUTTER_ACTOR (self));
} }
/** /**
@ -853,40 +711,7 @@ clutter_stage_get_actor_at_pos (ClutterStage *stage,
gint x, gint x,
gint y) gint y)
{ {
ClutterMainContext *context; return _clutter_do_pick (stage, x, y, CLUTTER_PICK_ALL);
guchar pixel[4];
GLint viewport[4];
ClutterColor white = { 0xff, 0xff, 0xff, 0xff };
guint32 id;
gint r,g,b;
context = clutter_context_get_default ();
cogl_paint_init (&white);
cogl_enable (0);
/* Render the entire scence in pick mode - just single colored silhouette's
* are drawn offscreen (as we never swap buffers)
*/
context->pick_mode = TRUE;
clutter_actor_paint (CLUTTER_ACTOR (stage));
context->pick_mode = FALSE;
/* Calls should work under both GL and GLES, note GLES needs RGBA */
glGetIntegerv (GL_VIEWPORT, viewport);
glReadPixels (x, viewport[3] - y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff)
return CLUTTER_ACTOR(stage);
cogl_get_bitmasks (&r, &g, &b, NULL);
/* Decode color back into an ID, taking into account fb depth */
id = pixel[2] >> (8 - b)
| pixel[1] << b >> (8 - g)
| pixel[0] << (g + b) >> (8 - r);
return clutter_container_find_child_by_id (CLUTTER_CONTAINER (stage), id);
} }
/** /**
@ -906,64 +731,12 @@ gboolean
clutter_stage_event (ClutterStage *stage, clutter_stage_event (ClutterStage *stage,
ClutterEvent *event) ClutterEvent *event)
{ {
gboolean res = TRUE;
gint signal_num = -1;
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE); g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
g_return_val_if_fail (event != NULL, FALSE); g_return_val_if_fail (event != NULL, FALSE);
g_object_ref (stage); /* FIXME: Handle StageState Changes and Delete events */
g_signal_emit (stage, stage_signals[EVENT], 0, event); return TRUE;
switch (event->type)
{
case CLUTTER_NOTHING:
break;
case CLUTTER_BUTTON_PRESS:
case CLUTTER_2BUTTON_PRESS:
case CLUTTER_3BUTTON_PRESS:
signal_num = BUTTON_PRESS_EVENT;
break;
case CLUTTER_BUTTON_RELEASE:
signal_num = BUTTON_RELEASE_EVENT;
break;
case CLUTTER_SCROLL:
signal_num = SCROLL_EVENT;
break;
case CLUTTER_KEY_PRESS:
signal_num = KEY_PRESS_EVENT;
break;
case CLUTTER_KEY_RELEASE:
signal_num = KEY_RELEASE_EVENT;
break;
case CLUTTER_MOTION:
signal_num = MOTION_EVENT;
break;
case CLUTTER_DELETE:
signal_num = -1;
break;
case CLUTTER_STAGE_STATE:
signal_num = -1;
break;
case CLUTTER_DESTROY_NOTIFY:
signal_num = -1;
break;
case CLUTTER_CLIENT_MESSAGE:
signal_num = -1;
break;
}
if (signal_num != -1)
{
g_signal_emit (stage, stage_signals[signal_num], 0, event);
g_signal_emit (stage, stage_signals[EVENT_AFTER], 0, event);
res = TRUE;
}
g_object_unref (stage);
return res;
} }
/** /**
@ -1014,6 +787,70 @@ clutter_stage_get_title (ClutterStage *stage)
return stage->priv->title; return stage->priv->title;
} }
static void
on_key_focused_weak_notify (gpointer data,
GObject *where_the_object_was)
{
ClutterStagePrivate *priv;
ClutterStage *stage = CLUTTER_STAGE(data);
g_return_if_fail (CLUTTER_IS_STAGE (stage));
priv = stage->priv;
priv->key_focused_actor = NULL;
/* focused actor has dissapeared - fall back to stage
* FIXME: need some kind of signal dance/block here.
*/
clutter_stage_set_key_focus (stage, CLUTTER_ACTOR(stage));
}
void
clutter_stage_set_key_focus (ClutterStage *stage,
ClutterActor *actor)
{
ClutterStagePrivate *priv;
g_return_if_fail (CLUTTER_IS_STAGE (stage));
g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor));
priv = stage->priv;
if (priv->key_focused_actor == actor)
return;
if (priv->key_focused_actor)
{
g_object_weak_unref (G_OBJECT(priv->key_focused_actor),
on_key_focused_weak_notify,
stage);
g_signal_emit_by_name (G_OBJECT(priv->key_focused_actor), "focus-out");
}
priv->key_focused_actor = actor;
if (actor)
{
g_object_weak_ref (G_OBJECT(actor),
on_key_focused_weak_notify,
stage);
g_signal_emit_by_name (G_OBJECT(actor), "focus-in");
}
}
ClutterActor*
clutter_stage_get_key_focus (ClutterStage *stage)
{
ClutterStagePrivate *priv;
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
priv = stage->priv;
return priv->key_focused_actor;
}
/*** Perspective boxed type ******/ /*** Perspective boxed type ******/
/** /**

View File

@ -98,23 +98,7 @@ struct _ClutterStageClass
void (* set_user_resize) (ClutterStage *stage, void (* set_user_resize) (ClutterStage *stage,
gboolean value); gboolean value);
/* signals */ /* events */
void (* event) (ClutterStage *stage,
ClutterEvent *event);
void (* event_after) (ClutterStage *stage,
ClutterEvent *event);
void (* button_press_event) (ClutterStage *stage,
ClutterButtonEvent *event);
void (* button_release_event) (ClutterStage *stage,
ClutterButtonEvent *event);
void (* scroll_event) (ClutterStage *stage,
ClutterScrollEvent *event);
void (* key_press_event) (ClutterStage *stage,
ClutterKeyEvent *event);
void (* key_release_event) (ClutterStage *stage,
ClutterKeyEvent *event);
void (* motion_event) (ClutterStage *stage,
ClutterMotionEvent *event);
void (* stage_state_event) (ClutterStage *stage, void (* stage_state_event) (ClutterStage *stage,
ClutterStageStateEvent *event); ClutterStageStateEvent *event);
@ -192,6 +176,14 @@ void clutter_stage_set_user_resizable (ClutterStage *stage,
gboolean resizable); gboolean resizable);
gboolean clutter_stage_get_user_resizable (ClutterStage *stage); gboolean clutter_stage_get_user_resizable (ClutterStage *stage);
/* New experiental calls */
void
clutter_stage_set_key_focus (ClutterStage *stage,
ClutterActor *actor);
ClutterActor*
clutter_stage_get_key_focus (ClutterStage *stage);
G_END_DECLS G_END_DECLS
#endif /* __CLUTTER_STAGE_H__ */ #endif /* __CLUTTER_STAGE_H__ */

View File

@ -39,6 +39,9 @@ G_BEGIN_DECLS
#define CLUTTER_TYPE_PADDING (clutter_padding_get_type ()) #define CLUTTER_TYPE_PADDING (clutter_padding_get_type ())
#define CLUTTER_TYPE_VERTEX (clutter_vertex_get_type ()) #define CLUTTER_TYPE_VERTEX (clutter_vertex_get_type ())
/* Forward delarations to avoid header catch 22's */
typedef struct _ClutterActor ClutterActor;
/** /**
* ClutterGravity: * ClutterGravity:
* @CLUTTER_GRAVITY_NONE: Do not apply any gravity * @CLUTTER_GRAVITY_NONE: Do not apply any gravity

View File

@ -29,6 +29,13 @@
#include <GL/gl.h> #include <GL/gl.h>
#include <string.h> #include <string.h>
#ifdef HAVE_CLUTTER_GLX
#include <dlfcn.h>
#include <GL/glx.h>
typedef CoglFuncPtr (*GLXGetProcAddressProc) (const guint8 *procName);
#endif
static gulong __enable_flags = 0; static gulong __enable_flags = 0;
#if COGL_DEBUG #if COGL_DEBUG
@ -81,7 +88,43 @@ error_string(GLenum errorCode)
CoglFuncPtr CoglFuncPtr
cogl_get_proc_address (const gchar* name) cogl_get_proc_address (const gchar* name)
{ {
/* FIXME: This very likely needs to be handled in the backend */ /* Sucks to ifdef here but not other option..? would be nice to
* split the code up for more reuse (once more backends use this
*/
#ifdef HAVE_CLUTTER_GLX
static GLXGetProcAddressProc get_proc_func = NULL;
static void *dlhand = NULL;
if (get_proc_func == NULL && dlhand == NULL)
{
dlhand = dlopen (NULL, RTLD_LAZY);
if (dlhand)
{
dlerror ();
get_proc_func =
(GLXGetProcAddressProc) dlsym (dlhand, "glXGetProcAddress");
if (dlerror () != NULL)
{
get_proc_func =
(GLXGetProcAddressProc) dlsym (dlhand, "glXGetProcAddressARB");
}
if (dlerror () != NULL)
{
get_proc_func = NULL;
g_warning ("failed to bind GLXGetProcAddress "
"or GLXGetProcAddressARB");
}
}
}
if (get_proc_func)
return get_proc_func ((unsigned char*) name);
#endif
return NULL; return NULL;
} }

View File

@ -37,7 +37,7 @@
#include <GL/glx.h> #include <GL/glx.h>
#include <GL/gl.h> #include <GL/gl.h>
#include <dlfcn.h>
#include "clutter-backend-glx.h" #include "clutter-backend-glx.h"
#include "clutter-stage-glx.h" #include "clutter-stage-glx.h"
@ -52,8 +52,6 @@
G_DEFINE_TYPE (ClutterBackendGLX, clutter_backend_glx, CLUTTER_TYPE_BACKEND); G_DEFINE_TYPE (ClutterBackendGLX, clutter_backend_glx, CLUTTER_TYPE_BACKEND);
typedef CoglFuncPtr (*GLXGetProcAddressProc) (const guint8 *procName);
/* singleton object */ /* singleton object */
static ClutterBackendGLX *backend_singleton = NULL; static ClutterBackendGLX *backend_singleton = NULL;
@ -387,43 +385,6 @@ check_vblank_env (const char *name)
return FALSE; return FALSE;
} }
static CoglFuncPtr
get_proc_address (const gchar* name)
{
static GLXGetProcAddressProc get_proc_func = NULL;
static void *dlhand = NULL;
if (get_proc_func == NULL && dlhand == NULL)
{
dlhand = dlopen (NULL, RTLD_LAZY);
if (dlhand)
{
dlerror ();
get_proc_func =
(GLXGetProcAddressProc) dlsym (dlhand, "glXGetProcAddress");
if (dlerror () != NULL)
{
get_proc_func =
(GLXGetProcAddressProc) dlsym (dlhand, "glXGetProcAddressARB");
}
if (dlerror () != NULL)
{
get_proc_func = NULL;
g_warning ("failed to bind GLXGetProcAddress "
"or GLXGetProcAddressARB");
}
}
}
if (get_proc_func)
return get_proc_func ((unsigned char*) name);
return NULL;
}
static ClutterFeatureFlags static ClutterFeatureFlags
clutter_backend_glx_get_features (ClutterBackend *backend) clutter_backend_glx_get_features (ClutterBackend *backend)
@ -475,7 +436,7 @@ clutter_backend_glx_get_features (ClutterBackend *backend)
cogl_check_extension ("GLX_SGI_swap_control", glx_extensions)) cogl_check_extension ("GLX_SGI_swap_control", glx_extensions))
{ {
backend_glx->swap_interval = backend_glx->swap_interval =
(SwapIntervalProc) get_proc_address ("glXSwapIntervalSGI"); (SwapIntervalProc) cogl_get_proc_address ("glXSwapIntervalSGI");
CLUTTER_NOTE (BACKEND, "attempting glXSwapIntervalSGI vblank setup"); CLUTTER_NOTE (BACKEND, "attempting glXSwapIntervalSGI vblank setup");
@ -500,10 +461,10 @@ clutter_backend_glx_get_features (ClutterBackend *backend)
CLUTTER_NOTE (BACKEND, "attempting glXGetVideoSyncSGI vblank setup"); CLUTTER_NOTE (BACKEND, "attempting glXGetVideoSyncSGI vblank setup");
backend_glx->get_video_sync = backend_glx->get_video_sync =
(GetVideoSyncProc) get_proc_address ("glXGetVideoSyncSGI"); (GetVideoSyncProc) cogl_get_proc_address ("glXGetVideoSyncSGI");
backend_glx->wait_video_sync = backend_glx->wait_video_sync =
(WaitVideoSyncProc) get_proc_address ("glXWaitVideoSyncSGI"); (WaitVideoSyncProc) cogl_get_proc_address ("glXWaitVideoSyncSGI");
if ((backend_glx->get_video_sync != NULL) && if ((backend_glx->get_video_sync != NULL) &&
(backend_glx->wait_video_sync != NULL)) (backend_glx->wait_video_sync != NULL))

View File

@ -1,11 +1,37 @@
#include <clutter/clutter.h> #include <clutter/clutter.h>
void
key_focus_in_cb (ClutterActor *actor,
gpointer data)
{
ClutterActor *focus_box = CLUTTER_ACTOR(data);
if (actor == clutter_stage_get_default ())
{
clutter_actor_hide (focus_box);
}
else
{
clutter_actor_show (focus_box);
clutter_actor_set_position (focus_box,
clutter_actor_get_x (actor) - 5,
clutter_actor_get_y (actor) - 5);
clutter_actor_set_size (focus_box,
clutter_actor_get_width (actor) + 10,
clutter_actor_get_height (actor) + 10);
}
}
static void static void
input_cb (ClutterStage *stage, input_cb (ClutterActor *actor,
ClutterEvent *event, ClutterEvent *event,
gpointer data) gpointer data)
{ {
gchar keybuf[9];
gchar keybuf[9], *source = (gchar*)data;
int len = 0; int len = 0;
switch (event->type) switch (event->type)
@ -14,58 +40,126 @@ input_cb (ClutterStage *stage,
len = g_unichar_to_utf8 (clutter_keysym_to_unicode (event->key.keyval), len = g_unichar_to_utf8 (clutter_keysym_to_unicode (event->key.keyval),
keybuf); keybuf);
keybuf[len] = '\0'; keybuf[len] = '\0';
printf ("- KEY PRESS '%s'\n", keybuf); printf ("[%s] KEY PRESS '%s'", source, keybuf);
break; break;
case CLUTTER_KEY_RELEASE: case CLUTTER_KEY_RELEASE:
len = g_unichar_to_utf8 (clutter_keysym_to_unicode (event->key.keyval), len = g_unichar_to_utf8 (clutter_keysym_to_unicode (event->key.keyval),
keybuf); keybuf);
keybuf[len] = '\0'; keybuf[len] = '\0';
printf ("- KEY RELEASE '%s'\n", keybuf); printf ("[%s] KEY RELEASE '%s'", source, keybuf);
break; break;
case CLUTTER_MOTION: case CLUTTER_MOTION:
printf("- MOTION\n"); printf("[%s] MOTION", source);
break; break;
case CLUTTER_BUTTON_PRESS: case CLUTTER_BUTTON_PRESS:
printf("- BUTTON PRESS\n"); printf("[%s] BUTTON PRESS", source);
break; break;
case CLUTTER_2BUTTON_PRESS: case CLUTTER_2BUTTON_PRESS:
printf("- BUTTON 2 PRESS\n"); printf("[%s] BUTTON 2 PRESS", source);
break; break;
case CLUTTER_3BUTTON_PRESS: case CLUTTER_3BUTTON_PRESS:
printf("- BUTTON 3 PRESS\n"); printf("[%s] BUTTON 3 PRESS", source);
break; break;
case CLUTTER_BUTTON_RELEASE: case CLUTTER_BUTTON_RELEASE:
printf("- BUTTON RELEASE\n"); printf("[%s] BUTTON RELEASE", source);
if (clutter_event_get_source (event) == actor)
clutter_stage_set_key_focus
(CLUTTER_STAGE(clutter_stage_get_default ()), actor);
break; break;
case CLUTTER_SCROLL: case CLUTTER_SCROLL:
printf("- BUTTON SCROLL\n"); printf("[%s] BUTTON SCROLL", source);
break; break;
case CLUTTER_STAGE_STATE: case CLUTTER_STAGE_STATE:
printf("- STAGE STATE\n"); printf("[%s] STAGE STATE", source);
break; break;
case CLUTTER_DESTROY_NOTIFY: case CLUTTER_DESTROY_NOTIFY:
printf("- DESTROY NOTIFY\n"); printf("[%s] DESTROY NOTIFY", source);
break; break;
case CLUTTER_CLIENT_MESSAGE: case CLUTTER_CLIENT_MESSAGE:
printf("- CLIENT MESSAGE\n"); printf("[%s] CLIENT MESSAGE\n", source);
break; break;
case CLUTTER_DELETE: case CLUTTER_DELETE:
printf("- DELETE\n"); printf("[%s] DELETE", source);
break; break;
case CLUTTER_NOTHING: case CLUTTER_NOTHING:
break; return;
} }
if (clutter_event_get_source (event) == actor)
printf(" *source*");
printf("\n");
} }
int int
main (int argc, char *argv[]) main (int argc, char *argv[])
{ {
ClutterActor *stage; ClutterActor *stage, *actor, *focus_box;
ClutterColor rcol = { 0xff, 0, 0, 0xff},
bcol = { 0, 0, 0xff, 0xff },
gcol = { 0, 0xff, 0, 0xff },
ncol = { 0, 0, 0, 0xff };
clutter_init (&argc, &argv); clutter_init (&argc, &argv);
stage = clutter_stage_get_default (); stage = clutter_stage_get_default ();
g_signal_connect (stage, "event", G_CALLBACK (input_cb), NULL); g_signal_connect (stage, "event", G_CALLBACK (input_cb), "stage");
focus_box = clutter_rectangle_new_with_color (&ncol);
clutter_container_add (CLUTTER_CONTAINER(stage), focus_box, NULL);
actor = clutter_rectangle_new_with_color (&rcol);
clutter_actor_set_size (actor, 100, 100);
clutter_actor_set_position (actor, 100, 100);
clutter_actor_set_reactive (actor);
clutter_container_add (CLUTTER_CONTAINER(stage), actor, NULL);
g_signal_connect (actor, "event", G_CALLBACK (input_cb), "red box");
g_signal_connect (actor, "focus-in", G_CALLBACK (key_focus_in_cb),
focus_box);
clutter_stage_set_key_focus (stage, actor);
actor = clutter_rectangle_new_with_color (&gcol);
clutter_actor_set_size (actor, 100, 100);
clutter_actor_set_position (actor, 250, 100);
clutter_actor_set_reactive (actor);
clutter_container_add (CLUTTER_CONTAINER(stage), actor, NULL);
g_signal_connect (actor, "event", G_CALLBACK (input_cb), "green box");
g_signal_connect (actor, "focus-in", G_CALLBACK (key_focus_in_cb),
focus_box);
actor = clutter_rectangle_new_with_color (&bcol);
clutter_actor_set_size (actor, 100, 100);
clutter_actor_set_position (actor, 400, 100);
clutter_actor_set_reactive (actor);
clutter_container_add (CLUTTER_CONTAINER(stage), actor, NULL);
g_signal_connect (actor, "event", G_CALLBACK (input_cb), "blue box");
g_signal_connect (actor, "focus-in", G_CALLBACK (key_focus_in_cb),
focus_box);
actor = clutter_rectangle_new_with_color (&ncol);
clutter_actor_set_size (actor, 400, 50);
clutter_actor_set_position (actor, 100, 250);
clutter_container_add (CLUTTER_CONTAINER(stage), actor, NULL);
g_signal_connect (actor, "event", G_CALLBACK (input_cb), "blue box");
g_signal_connect (actor, "focus-in", G_CALLBACK (key_focus_in_cb),
focus_box);
g_signal_connect (stage, "focus-in", G_CALLBACK (key_focus_in_cb),
focus_box);
clutter_actor_show_all (CLUTTER_ACTOR (stage)); clutter_actor_show_all (CLUTTER_ACTOR (stage));
clutter_main(); clutter_main();