diff --git a/doc/cookbook/Makefile.am b/doc/cookbook/Makefile.am
index e06e0cc10..5aa3a0456 100644
--- a/doc/cookbook/Makefile.am
+++ b/doc/cookbook/Makefile.am
@@ -1,10 +1,21 @@
+NULL =
+
HTML_DIR = $(datadir)/gtk-doc/html
TARGET_DIR = $(HTML_DIR)/clutter-cookbook
+XML_FILES = \
+ actors.xml \
+ animations.xml \
+ events.xml \
+ introduction.xml \
+ recipe-template.xml \
+ textures.xml \
+ $(NULL)
+
HTML_FILES = html/*.html
IMAGE_FILES = images/clutter-logo.png
-EXTRA_DIST = clutter-cookbook.xml.in $(IMAGE_FILES)
+EXTRA_DIST = clutter-cookbook.xml.in $(IMAGE_FILES) $(XML_FILES)
CLEANFILES = \
pdf-build.stamp \
diff --git a/doc/cookbook/actors.xml b/doc/cookbook/actors.xml
new file mode 100644
index 000000000..815f9d27a
--- /dev/null
+++ b/doc/cookbook/actors.xml
@@ -0,0 +1,260 @@
+
+
+
+ Actors
+
+
+ Edmon Gween, actor, on his deathbed
+ An actor's a guy who if you ain't talkin' about him, ain't
+ listening.
+
+
+
+ Introduction
+
+ When building a User Interface with Clutter, the visible part
+ of the UI — that is, what is displayed on the screen — is
+ commonly referred to as "the scene graph". Like every graph, a scene
+ graph is composed by nodes.
+
+ Every node on the Clutter scene graph is an
+ actor. Every actor has a single relationship
+ with the others: it can be the parent of another actor, or a child of
+ another actor.
+
+ The Stage is an actor that can have children but cannot have
+ any parent.
+
+ Actors have different attributes: a position, a size, a
+ scale factor, a rotation angle on each axis (relative to a specific
+ center on the normal plane for that axis), an opacity factor.
+
+ The scene graph is not fixed: it can be changed, not only
+ by adding or removing actors, but also by changing the parent-child
+ relationship: it is possible, for instance, to move an entire
+ section of the scene graph from one parent actor to another.
+
+
+
+
+ Knowing when an actor position or size change
+
+
+ Problem
+
+ You want to know when the position or the size, or
+ both, of an actor change, for instance to update an unrelated
+ actor or some internal state.
+
+
+
+ Solution
+
+ You can use the notify signal,
+ detailed with the coordinate or the dimension you want
+ to know has changed:
+
+
+
+g_signal_connect (actor, "notify::x",
+ G_CALLBACK (on_x_changed),
+ NULL);
+g_signal_connect (actor, "notify::height",
+ G_CALLBACK (on_height_changed),
+ NULL);
+g_signal_connect (actor, "notify::depth",
+ G_CALLBACK (on_depth_changed),
+ NULL);
+
+
+
+ If you want to know if any of the coordinates or dimensions of
+ an actor have been changed, except for depth, you can use the
+ allocation-changed signal:
+
+
+
+g_signal_connect (actor, "allocation-changed",
+ G_CALLBACK (on_allocation_changed),
+ NULL);
+
+
+
+ The signature for the handler of the "notify" signal is:
+
+
+
+void
+on_notify (GObject *gobject,
+ GParamSpec *pspec,
+ gpointer user_data);
+
+
+
+ While the signature for the handler of the "allocation-changed"
+ signal is:
+
+
+
+void
+on_allocation_changed (ClutterActor *actor,
+ const ClutterActorBox *allocation,
+ ClutterAllocationFlags flags,
+ gpointer user_data);
+
+
+
+
+
+
+ Discussion
+
+ Any change the position and size of an actor will cause a
+ change in the allocation of the actor itself. This will update the
+ values of the :x, :y, :width and :height properties as well.
+
+ The first technique allows a greater deal of granularity,
+ allowing you to know what exactly changed. Inside the callback
+ for the signal you can query the value of the property:
+
+
+
+void
+on_x_changed (GObject *gobject,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+gint x_value = 0;
+
+/* Round the X coordinate to the nearest pixel */
+x_value = floorf (clutter_actor_get_x (CLUTTER_ACTOR (gobject))) + 0.5;
+
+g_print ("The new X coordinate is '%d' pixels\n", x_value);
+}
+
+
+
+ The second technique is more indicated if you want to
+ get notification that any of the positional or dimensional
+ attributes changed, except for the depth:
+
+
+
+void
+on_allocation_changed (ClutterActor *actor,
+ const ClutterActorBox *allocation,
+ ClutterAllocationFlags flags,
+ gpointer user_data)
+{
+ClutterActor *actor = CLUTTER_ACTOR (gobject);
+
+g_print ("The bounding box is now: (%.2f, %.2f) (%.2f x %.2f)\n",
+ clutter_actor_box_get_x (allocation),
+ clutter_actor_box_get_y (allocation),
+ clutter_actor_box_get_width (allocation),
+ clutter_actor_box_get_height (allocation));
+}
+
+
+
+ All actors will update these properties when their size
+ or position change.
+
+ Note that the Stage, on the other hand, will not notify on
+ position changes, so it is not possible to use the :x and :y
+ properties to know that the platform-specific window embedding the
+ stage has been moved — if the platform supports a windowing
+ system. In order to achieve that you will have to use backend-specific
+ API to extract the surface used by the Stage and then platform-specific
+ API to retrieve its coordinates.
+
+
+
+
+
+
+ Overriding the paint sequence
+
+
+ Problem
+
+ You want to override the way an actor paints itself
+ without creating a subclass.
+
+
+
+ Solution
+
+ You can use the paint signal to
+ invoke a callback that will be executed before the actor's
+ paint implementation:
+
+
+
+g_signal_connect (actor, "paint", G_CALLBACK (on_paint), NULL);
+
+
+
+ You can paint something after the actor's paint implementation
+ by using the g_signal_connect_after() function
+ instead of g_signal_connect():
+
+
+
+g_signal_connect_after (actor, "paint", G_CALLBACK (on_paint_after), NULL);
+
+
+
+ The signature for the handler of the "paint" signal is:
+
+
+
+void on_paint (ClutterActor *actor, gpointer user_data);
+
+
+
+
+
+
+ Discussion
+
+ The paint cycle in Clutter works its way recursively from the
+ Stage through every child.
+
+ Whenever an Actor is going to be painted it will be positioned in
+ a new frame of reference according to the list of transformations
+ (scaling, rotation and additional traslations). After that, the "paint"
+ signal will be emitted.
+
+ The "paint" signal is defined as run-last,
+ that is the signal handlers connected to it using
+ g_signal_connetc() will be called first; then the
+ default handler defined by the Actor's sub-class will be called;
+ finally, all the signal handlers connected to the signal using
+ g_signal_connect_after() will be called.
+
+ This allows pre- and post-default paint handlers, and it also
+ allows completely overriding the way an Actor draws itself by default;
+ for instance:
+
+
+
+void
+on_paint (ClutterActor *actor)
+{
+do_my_paint (actor);
+
+g_signal_stop_emission_by_name (actor, "paint");
+}
+
+
+
+ The code above will prevent the default paint implementation of
+ the actor from running.
+
+
+
+
+
+
diff --git a/doc/cookbook/animations.xml b/doc/cookbook/animations.xml
new file mode 100644
index 000000000..1c310060a
--- /dev/null
+++ b/doc/cookbook/animations.xml
@@ -0,0 +1,42 @@
+
+
+
+ Animations
+
+
+ the author of the epigraph
+ a short epigraph
+
+
+
+ Introduction
+
+ introduction
+
+
+
+ Inverting Animations
+
+
+ Problem
+
+ You want to have an animation exactly mirroring another one
+ that you just played.
+
+
+
+
+
+
+
+
+
diff --git a/doc/cookbook/clutter-cookbook.xml.in b/doc/cookbook/clutter-cookbook.xml.in
index 880ca7bf0..f6d858387 100644
--- a/doc/cookbook/clutter-cookbook.xml.in
+++ b/doc/cookbook/clutter-cookbook.xml.in
@@ -9,1254 +9,42 @@
]>
-
-
+
-
-
Emmanuele
Bassi
&ebassi_mail;
-
Elliot
Smith
&elliot_mail;
-
-
2009, 2010
Intel Corporation
-
Permission is granted to copy, distribute and/or modify this
document under the terms of the Creative
Commons Attribution-Non-Commercial-Share Alike 2.0 UK: England &
Wales as published by Creative Commons.
-
The Clutter Cookbook
for Clutter &apiversion;
-
- Preface
-
-
- The Perl Cookbook
- Let me show you that easy way, so others may easily follow.
-
-
- There is a wonderful simile in the preface of the Perl
- Cookbook: approaching a programming problem is oftentimes
- similar to balancing Columbus's egg. The initial difficulties of dealing
- with, and more importantly solving, problems in the computer programming
- field sometimes can only be overcome if somebody shows you how to use a
- new tool. This is true for programming languages but also for programming
- libraries.
-
- This book has been written to try and give you a reference on
- how to solve common issues that you might have to face when using
- the Clutter toolkit.
-
- This book is not meant to be a replacement for the API reference,
- even though there will be descriptions of how Clutter works and how
- its API looks like. We will require knowledge of the Clutter API, but
- we will also point out where to find more information on the API that
- examples have used.
-
- Indeed, this book should be used as a companion to the API reference,
- expanding the examples and showing how to achieve a specific result.
-
- This is not a book for learning Clutter. This is also not a book
- for learning C, or GObject or even GUI development.
-
- Above all, this is a book for learning more
- about Clutter, and about how to use it in the most efficient and easiest
- way. It is meant to help you move past the basic usage of Clutter.
-
- This book is divided into chapters. Each chapter is dedicated to
- a specific class, like ClutterTexture, or a specific area, like animations.
- Each chapter starts with a short introduction, followed by different
- recipes. Each recipe starts with a problem, or a short
- statement describing what we want to achieve; a solution, containing the
- source code; and a discussion section, where the code is explained, where
- alternative approaches might be useful, caveats and references to the
- Clutter API for furher studying.
-
- This book, in the cookbook spirit, can be accessed mostly at
- random.
-
-
- About Clutter
-
- Clutter is an free and open source software library for creating
- portable, dynamic, compelling and fast graphical user interfaces.
-
- Clutter uses OpenGL (and, optionally, OpenGL ES on mobile and
- embedded platforms) for rendering the user interface elements, but
- at the same time it exposes an application program interface that hides
- the underlying complexity of the OpenGL state machine from the
- developer.
-
- The program interface of Clutter is intended to be easy to use,
- efficient, flexible and as self-documenting as possible.
-
-
-
- About this document
-
- This document is available in various formats like HTML, and
- PDF.
-
- The latest version is always available at
- &docurl;.
-
-
-
-
- Acknowledgments
-
- This book has been written taking the inspiration from the Perl
- Cookbook, authored by Tom Christiansen and Nathan Torkington.
-
-
-
-
- Where to get Clutter
-
- You can obtain Clutter from &appurl;.
-
- Clutter is also available on all major GNU/Linux distributions,
- in various package formats.
-
- On OSX, Clutter is available with both Fink and MacPorts.
-
- Binaries for Microsoft Windows are also available.
-
-
-
-
-
- Actors
-
-
- Edmon Gween, actor, on his deathbed
- An actor's a guy who if you ain't talkin' about him, ain't
- listening.
-
-
-
- Introduction
-
- When building a User Interface with Clutter, the visible part
- of the UI — that is, what is displayed on the screen — is
- commonly referred to as "the scene graph". Like every graph, a scene
- graph is composed by nodes.
-
- Every node on the Clutter scene graph is an
- actor. Every actor has a single relationship
- with the others: it can be the parent of another actor, or a child of
- another actor.
-
- The Stage is an actor that can have children but cannot have
- any parent.
-
- Actors have different attributes: a position, a size, a
- scale factor, a rotation angle on each axis (relative to a specific
- center on the normal plane for that axis), an opacity factor.
-
- The scene graph is not fixed: it can be changed, not only
- by adding or removing actors, but also by changing the parent-child
- relationship: it is possible, for instance, to move an entire
- section of the scene graph from one parent actor to another.
-
-
-
-
- Knowing when an actor position or size change
-
-
- Problem
-
- You want to know when the position or the size, or
- both, of an actor change, for instance to update an unrelated
- actor or some internal state.
-
-
-
- Solution
-
- You can use the notify signal,
- detailed with the coordinate or the dimension you want
- to know has changed:
-
-
-
-g_signal_connect (actor, "notify::x",
- G_CALLBACK (on_x_changed),
- NULL);
-g_signal_connect (actor, "notify::height",
- G_CALLBACK (on_height_changed),
- NULL);
-g_signal_connect (actor, "notify::depth",
- G_CALLBACK (on_depth_changed),
- NULL);
-
-
-
- If you want to know if any of the coordinates or dimensions of
- an actor have been changed, except for depth, you can use the
- allocation-changed signal:
-
-
-
-g_signal_connect (actor, "allocation-changed",
- G_CALLBACK (on_allocation_changed),
- NULL);
-
-
-
- The signature for the handler of the "notify" signal is:
-
-
-
-void
-on_notify (GObject *gobject,
- GParamSpec *pspec,
- gpointer user_data);
-
-
-
- While the signature for the handler of the "allocation-changed"
- signal is:
-
-
-
-void
-on_allocation_changed (ClutterActor *actor,
- const ClutterActorBox *allocation,
- ClutterAllocationFlags flags,
- gpointer user_data);
-
-
-
-
-
-
- Discussion
-
- Any change the position and size of an actor will cause a
- change in the allocation of the actor itself. This will update the
- values of the :x, :y, :width and :height properties as well.
-
- The first technique allows a greater deal of granularity,
- allowing you to know what exactly changed. Inside the callback
- for the signal you can query the value of the property:
-
-
-
-void
-on_x_changed (GObject *gobject,
- GParamSpec *pspec,
- gpointer user_data)
-{
- gint x_value = 0;
-
- /* Round the X coordinate to the nearest pixel */
- x_value = floorf (clutter_actor_get_x (CLUTTER_ACTOR (gobject))) + 0.5;
-
- g_print ("The new X coordinate is '%d' pixels\n", x_value);
-}
-
-
-
- The second technique is more indicated if you want to
- get notification that any of the positional or dimensional
- attributes changed, except for the depth:
-
-
-
-void
-on_allocation_changed (ClutterActor *actor,
- const ClutterActorBox *allocation,
- ClutterAllocationFlags flags,
- gpointer user_data)
-{
- ClutterActor *actor = CLUTTER_ACTOR (gobject);
-
- g_print ("The bounding box is now: (%.2f, %.2f) (%.2f x %.2f)\n",
- clutter_actor_box_get_x (allocation),
- clutter_actor_box_get_y (allocation),
- clutter_actor_box_get_width (allocation),
- clutter_actor_box_get_height (allocation));
-}
-
-
-
- All actors will update these properties when their size
- or position change.
-
- Note that the Stage, on the other hand, will not notify on
- position changes, so it is not possible to use the :x and :y
- properties to know that the platform-specific window embedding the
- stage has been moved — if the platform supports a windowing
- system. In order to achieve that you will have to use backend-specific
- API to extract the surface used by the Stage and then platform-specific
- API to retrieve its coordinates.
-
-
-
-
-
-
- Overriding the paint sequence
-
-
- Problem
-
- You want to override the way an actor paints itself
- without creating a subclass.
-
-
-
- Solution
-
- You can use the paint signal to
- invoke a callback that will be executed before the actor's
- paint implementation:
-
-
-
-g_signal_connect (actor, "paint", G_CALLBACK (on_paint), NULL);
-
-
-
- You can paint something after the actor's paint implementation
- by using the g_signal_connect_after() function
- instead of g_signal_connect():
-
-
-
-g_signal_connect_after (actor, "paint", G_CALLBACK (on_paint_after), NULL);
-
-
-
- The signature for the handler of the "paint" signal is:
-
-
-
-void on_paint (ClutterActor *actor, gpointer user_data);
-
-
-
-
-
-
- Discussion
-
- The paint cycle in Clutter works its way recursively from the
- Stage through every child.
-
- Whenever an Actor is going to be painted it will be positioned in
- a new frame of reference according to the list of transformations
- (scaling, rotation and additional traslations). After that, the "paint"
- signal will be emitted.
-
- The "paint" signal is defined as run-last,
- that is the signal handlers connected to it using
- g_signal_connetc() will be called first; then the
- default handler defined by the Actor's sub-class will be called;
- finally, all the signal handlers connected to the signal using
- g_signal_connect_after() will be called.
-
- This allows pre- and post-default paint handlers, and it also
- allows completely overriding the way an Actor draws itself by default;
- for instance:
-
-
-
-void
-on_paint (ClutterActor *actor)
-{
- do_my_paint (actor);
-
- g_signal_stop_emission_by_name (actor, "paint");
-}
-
-
-
- The code above will prevent the default paint implementation of
- the actor from running.
-
-
-
-
-
-
-
- Events
-
-
- The Tenth Doctor (David Tennant)
- Crossing into established events is strictly forbidden. Except for
- cheap tricks.
-
-
-
- Introduction
- Once you have set up a scene on the stage, in order to respond
- to user interaction you will have to handle events coming from the
- underlying platform.
-
- Events are relayed to actors by Clutter in form of
- signals; signals are a facility provided by the
- GObject framework to call functions depending on a unique name. A signal
- can be thought as a message that an object instance broadcasts to various
- listener functions.
-
- There are various events that Clutter will handle: mostly, they
- deal with input devices, like a mouse pointer or a keyboard; but they can
- also come from the windowing system, like the
- delete-event signal that is emitted when the user
- closes the window of the stage.
-
- Each event has a particular source, that is
- the actor that received the event. The event handling sequence is divided
- in two phases:
-
-
- the capture phase, which consists
- in an emission of the captured-event signal
- starting from the stage to, following the parent-child relationship,
- the source of the event;
- the bubble phase, which consists
- in an emission of the event signal starting from
- the the source of the event to, following the parent-child
- relationship, the stage.
-
-
- At any point during the event emission sequence a handler of either
- the captured-event or the event signals can stop it, by returning a value
- of TRUE, which means that the event has been handled. If an event hasn't
- been handled, FALSE should be returned instead.
-
-
-
- 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 gboolean
-_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;
- }
-
- /* The event was handled, and the emission should stop */
- return TRUE;
- }
-
- /* The event was not handled, and the emission should continue */
- return FALSE;
-}
-
-
-
- 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;
-GObjectClass *stage_class;
-
-stage_class = CLUTTER_STAGE_GET_CLASS (stage);
-binding_pool = clutter_binding_pool_get_for_class (stage_class);
-
-
-
- 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
-
-
- the author of the epigraph
- a short epigraph
-
-
-
- Introduction
-
- introduction
-
-
-
- Drawing 2D graphics onto a texture
-
-
- Problem
-
- You want to draw 2D graphics inside a Clutter application.
-
-
-
- Solution
-
- Create a ClutterCairoTexture, then draw onto the Cairo context
- it wraps using the Cairo API:
-
-
-
-ClutterActor *texture;
-cairo_t *cr;
-
-guint width, height;
-width = 800;
-height = 600;
-
-texture = clutter_cairo_texture_new (width, height);
-
-cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (texture));
-
-/*
- * write onto the Cairo context cr using the Cairo API;
- * see the Cairo API reference for details
- */
-cairo_move_to (cr, 0, 0);
-cairo_line_to (cr, 800, 600);
-cairo_stroke (cr);
-
-/* does the actual drawing onto the texture */
-cairo_destroy (cr);
-
-
-
- Here's a useful
- Cairo tutorial if you want to learn more about the Cairo API
- itself.
-
-
-
- Discussion
-
- A ClutterCairoTexture is a standard ClutterActor, so it can be
- added to ClutterContainers (e.g. a ClutterStage or ClutterGroup),
- animated, resized etc. in the usual ways.
-
- Other useful operations:
-
-
-
-
- To draw on part of the texture:
- use clutter_cairo_texture_create_region to
- retrieve a Cairo context for the region you want to draw on.
-
-
-
- To clear existing content from a texture:
- use clutter_cairo_texture_clear.
-
- You may need to do this as the texture reuses the same
- Cairo context each time you call
- clutter_cairo_texture_create or
- clutter_cairo_texture_create_region.
-
-
-
- To resize the Cairo context wrapped
- by a texture, use
- clutter_cairo_texture_set_surface_size.
-
-
-
-
-
- Drawing pages from a PDF onto a ClutterCairoContext
-
- Other libraries may provide an API for writing onto a
- Cairo context; you can make use of these APIs on the exposed
- Cairo context of a ClutterCairoTexture. For example, you
- can use the poppler-glib API to display pages
- from a PopplerDocument inside a Clutter application:
-
-
-
-
-
-/* snipped setup code (as above) */
-
-/*
- * cast to CLUTTER_CAIRO_TEXTURE, as the functions
- * used below require that type
- */
-ClutterCairoTexture *cc_texture = CLUTTER_CAIRO_TEXTURE (texture);
-
-clutter_cairo_texture_clear (cc_texture);
-
-gchar *file_uri = "file:///path/to/file.pdf";
-guint page_num = 0;
-double page_width, page_height;
-
-PopplerDocument *doc;
-PopplerPage *page;
-GError *error = NULL;
-
-doc = poppler_document_new_from_file (file_uri, NULL, &error);
-
-page = poppler_document_get_page (doc, page_num);
-
-poppler_page_get_size (page, &page_width, &page_height);
-
-cr = clutter_cairo_texture_create (cc_texture);
-
-/* render the page to the context */
-poppler_page_render (page, cr);
-
-cairo_destroy (cr);
-]]>
-
-
-
- Note that if the page is larger than the Cairo context,
- some of it might not be visible. Similarly, if the ClutterCairoTexture
- is larger than the stage, some of that might not be visible. So you
- may need to do some work to make the ClutterCairoTexture fit
- inside the stage properly (e.g. resize the stage), and/or some work
- to make the PDF page sit inside the Cairo context (e.g. scale the PDF
- page or put it inside a scrollable actor).
-
-
-
-
-
-
-
-
- Maintaining the aspect ratio when loading an
- image into a texture
-
-
- Problem
-
- You want want to load an image into a texture
- and scale it, while retaining the underlying image's aspect ratio.
-
-
-
- Solution
-
- Set the texture to keep the aspect ratio of the
- underlying image (so it doesn't distort when it's scaled); use
- the actor's request-mode property to set the correct
- geometry management (see the discussion section); then
- resize the texture along one dimension (height or width).
- Now, when an image is loaded into the texture, the image is
- scaled to fit the set height or width; the other dimension
- is automatically scaled by the same factor so the image fits
- the texture:
-
-
-
-
-
-
-
-
-
- Discussion
-
- The request mode for an actor determines how
- geometry requisition is performed; in this case, this
- includes how scaling is applied if you change the actor's
- width or height. There are two possible values for
- request-mode:
-
-
-
- If set to CLUTTER_REQUEST_HEIGHT_FOR_WIDTH
- (the default), changing the width causes the height
- to be scaled by the same factor as the width.
-
-
- If set to CLUTTER_REQUEST_WIDTH_FOR_HEIGHT,
- changing the height causes the width to be scaled by the
- same factor as the height.
-
-
-
- In the example above, the texture is set to keep its
- aspect ratio then fixed to a width of 300 pixels; the
- request-mode is set to CLUTTER_REQUEST_HEIGHT_FOR_WIDTH. If a
- standard, photo-sized image in landscape orientation were
- loaded into it (2848 pixels wide x 2136 high), it would be scaled
- down to 300 pixels wide; then, its height would be scaled by the
- same factor as the width (i.e. scaled down to 225 pixels).
-
- With request-mode set to CLUTTER_REQUEST_WIDTH_FOR_HEIGHT,
- you would get the same effect by setting the height first;
- then, computation of the width for the scaled image would be
- based on the scaling factor applied to its height instead.
-
- You can work out which side of the source image is longest using
- clutter_texture_base_size() to get its width and height. This can
- be useful when trying to scale images with different orientations
- to fit into uniform rows or columns:
-
-
-
-
-
-
-
- Note that if you explicitly set the size (both width and height)
- of a texture with clutter_actor_set_size() (or
- with clutter_actor_set_width() and clutter_actor_set_height()), any
- image loaded into the texture is automatically stretched/shrunk to
- fit the texture. This is the case regardless of any other settings
- (like whether to keep aspect ratio).
-
- Also note that a texture won't try to fit itself inside the bounds of
- its parent container: so if it's bigger than its container, only part
- of it may be visible.
-
-
-
-
-
- Loading image data into a texture
-
-
- Problem
-
- You want to display an image inside a Clutter
- application.
-
-
-
- Solution
-
- Create a ClutterTexture directly from an image file:
-
-
-
-
-
-
-
- Or create a texture and set its source to an image
- file:
-
-
-
-
-
-
-
-
-
-
- Discussion
-
- Bear the following in mind when loading images into a
- texture:
-
-
-
- An image load may fail if:
-
-
- The file does not exist.
-
-
- The image format is unsupported: most of the
- common bitmap formats (PNG, JPEG, BMP, GIF, TIFF, XPM)
- are supported, but more exotic ones may not be.
-
-
-
-
-
- Whether you're creating a texture from an image file,
- or loading an image from a file into an existing texture,
- you should specify the filesystem path to the file, rather
- than a URI.
-
-
-
-
- Synchronous vs. asynchronous image loading
-
- The code examples above show the simplest approach:
- loading an image into a texture synchronously. This means that
- the application waits for each image to be loaded before continuing;
- which is acceptable in this case, but may not be when
- loading images into multiple textures.
-
- Another approach is to load data into textures
- asynchronously. This requires some extra set up in your code:
-
-
-
- Call g_thread_init() (from the GLib library) prior
- to calling clutter_init(), so that a local thread is used
- to load the file, rather than the main loop. (Note that
- this is not necessary if you're using GLib version >= 2.24,
- since GObject initializes threading with the type system.)
-
-
- Set the texture to load data asynchronously.
-
-
- Connect a callback to the texture's load-finished
- signal to handle any errors which occur during loading,
- and/or to do extra work if data loads successfully.
-
-
-
- The code below shows how to put these together:
-
-
-
-message);
- else
- g_debug ("Image loaded from %s", image_path);
-}
-
-int
-main (int argc, char *argv[])
-{
- /* initialize GLib's default threading implementation */
- g_thread_init (NULL);
-
- clutter_init (&argc, &argv);
-
- /* ... get stage etc. */
-
- ClutterActor *texture;
- GError *error = NULL;
-
- texture = clutter_texture_new ();
-
- /* load data asynchronously */
- clutter_texture_set_load_async (CLUTTER_TEXTURE (texture), TRUE);
-
- /* connect a callback to the "load-finished" signal */
- g_signal_connect (texture,
- "load-finished",
- G_CALLBACK (_load_finished_cb),
- image_path);
-
- /* load the image from a file */
- clutter_texture_set_from_file (CLUTTER_TEXTURE (texture),
- image_path,
- &error);
-
- /* ... clutter_main () etc. */
-}
-]]>
-
-
-
-
-
-
- Other ways to load image data into a texture
-
- While it's useful to load image data into a texture directly
- from a file, there are occasions where you may have image data
- in some other (non-file) format:
-
-
-
- Various GNOME libraries provide image data in GdkPixbuf
- structures; clutter-gtk has functions for
- creating or setting a texture from a GdkPixbuf:
- gtk_clutter_texture_new_from_pixbuf()
- and gtk_clutter_texture_set_from_pixbuf() respectively.
-
-
- If you have raw RGB or YUV pixel data, ClutterTexture has
- clutter_texture_set_from_rgb_data() and
- clutter_texture_set_from_yuv_data() methods for loading it.
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
Contributing to this document
@@ -1266,29 +54,4 @@ main (int argc, char *argv[])
directory of Clutter.
-
-
diff --git a/doc/cookbook/events.xml b/doc/cookbook/events.xml
new file mode 100644
index 000000000..b3fc2f9d4
--- /dev/null
+++ b/doc/cookbook/events.xml
@@ -0,0 +1,337 @@
+
+
+
+ Events
+
+
+ The Tenth Doctor (David Tennant)
+ Crossing into established events is strictly forbidden. Except for
+ cheap tricks.
+
+
+
+ Introduction
+ Once you have set up a scene on the stage, in order to respond
+ to user interaction you will have to handle events coming from the
+ underlying platform.
+
+ Events are relayed to actors by Clutter in form of
+ signals; signals are a facility provided by the
+ GObject framework to call functions depending on a unique name. A signal
+ can be thought as a message that an object instance broadcasts to various
+ listener functions.
+
+ There are various events that Clutter will handle: mostly, they
+ deal with input devices, like a mouse pointer or a keyboard; but they can
+ also come from the windowing system, like the
+ delete-event signal that is emitted when the user
+ closes the window of the stage.
+
+ Each event has a particular source, that is
+ the actor that received the event. The event handling sequence is divided
+ in two phases:
+
+
+ the capture phase, which consists
+ in an emission of the captured-event signal
+ starting from the stage to, following the parent-child relationship,
+ the source of the event;
+ the bubble phase, which consists
+ in an emission of the event signal starting from
+ the the source of the event to, following the parent-child
+ relationship, the stage.
+
+
+ At any point during the event emission sequence a handler of either
+ the captured-event or the event signals can stop it, by returning a value
+ of TRUE, which means that the event has been handled. If an event hasn't
+ been handled, FALSE should be returned instead.
+
+
+
+ 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 gboolean
+_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;
+ }
+
+ /* The event was handled, and the emission should stop */
+ return TRUE;
+ }
+
+ /* The event was not handled, and the emission should continue */
+ return FALSE;
+}
+
+
+
+ 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;
+GObjectClass *stage_class;
+
+stage_class = CLUTTER_STAGE_GET_CLASS (stage);
+binding_pool = clutter_binding_pool_get_for_class (stage_class);
+
+
+
+ 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);
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/cookbook/introduction.xml b/doc/cookbook/introduction.xml
new file mode 100644
index 000000000..f88fd6d4c
--- /dev/null
+++ b/doc/cookbook/introduction.xml
@@ -0,0 +1,103 @@
+
+
+]>
+
+
+ Preface
+
+
+ The Perl Cookbook
+ Let me show you that easy way, so others may easily follow.
+
+
+ There is a wonderful simile in the preface of the Perl
+ Cookbook: approaching a programming problem is oftentimes
+ similar to balancing Columbus's egg. The initial difficulties of dealing
+ with, and more importantly solving, problems in the computer programming
+ field sometimes can only be overcome if somebody shows you how to use a
+ new tool. This is true for programming languages but also for programming
+ libraries.
+
+ This book has been written to try and give you a reference on
+ how to solve common issues that you might have to face when using
+ the Clutter toolkit.
+
+ This book is not meant to be a replacement for the API reference,
+ even though there will be descriptions of how Clutter works and how
+ its API looks like. We will require knowledge of the Clutter API, but
+ we will also point out where to find more information on the API that
+ examples have used.
+
+ Indeed, this book should be used as a companion to the API reference,
+ expanding the examples and showing how to achieve a specific result.
+
+ This is not a book for learning Clutter. This is also not a book
+ for learning C, or GObject or even GUI development.
+
+ Above all, this is a book for learning more
+ about Clutter, and about how to use it in the most efficient and easiest
+ way. It is meant to help you move past the basic usage of Clutter.
+
+ This book is divided into chapters. Each chapter is dedicated to
+ a specific class, like ClutterTexture, or a specific area, like animations.
+ Each chapter starts with a short introduction, followed by different
+ recipes. Each recipe starts with a problem, or a short
+ statement describing what we want to achieve; a solution, containing the
+ source code; and a discussion section, where the code is explained, where
+ alternative approaches might be useful, caveats and references to the
+ Clutter API for furher studying.
+
+ This book, in the cookbook spirit, can be accessed mostly at
+ random.
+
+
+ About Clutter
+
+ Clutter is an free and open source software library for creating
+ portable, dynamic, compelling and fast graphical user interfaces.
+
+ Clutter uses OpenGL (and, optionally, OpenGL ES on mobile and
+ embedded platforms) for rendering the user interface elements, but
+ at the same time it exposes an application program interface that hides
+ the underlying complexity of the OpenGL state machine from the
+ developer.
+
+ The program interface of Clutter is intended to be easy to use,
+ efficient, flexible and as self-documenting as possible.
+
+
+
+ About this document
+
+ This document is available in various formats like HTML, and
+ PDF.
+
+ The latest version is always available at
+ &docurl;.
+
+
+
+
+ Acknowledgments
+
+ This book has been written taking the inspiration from the Perl
+ Cookbook, authored by Tom Christiansen and Nathan Torkington.
+
+
+
+
+ Where to get Clutter
+
+ You can obtain Clutter from &appurl;.
+
+ Clutter is also available on all major GNU/Linux distributions,
+ in various package formats.
+
+ On OSX, Clutter is available with both Fink and MacPorts.
+
+ Binaries for Microsoft Windows are also available.
+
+
+
diff --git a/doc/cookbook/recipe-template.xml b/doc/cookbook/recipe-template.xml
new file mode 100644
index 000000000..9dfe62876
--- /dev/null
+++ b/doc/cookbook/recipe-template.xml
@@ -0,0 +1,24 @@
+
diff --git a/doc/cookbook/textures.xml b/doc/cookbook/textures.xml
new file mode 100644
index 000000000..e82bc80bc
--- /dev/null
+++ b/doc/cookbook/textures.xml
@@ -0,0 +1,483 @@
+
+
+
+ Textures
+
+
+ the author of the epigraph
+ a short epigraph
+
+
+
+ Introduction
+
+ introduction
+
+
+
+ Drawing 2D graphics onto a texture
+
+
+ Problem
+
+ You want to draw 2D graphics inside a Clutter application.
+
+
+
+ Solution
+
+ Create a ClutterCairoTexture, then draw onto the Cairo context
+ it wraps using the Cairo API:
+
+
+
+ClutterActor *texture;
+cairo_t *cr;
+
+guint width, height;
+width = 800;
+height = 600;
+
+texture = clutter_cairo_texture_new (width, height);
+
+cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (texture));
+
+/*
+ * write onto the Cairo context cr using the Cairo API;
+ * see the Cairo API reference for details
+ */
+cairo_move_to (cr, 0, 0);
+cairo_line_to (cr, 800, 600);
+cairo_stroke (cr);
+
+/* does the actual drawing onto the texture */
+cairo_destroy (cr);
+
+
+
+ Here's a useful
+ Cairo tutorial if you want to learn more about the Cairo API
+ itself.
+
+
+
+ Discussion
+
+ A ClutterCairoTexture is a standard ClutterActor, so it can be
+ added to ClutterContainers (e.g. a ClutterStage or ClutterGroup),
+ animated, resized etc. in the usual ways.
+
+ Other useful operations:
+
+
+
+
+ To draw on part of the texture:
+ use clutter_cairo_texture_create_region to
+ retrieve a Cairo context for the region you want to draw on.
+
+
+
+ To clear existing content from a texture:
+ use clutter_cairo_texture_clear.
+
+ You may need to do this as the texture reuses the same
+ Cairo context each time you call
+ clutter_cairo_texture_create or
+ clutter_cairo_texture_create_region.
+
+
+
+ To resize the Cairo context wrapped
+ by a texture, use
+ clutter_cairo_texture_set_surface_size.
+
+
+
+
+
+ Drawing pages from a PDF onto a ClutterCairoContext
+
+ Other libraries may provide an API for writing onto a
+ Cairo context; you can make use of these APIs on the exposed
+ Cairo context of a ClutterCairoTexture. For example, you
+ can use the poppler-glib API to display pages
+ from a PopplerDocument inside a Clutter application:
+
+
+
+
+
+/* snipped setup code (as above) */
+
+/*
+ * cast to CLUTTER_CAIRO_TEXTURE, as the functions
+ * used below require that type
+ */
+ClutterCairoTexture *cc_texture = CLUTTER_CAIRO_TEXTURE (texture);
+
+clutter_cairo_texture_clear (cc_texture);
+
+gchar *file_uri = "file:///path/to/file.pdf";
+guint page_num = 0;
+double page_width, page_height;
+
+PopplerDocument *doc;
+PopplerPage *page;
+GError *error = NULL;
+
+doc = poppler_document_new_from_file (file_uri, NULL, &error);
+
+page = poppler_document_get_page (doc, page_num);
+
+poppler_page_get_size (page, &page_width, &page_height);
+
+cr = clutter_cairo_texture_create (cc_texture);
+
+/* render the page to the context */
+poppler_page_render (page, cr);
+
+cairo_destroy (cr);
+]]>
+
+
+
+ Note that if the page is larger than the Cairo context,
+ some of it might not be visible. Similarly, if the ClutterCairoTexture
+ is larger than the stage, some of that might not be visible. So you
+ may need to do some work to make the ClutterCairoTexture fit
+ inside the stage properly (e.g. resize the stage), and/or some work
+ to make the PDF page sit inside the Cairo context (e.g. scale the PDF
+ page or put it inside a scrollable actor).
+
+
+
+
+
+
+
+
+ Maintaining the aspect ratio when loading an
+ image into a texture
+
+
+ Problem
+
+ You want want to load an image into a texture
+ and scale it, while retaining the underlying image's aspect ratio.
+
+
+
+ Solution
+
+ Set the texture to keep the aspect ratio of the
+ underlying image (so it doesn't distort when it's scaled); use
+ the actor's request-mode property to set the correct
+ geometry management (see the discussion section); then
+ resize the texture along one dimension (height or width).
+ Now, when an image is loaded into the texture, the image is
+ scaled to fit the set height or width; the other dimension
+ is automatically scaled by the same factor so the image fits
+ the texture:
+
+
+
+
+
+
+
+
+
+ Discussion
+
+ The request mode for an actor determines how
+ geometry requisition is performed; in this case, this
+ includes how scaling is applied if you change the actor's
+ width or height. There are two possible values for
+ request-mode:
+
+
+
+ If set to CLUTTER_REQUEST_HEIGHT_FOR_WIDTH
+ (the default), changing the width causes the height
+ to be scaled by the same factor as the width.
+
+
+ If set to CLUTTER_REQUEST_WIDTH_FOR_HEIGHT,
+ changing the height causes the width to be scaled by the
+ same factor as the height.
+
+
+
+ In the example above, the texture is set to keep its
+ aspect ratio then fixed to a width of 300 pixels; the
+ request-mode is set to CLUTTER_REQUEST_HEIGHT_FOR_WIDTH. If a
+ standard, photo-sized image in landscape orientation were
+ loaded into it (2848 pixels wide x 2136 high), it would be scaled
+ down to 300 pixels wide; then, its height would be scaled by the
+ same factor as the width (i.e. scaled down to 225 pixels).
+
+ With request-mode set to CLUTTER_REQUEST_WIDTH_FOR_HEIGHT,
+ you would get the same effect by setting the height first;
+ then, computation of the width for the scaled image would be
+ based on the scaling factor applied to its height instead.
+
+ You can work out which side of the source image is longest using
+ clutter_texture_base_size() to get its width and height. This can
+ be useful when trying to scale images with different orientations
+ to fit into uniform rows or columns:
+
+
+
+
+
+
+
+ Note that if you explicitly set the size (both width and height)
+ of a texture with clutter_actor_set_size() (or
+ with clutter_actor_set_width() and clutter_actor_set_height()), any
+ image loaded into the texture is automatically stretched/shrunk to
+ fit the texture. This is the case regardless of any other settings
+ (like whether to keep aspect ratio).
+
+ Also note that a texture won't try to fit itself inside the bounds of
+ its parent container: so if it's bigger than its container, only part
+ of it may be visible.
+
+
+
+
+
+ Loading image data into a texture
+
+
+ Problem
+
+ You want to display an image inside a Clutter
+ application.
+
+
+
+ Solution
+
+ Create a ClutterTexture directly from an image file:
+
+
+
+
+
+
+
+ Or create a texture and set its source to an image
+ file:
+
+
+
+
+
+
+
+
+
+
+ Discussion
+
+ Bear the following in mind when loading images into a
+ texture:
+
+
+
+ An image load may fail if:
+
+
+ The file does not exist.
+
+
+ The image format is unsupported: most of the
+ common bitmap formats (PNG, JPEG, BMP, GIF, TIFF, XPM)
+ are supported, but more exotic ones may not be.
+
+
+
+
+
+ Whether you're creating a texture from an image file,
+ or loading an image from a file into an existing texture,
+ you should specify the filesystem path to the file, rather
+ than a URI.
+
+
+
+
+ Synchronous vs. asynchronous image loading
+
+ The code examples above show the simplest approach:
+ loading an image into a texture synchronously. This means that
+ the application waits for each image to be loaded before continuing;
+ which is acceptable in this case, but may not be when
+ loading images into multiple textures.
+
+ Another approach is to load data into textures
+ asynchronously. This requires some extra set up in your code:
+
+
+
+ Call g_thread_init() (from the GLib library) prior
+ to calling clutter_init(), so that a local thread is used
+ to load the file, rather than the main loop. (Note that
+ this is not necessary if you're using GLib version >= 2.24,
+ since GObject initializes threading with the type system.)
+
+
+ Set the texture to load data asynchronously.
+
+
+ Connect a callback to the texture's load-finished
+ signal to handle any errors which occur during loading,
+ and/or to do extra work if data loads successfully.
+
+
+
+ The code below shows how to put these together:
+
+
+
+message);
+ else
+ g_debug ("Image loaded from %s", image_path);
+}
+
+int
+main (int argc, char *argv[])
+{
+ /* initialize GLib's default threading implementation */
+ g_thread_init (NULL);
+
+ clutter_init (&argc, &argv);
+
+ /* ... get stage etc. */
+
+ ClutterActor *texture;
+ GError *error = NULL;
+
+ texture = clutter_texture_new ();
+
+ /* load data asynchronously */
+ clutter_texture_set_load_async (CLUTTER_TEXTURE (texture), TRUE);
+
+ /* connect a callback to the "load-finished" signal */
+ g_signal_connect (texture,
+ "load-finished",
+ G_CALLBACK (_load_finished_cb),
+ image_path);
+
+ /* load the image from a file */
+ clutter_texture_set_from_file (CLUTTER_TEXTURE (texture),
+ image_path,
+ &error);
+
+ /* ... clutter_main () etc. */
+}
+]]>
+
+
+
+
+
+
+ Other ways to load image data into a texture
+
+ While it's useful to load image data into a texture directly
+ from a file, there are occasions where you may have image data
+ in some other (non-file) format:
+
+
+
+ Various GNOME libraries provide image data in GdkPixbuf
+ structures; clutter-gtk has functions for
+ creating or setting a texture from a GdkPixbuf:
+ gtk_clutter_texture_new_from_pixbuf()
+ and gtk_clutter_texture_set_from_pixbuf() respectively.
+
+
+ If you have raw RGB or YUV pixel data, ClutterTexture has
+ clutter_texture_set_from_rgb_data() and
+ clutter_texture_set_from_yuv_data() methods for loading it.
+
+
+
+
+
+
+
+
+