From 089b9b545e393848a0f8bce73d2a8468566d56c6 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 1 Jul 2010 11:29:46 +0100 Subject: [PATCH] cookbook: Split the cookbook chapters Use separate files, to avoid making the XML too big and uneditable. This breaks the PDF build. --- doc/cookbook/Makefile.am | 13 +- doc/cookbook/actors.xml | 260 +++++++ doc/cookbook/animations.xml | 42 ++ doc/cookbook/clutter-cookbook.xml.in | 1255 +--------------------------------- doc/cookbook/events.xml | 337 +++++++++ doc/cookbook/introduction.xml | 103 +++ doc/cookbook/recipe-template.xml | 24 + doc/cookbook/textures.xml | 483 +++++++++++++ 8 files changed, 1270 insertions(+), 1247 deletions(-) create mode 100644 doc/cookbook/actors.xml create mode 100644 doc/cookbook/animations.xml create mode 100644 doc/cookbook/events.xml create mode 100644 doc/cookbook/introduction.xml create mode 100644 doc/cookbook/recipe-template.xml create mode 100644 doc/cookbook/textures.xml diff --git a/doc/cookbook/Makefile.am b/doc/cookbook/Makefile.am index e06e0cc..5aa3a04 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 0000000..815f9d2 --- /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 0000000..1c31006 --- /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. +
+ +
+ Solution + + ... +
+ +
+ Discussion + + ... +
+ +
+ +
diff --git a/doc/cookbook/clutter-cookbook.xml.in b/doc/cookbook/clutter-cookbook.xml.in index 880ca7b..f6d8583 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 0000000..b3fc2f9 --- /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 0000000..f88fd6d --- /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 0000000..9dfe628 --- /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 0000000..e82bc80 --- /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. + + + +
+ +
+
+ +
-- 2.7.4