78325a34db
The Clutter cookbook has a chapter for textures. It would be useful to provide a recipe on simple uses of ClutterCairoTexture as part of that. Some suggested content is attached.
649 lines
20 KiB
XML
649 lines
20 KiB
XML
<?xml version='1.0' encoding='UTF-8'?>
|
|
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
|
|
<!ENTITY appurl "http://clutter-project.org">
|
|
<!ENTITY docurl "http://clutter-project.org/docs/">
|
|
<!ENTITY author_mail "ebassi@linux.intel.com">
|
|
<!ENTITY apiversion "@CLUTTER_API_VERSION@">
|
|
]>
|
|
|
|
<book lang="en">
|
|
|
|
<bookinfo> <!-- {{{ -->
|
|
<author>
|
|
<firstname>Emmanuele</firstname>
|
|
<surname>Bassi</surname>
|
|
<address><email>&author_mail;</email></address>
|
|
</author>
|
|
|
|
<copyright>
|
|
<year>2009</year>
|
|
<holder>Intel Corporation</holder>
|
|
</copyright>
|
|
|
|
<legalnotice>
|
|
<para>This document is distributed under the terms of the GNU General
|
|
Public License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version. A copy
|
|
of this license can be found in the file COPYING included with the
|
|
source code of this program.</para>
|
|
</legalnotice>
|
|
|
|
<title>The Clutter Cookbook</title>
|
|
<releaseinfo>for Clutter &apiversion;</releaseinfo>
|
|
</bookinfo> <!-- }}} -->
|
|
|
|
<chapter id="introduction"> <!-- {{{ -->
|
|
<title>Preface</title>
|
|
|
|
<epigraph>
|
|
<attribution>The Perl Cookbook</attribution>
|
|
<para>Let me show you that easy way, so others may easily follow.</para>
|
|
</epigraph>
|
|
|
|
<para>There is a wonderful simile in the preface of the <emphasis>Perl
|
|
Cookbook</emphasis>: 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.</para>
|
|
|
|
<para>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.</para>
|
|
|
|
<para>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.</para>
|
|
|
|
<para>Indeed, this book should be used as a companion to the API reference,
|
|
expanding the examples and showing how to achieve a specific result.</para>
|
|
|
|
<para>This is not a book for learning Clutter. This is also not a book
|
|
for learning C, or GObject or even GUI development.</para>
|
|
|
|
<para>Above all, this is a book for learning <emphasis>more</emphasis>
|
|
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.</para>
|
|
|
|
<para>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
|
|
<emphasis>recipes</emphasis>. 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.</para>
|
|
|
|
<para>This book, in the cookbook spirit, can be accessed mostly at
|
|
random.</para>
|
|
|
|
<section>
|
|
<title>About Clutter</title>
|
|
|
|
<para>Clutter is an free and open source software library for creating
|
|
fast, visually rich and animated graphical user interfaces.</para>
|
|
|
|
<para>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.</para>
|
|
|
|
<para>The program interface of Clutter is intended to be easy to use,
|
|
efficient, flexible and as self-documenting as possible.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>About this document</title>
|
|
|
|
<para>This document is available in various formats like HTML, and
|
|
PDF.</para>
|
|
|
|
<para>The latest version is always available at
|
|
<ulink url="&docurl;">&docurl;</ulink>.</para>
|
|
|
|
</section>
|
|
|
|
<section>
|
|
<title>Where to get Clutter</title>
|
|
|
|
<para>You can obtain Clutter from <ulink url="&appurl;">&appurl;</ulink>.</para>
|
|
|
|
<para>Clutter is also available on all major GNU/Linux distributions,
|
|
in various package formats.</para>
|
|
|
|
<para>On OSX, Clutter is available with both Fink and MacPorts.</para>
|
|
|
|
<para>Binaries for Microsoft Windows are also available.</para>
|
|
</section>
|
|
|
|
</chapter> <!-- introduction }}} -->
|
|
|
|
<chapter id="actors"> <!-- actors {{{ -->
|
|
<title>Actors</title>
|
|
|
|
<epigraph>
|
|
<attribution>Edmon Gween, actor, on his deathbed</attribution>
|
|
<para>An actor's a guy who if you ain't talkin' about him, ain't
|
|
listening.</para>
|
|
</epigraph>
|
|
|
|
<section id="actors-introduction">
|
|
<title>Introduction</title>
|
|
|
|
<para>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.</para>
|
|
|
|
<para>Every node on the Clutter scene graph is an
|
|
<emphasis>actor</emphasis>. Every actor has a single relationship
|
|
with the others: it can be the parent of another actor, or a child of
|
|
another actor.</para>
|
|
|
|
<note><para>The Stage is an actor that can have children but cannot have
|
|
any parent.</para></note>
|
|
|
|
<para>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.</para>
|
|
|
|
<para>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.</para>
|
|
|
|
</section>
|
|
|
|
<section id="actors-allocation-notify"> <!-- {{{ -->
|
|
<title>Knowing when an actor position or size change</title>
|
|
|
|
<section>
|
|
<title>Problem</title>
|
|
|
|
<para>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.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Solution</title>
|
|
|
|
<para>You can use the <emphasis>notify</emphasis> signal,
|
|
detailed with the coordinate or the dimension you want
|
|
to know has changed:</para>
|
|
|
|
<informalexample>
|
|
<programlisting>
|
|
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);
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>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
|
|
<emphasis>allocation-changed</emphasis> signal:</para>
|
|
|
|
<informalexample>
|
|
<programlisting>
|
|
g_signal_connect (actor, "allocation-changed",
|
|
G_CALLBACK (on_allocation_changed),
|
|
NULL);
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>The signature for the handler of the "notify" signal is:</para>
|
|
|
|
<informalexample>
|
|
<programlisting>
|
|
void
|
|
on_notify (GObject *gobject,
|
|
GParamSpec *pspec,
|
|
gpointer user_data);
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>While the signature for the handler of the "allocation-changed"
|
|
signal is:</para>
|
|
|
|
<informalexample>
|
|
<programlisting>
|
|
void
|
|
on_allocation_changed (ClutterActor *actor,
|
|
const ClutterActorBox *allocation,
|
|
ClutterAllocationFlags flags,
|
|
gpointer user_data);
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
</section>
|
|
|
|
<section>
|
|
<title>Discussion</title>
|
|
|
|
<para>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.</para>
|
|
|
|
<para>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:</para>
|
|
|
|
<informalexample>
|
|
<programlisting>
|
|
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);
|
|
}
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>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:</para>
|
|
|
|
<informalexample>
|
|
<programlisting>
|
|
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));
|
|
}
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>All actors will update these properties when their size
|
|
or position change.</para>
|
|
|
|
<para>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.</para>
|
|
|
|
</section>
|
|
|
|
</section> <!-- recipe 1 }}} -->
|
|
|
|
<section id="actors-paint-wrappers"> <!-- {{{ -->
|
|
<title>Overriding the paint sequence</title>
|
|
|
|
<section>
|
|
<title>Problem</title>
|
|
|
|
<para>You want to override the way an actor paints itself
|
|
without creating a subclass.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Solution</title>
|
|
|
|
<para>You can use the <emphasis>paint</emphasis> signal to
|
|
invoke a callback that will be executed before the actor's
|
|
paint implementation:</para>
|
|
|
|
<informalexample>
|
|
<programlisting>
|
|
g_signal_connect (actor, "paint",
|
|
G_CALLBACK (on_paint),
|
|
NULL);
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>You can paint something after the actor's paint implementation
|
|
by using the <function>g_signal_connect_after()</function> function
|
|
instead of <function>g_signal_connect()</function>:</para>
|
|
|
|
<informalexample>
|
|
<programlisting>
|
|
g_signal_connect_after (actor, "paint",
|
|
G_CALLBACK (on_paint_after),
|
|
NULL);
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>The signature for the handler of the "paint" signal is:</para>
|
|
|
|
<informalexample>
|
|
<programlisting>
|
|
void
|
|
on_paint (ClutterActor *actor,
|
|
gpointer user_data);
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
</section>
|
|
|
|
<section>
|
|
<title>Discussion</title>
|
|
|
|
<para>The paint cycle in Clutter works its way recursively from the
|
|
Stage through every child.</para>
|
|
|
|
<para>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.</para>
|
|
|
|
<para>The "paint" signal is defined as <emphasis>run-last</emphasis>,
|
|
that is the signal handlers connected to it using
|
|
<function>g_signal_connetc()</function> 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
|
|
<function>g_signal_connect_after()</function> will be called.</para>
|
|
|
|
<para>This allows pre- and post-default paint handlers, and it also
|
|
allows completely overriding the way an Actor draws itself by default;
|
|
for instance:</para>
|
|
|
|
<informalexample>
|
|
<programlisting>
|
|
void
|
|
on_paint (ClutterActor *actor)
|
|
{
|
|
do_my_paint (actor);
|
|
|
|
g_signal_stop_emission_by_name (actor, "paint");
|
|
}
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>The code above will prevent the default paint implementation of
|
|
the actor from running.</para>
|
|
</section>
|
|
|
|
</section> <!-- }}} -->
|
|
|
|
</chapter> <!-- actors }}} -->
|
|
|
|
<chapter id="textures"> <!-- textures {{{ -->
|
|
<title>Textures</title>
|
|
|
|
<epigraph>
|
|
<attribution>the author of the epigraph</attribution>
|
|
<para>a short epigraph</para>
|
|
</epigraph>
|
|
|
|
<section id="textures-introduction">
|
|
<title>Introduction</title>
|
|
|
|
<para>introduction</para>
|
|
</section>
|
|
|
|
<section id="textures-drawing-with-cairo">
|
|
<title>Drawing 2D graphics onto a texture</title>
|
|
|
|
<section>
|
|
<title>Problem</title>
|
|
|
|
<para>You want to draw 2D graphics inside a Clutter application.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Solution</title>
|
|
|
|
<para>Create a ClutterCairoTexture, then draw onto the Cairo context
|
|
it wraps using the Cairo API:</para>
|
|
|
|
<informalexample>
|
|
<programlisting>
|
|
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 <ulink url="http://cairographics.org/manual/">the Cairo API reference</ulink> 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);
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>Here's a <ulink url="http://cairographics.org/tutorial/">useful
|
|
Cairo tutorial</ulink> if you want to learn more about the Cairo API
|
|
itself.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Discussion</title>
|
|
|
|
<para>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.</para>
|
|
|
|
<para>Other useful operations:</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
<para><emphasis>To draw on part of the texture:</emphasis>
|
|
use <function>clutter_cairo_texture_create_region</function> to
|
|
retrieve a Cairo context for the region you want to draw on.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>To clear existing content from a texture:</emphasis>
|
|
use <function>clutter_cairo_texture_clear</function>.</para>
|
|
|
|
<para>You may need to do this as the texture reuses the same
|
|
Cairo context each time you call
|
|
<function>clutter_cairo_texture_create</function> or
|
|
<function>clutter_cairo_texture_create_region</function>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>To resize the Cairo context wrapped
|
|
by a texture</emphasis>, use
|
|
<function>clutter_cairo_texture_set_surface_size</function>.</para>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<section>
|
|
<title>Drawing pages from a PDF onto a ClutterCairoContext</title>
|
|
|
|
<para>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:</para>
|
|
|
|
<informalexample>
|
|
<programlisting>
|
|
<![CDATA[
|
|
#include <poppler/glib/poppler.h>
|
|
|
|
/* 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);
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>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).</para>
|
|
|
|
</section>
|
|
|
|
</section>
|
|
|
|
</section>
|
|
|
|
<!--
|
|
<section id="textures-aspect-ratio">
|
|
<title>Maintaining the aspect ratio when loading a texture</title>
|
|
|
|
<section>
|
|
<title>Problem</title>
|
|
|
|
<para>You want to maintain the aspect ratio of a texture.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Solution</title>
|
|
|
|
<para></para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Discussion</title>
|
|
|
|
<para></para>
|
|
</section>
|
|
|
|
</section>
|
|
-->
|
|
|
|
</chapter> <!-- textures }}} -->
|
|
|
|
<!--
|
|
<chapter id="animations">
|
|
<title>Animations</title>
|
|
|
|
<epigraph>
|
|
<attribution>the author of the epigraph</attribution>
|
|
<para>a short epigraph</para>
|
|
</epigraph>
|
|
|
|
<section id="animations-introduction">
|
|
<title>Introduction</title>
|
|
|
|
<para>introduction</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Inverting Animations</title>
|
|
|
|
<section>
|
|
<title>Problem</title>
|
|
|
|
<para>You want to have an animation exactly mirroring another one
|
|
that you just played.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Solution</title>
|
|
|
|
<para>...</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Discussion</title>
|
|
|
|
<para>...</para>
|
|
</section>
|
|
|
|
</section>
|
|
|
|
</chapter>
|
|
-->
|
|
|
|
<appendix id="contributing"> <!-- contributing {{{ -->
|
|
<title>Contributing to this document</title>
|
|
|
|
<para>This document is written in Docbook XML. The source file for this
|
|
document is located in the subdirectory "doc/cookbook" of the source
|
|
directory of Clutter.</para>
|
|
</appendix> <!-- contributing }}} -->
|
|
|
|
<!--
|
|
<section id="recipe">
|
|
<title>Recipe</title>
|
|
|
|
<section>
|
|
<title>Problem</title>
|
|
|
|
<para>...</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Solution</title>
|
|
|
|
<para>...</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Discussion</title>
|
|
|
|
<para>...</para>
|
|
</section>
|
|
|
|
</section>
|
|
-->
|
|
|
|
</book>
|