diff --git a/doc/cookbook/clutter-cookbook.xml.in b/doc/cookbook/clutter-cookbook.xml.in
index 0146bfadb..e6c9297de 100644
--- a/doc/cookbook/clutter-cookbook.xml.in
+++ b/doc/cookbook/clutter-cookbook.xml.in
@@ -386,6 +386,300 @@ on_paint (ClutterActor *actor)
+
+ Events
+
+
+
+
+
+
+
+ Introduction
+ introduction
+
+
+
+ Handling key events
+
+
+ Problem
+ You want to respond to key presses on an actor.
+
+
+
+ Solutions
+
+ There are two possible solutions:
+
+
+
+ Solution 1: Connect a callback to the
+ actor; inside the callback, manually analyse which key and
+ modifier(s) were pressed and react accordingly.
+
+
+ Solution 2: Use an actor's
+ ClutterBindingPool to declaratively assign actions to specific
+ key and modifier combinations.
+
+
+
+ Each solution is covered below.
+
+
+ Solution 1
+
+ Connect the key-press-event signal for an actor to a callback;
+ then examine the event in the callback to determine which key and
+ modifiers were pressed.
+
+ First, connect an actor's key-press-event signal
+ to a callback:
+
+
+
+g_signal_connect (actor,
+ "key-press-event",
+ G_CALLBACK (_key_press_cb),
+ NULL);
+
+
+
+ Then, in the callback, check which key was pressed and which
+ modifiers were down at the same time. For example, this callback
+ checks for a press on the up arrow key and whether
+ the Shift and/or Control key were down:
+
+
+
+static void
+_key_press_cb (ClutterActor *actor,
+ ClutterEvent *event,
+ gpointer user_data)
+{
+ guint keyval = clutter_event_get_key_symbol (event);
+
+ if (CLUTTER_Up == keyval)
+ {
+ ClutterModifierType modifiers = clutter_event_get_state (event);
+
+ switch (modifiers)
+ {
+ case CLUTTER_SHIFT_MASK:
+ g_debug ("Up and shift pressed");
+ break;
+
+ case CLUTTER_SHIFT_MASK + CLUTTER_CONTROL_MASK:
+ g_debug ("Up and shift and control pressed");
+ break;
+
+ default:
+ g_debug ("Up pressed");
+ break;
+ }
+ }
+}
+
+
+
+ Note that Clutter provides a range of key value definitions
+ (like CLUTTER_Up, used above). These are generated from the list in the
+ X.Org source code
+ (replace "XK" with "CLUTTER" in the definitions there to get the
+ CLUTTER equivalents; alternatively, look at the clutter-keysyms.h
+ header file for the list).
+
+ CLUTTER_SHIFT_MASK, CLUTTER_CONTROL_MASK and other modifiers are
+ defined in the ClutterModifierType enum.
+
+
+
+
+ Solution 2
+
+ Assign actions to an actor's ClutterBindingPool.
+ A binding pool stores mappings from a key press (either a single key
+ or a key plus modifiers) to actions; an action is simply a callback
+ function with a specific signature.
+
+ While this approach is trickier to implement, it is more
+ flexible and removes the drudgery of writing branching code to
+ handle different key presses. See the Discussion section for
+ more details.
+
+ To use this approach with an actor which will receive key press
+ events, first get that actor's binding pool. In the example below,
+ we're using the binding pool for the default ClutterStage:
+
+
+
+ClutterBindingPool *binding_pool;
+binding_pool = clutter_binding_pool_get_for_class (CLUTTER_STAGE_GET_CLASS (stage));
+
+
+
+ Next, install actions into the binding pool. For example, to
+ install an action bound to the up arrow key, which calls the _move_up
+ function when that key is pressed, you would do:
+
+
+
+clutter_binding_pool_install_action (binding_pool,
+ "move-up", /* identifier */
+ CLUTTER_Up, /* up arrow pressed */
+ 0, /* no modifiers pressed */
+ G_CALLBACK (_move_up),
+ NULL, /* no user data passed */
+ NULL);
+
+
+
+ Another example, binding up + Shift + Control to an action which
+ calls _move_up_shift_control when activated:
+
+
+
+clutter_binding_pool_install_action (binding_pool,
+ "move-up-shift-control",
+ CLUTTER_Up,
+ CLUTTER_SHIFT_MASK + CLUTTER_CONTROL_MASK,
+ G_CALLBACK (_move_up_shift_control),
+ NULL,
+ NULL);
+
+
+
+ The function called when an action is activated looks like this
+ (for _move_up):
+
+
+
+static void
+_move_up (GObject *instance,
+ const gchar *action_name,
+ guint key_val,
+ ClutterModifierType modifiers,
+ gpointer user_data)
+{
+ g_debug ("Up pressed");
+}
+
+
+
+ Then bind the key-press-event for the actor (in our case,
+ the stage) to a callback:
+
+
+
+g_signal_connect (stage,
+ "key-press-event",
+ G_CALLBACK (_key_press_cb),
+ NULL);
+
+
+
+ Finally, inside the callback, pass control to the actor's
+ binding pool rather than dissecting the key press event
+ yourself:
+
+
+
+static gboolean
+_key_press_cb (ClutterActor *actor,
+ ClutterEvent *event,
+ gpointer user_data)
+{
+ ClutterBindingPool *pool;
+
+ pool = clutter_binding_pool_find (G_OBJECT_TYPE_NAME (actor));
+
+ return clutter_binding_pool_activate (pool,
+ clutter_event_get_key_symbol (event),
+ clutter_event_get_state (event),
+ G_OBJECT (actor));
+}
+
+
+
+ Now, when a key plus modifiers that has been bound to an action
+ is pressed on the actor, the appropriate action is activated.
+
+
+
+
+
+ Discussion
+
+
+ Pros and cons of Solution 1 and Solution 2
+
+ Solution 1 is the simplest (in terms of the amount of code you
+ have to write for simple cases), but could quickly turn into a mess if
+ you need many conditions or want to capture many key combinations.
+ Also, if multiple actors need to respond to key press events, you'll
+ need similar event dissection code in each callback.
+
+ Solution 2 is more complicated to implement, but scales better
+ if you have many different key combinations on multiple actors.
+ The binding pool protects you from the minutiae of detecting which
+ keys were pressed, leaving you to concentrate on the
+ triggered actions instead. This could simplify your control
+ logic.
+
+ In addition, Solution 2 lets you write a single callback to
+ handle all key press events for all actors. This callback could then
+ use clutter_binding_pool_find (as in the example code) to determine
+ which binding pool to activate (depending on which actor received the
+ key press event).
+
+ Finally, a binding pool allows you to block and unblock actions.
+ This means you can make the response to a key press event conditional
+ on application state. For example, let's say you wanted the up arrow
+ key to move an actor, but only when the actor is at the bottom
+ of the stage. To implement this, you could disable the up arrow key
+ action in the binding pool initially; then, once the actor reaches the
+ bottom of the stage, enable the up arrow key action again. While this
+ is possible with Solution 1, you would have to implement more of the
+ state management code yourself.
+
+
+
+ Other useful things to know about key press events
+
+
+
+ A ClutterKeyEvent contains only a single
+ key value, plus possibly one or more modifier keys (like Shift,
+ Control, Alt etc.). There are no functions in the
+ Clutter API which return events for tracking near-simultaneous
+ presses on multiple keys.
+
+
+
+ By default, the stage receives all key events.
+ To make another actor receive key events, use
+ clutter_stage_set_key_focus:
+
+
+
+/*
+ * stage is a ClutterStage instance;
+ * actor is the ClutterActor instance which should receive key events
+ */
+clutter_stage_set_key_focus (stage, actor);
+
+
+
+
+
+
+
+
+
+
+
+
Textures