We Heaved Relief as Scores of Innocents Died

after all the changes in this series of blogs, and all the big changes I tried to introduce in them, this is mostly a coda — one in which I just want to mention a couple of new features that don’t fall in the previous apocalypses but that I think are interesting nonetheless.

ClutterTimeline and ClutterAlpha

the timeline class gained a new property, repeat-count which replaces the venerable loop one; whilst loop would just make the timeline loop indefinitely (until forcibly stopped), repeat-count allows you to set a ceiling to the number of repeats.

another change in the Timeline class is the introduction of the progress-mode property, which allows you to control how the progress property is computed. this effectively deprecates ClutterAlpha, even if the class itself hasn’t been marked for deprecation (as we still need it for other API).

these two changes hopefully will make using ClutterTimeline a better experience, and remove some custom code.

Support localizable strings in ClutterScript

if you currently define UI elements in ClutterScript you’ll notice that all the strings are not translatable; this is clearly sub-optimal, and prevents people from actually writing proper applications using this format, just like they do with GtkBuilder.

I recently added the ability to describe translatable strings inside the JSON format, using a syntax like:


  {
    ...
    "a-label-property" : {
      "translatable" : true,
      "string" : "A Translatable String",
      "context" : "Some Context",
      "domain" : "Gettext-Domain"
    },
    ...
  }

the domain and context members are optional, and allow you to specify a gettext domain and context for a specific string; you can assign a domain to the ClutterScript instance, using clutter_script_set_translation_domain(), or use the Gettext domain specified by the application itself upon initialization with bindtextdomain().

obviously, this is just a step: the real support for localization can only come after intltool is updated to handle the JSON format used by ClutterScript, to extract the translatable strings and place them into the POT file; this is planned, but it’s not ready yet.

see you in 6 months!

well, I hope you enjoyed this series of blog posts; oh, more accurately: I hope you haven’t been bored to death by it.

what will happen in six months is, very likely, a 1.12 release of Clutter, with a couple of other Apocalypses landing (a way to animate layout management by using the easing states and transition API instead of the half-aborted animation API inside ClutterLayoutManager; and the ClutterActorModel API, to get rid of the ClutterClones).

ideally, I’d really like to have the first 2.0 alpha release at about the same time — in order to give people the feel of the changes, as well as time to port their applications and start complaining about the missing functionality while I can still add, change, or remove API. what’s certain is that between 6 and 12 months I want to have Clutter 2.0 out of the door and into your systems; whether or not that will happen sooner or later it entirely depends on the time I’ll be able to spend on it, as well as the contributions I may receive. so, if I have to close with a familiar exhortation: patches welcome!

until then, have fun with Clutter!

And I Believe California Succumbed to the Fault Line

Clutter’s description, and I quote from the website, is:

an open source software library for creating fast, compelling, portable, and dynamic graphical user interfaces.

and yet, the API to build a user interface is static: you create the actor tree, you tell it how to paint its contents, and only then you animate it to create a compelling and dynamic result.

the ethos of an API should be to Do The Right Thing™ by default — and make it harder if not impossible to Do The Wrong Thing™ — so why is it that you have a simple function to make an actor jump at a given position, and you have a really complex function, full of side-effects and options, to make an actor tween between the current position and the desired new one?

Scumbag Steve meme - top caption says: "Promises dynamic user interfaces", bottom caption says: "makes everything static by default"

wouldn’t it be better, and even easier, if the simple function did the tweening, and if the complex function just went away because, well: who needs it, anyway?

so we need to identify properties that should be animated when changed, and we have to make every setter for that property perform a transition from the current value to the desired value, using a predefined duration (that can be changed), and a predefined easing mode (that can be changed). easy, right?

well, sort of. we already have all the pieces in place: we have the timeline, to define the duration and progress of a transition; we have the interval, to define the initial and final states, as well as the interpolation between the two; and we have the introspection capabilities of GObject to determine whether a property can be animated, and how. all we need to do is connect the dots inside ClutterActor. hence, the introduction of ClutterTransition and of the easing state. the former is a simplified version of ClutterAnimation, that ties a ClutterInterval directly into a ClutterTimeline to avoid signal emissions and weird memory management rules; the latter is a way of describing the duration, delay, and easing mode of all subsequent transitions. Clutter will manage everything behind the scenes for you, so you just need to tell it how long, and how paced, are your transitions.

so, in short, this call:


  clutter_actor_animate (actor, CLUTTER_EASE_OUT_CUBIC, 250,
                         "x", 100.0,
                         "y", 100.0,
                         "width", 200.0,
                         "height", 200.0,
                         NULL);

becomes:


  clutter_actor_save_easing_state (actor);
  clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_CUBIC);
  clutter_actor_set_easing_duration (actor, 250);
  clutter_actor_set_position (actor, 100, 100);
  clutter_actor_set_size (actor, 200, 200);
  clutter_actor_restore_easing_state (actor);

which does not seem much, but:

  • you get back all the type safety you need;
  • the code becomes easy to follow;
  • you can use the convenience API instead of a per-property set.

for instance, try throwing things like scaling or rotating:


  ClutterVertex vertex = CLUTTER_VERTEX_INIT (x, y, z);

  clutter_actor_animate (actor, CLUTTER_EASE_OUT_CUBIC, 250,
                         "rotation-angle-y", 360.0,
                         "fixed:rotation-center-y", &vertex,
                         "scale-x", 2.0,
                         "scale-y", 2.0,
                         "fixed:scale-gravity", CLUTTER_GRAVITY_CENTER,
                         NULL);

becomes the much more familiar:


  clutter_actor_save_easing_state (actor);
  clutter_actor_set_scale_with_gravity (actor, 2.0, 2.0, CLUTTER_GRAVITY_CENTER);
  clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
  clutter_actor_restore_easing_state (actor);

well, I cheated a bit: the easing mode of CLUTTER_EASE_OUT_CUBIC and the easing duration of 250 milliseconds are the default when creating a new easing state — but that’s just another benefit: you don’t need to specify an easing mode and a duration if you want to use the sensible defaults, whereas clutter_actor_animate() forces you to do that every time.

job done!

Darth Vader filling a jug with water filtered from the sea

we still don’t want existing Clutter applications to change behaviour and start animating everything just because you updated Clutter from 1.8 to 1.10; for this reason, all actors start off with an easing state with a duration of zero milliseconds — which means that all transitions happen immediately. at least, this will be true for the 1.x API series: for 2.x, the initial easing state will have a non-zero duration, which means that if you want to make an actor jump at a specified state then you’ll have to begin a zero-milliseconds duration.

well, kind of

Success Kid Meme image; top caption is: "Follows API ethos", bottom caption is: "Makes the World Better"

it’s important to make sure that every time you want to change a user interface you think of it as an animation; this API should immediately give you have a visual feedback of what that change is going to provide — without structuring your code around lots of variadic argument functions, with pretty loose type checking and “interesting” corner cases.

so, for the 1.10 cycle you should start opting in into this way of writing your application, and use easing states instead of using clutter_actor_animate().

You and Me and The War at The End Times

the actor tree is only the representation of what your user interface is composed of: textures, reactive items, containers to give them structure. if nothing is painted, though, it’s not much of a user interface.

with the current stable version of Clutter, if you want to get something on the screen you either use one of the pre-canned sub-classes of ClutterActor provided by Clutter itself — ClutterTexture, ClutterRectangle, and ClutterCairoTexture — or you end up using something written outside of Clutter — Mx widgets, for instance; or you write your own UI elements. if you chose to write something from scratch, you will have to sub-class ClutterActor and override the ClutterActor::paint virtual function.1

what happens inside a paint virtual function implementation is usually this:

  • you use Cogl API to set up the state of the graphics pipeline;
  • you use Cogl API to submit geometry to the graphics pipeline;
  • you recursively call clutter_actor_paint() on your children, if any.

the third step can now be taken care of Clutter itself, as any actor now has access to the section of the actor tree with itself as the local root. the first and second steps are kind of tricky: you have to remember a lot of things about how to use the Cogl API. it would be nice if Clutter provided some convenience API to Do The Right Thing™ instead.

it would also be nicer if we could structure that API to build a representation of an entire frame, decoupling what gets painted from what is the logical unit of the user interface, because then we could keep it (either as parts or the entire thing) around between frames, manipulating the former without affecting the latter. the keen readers will already have said: you want a retained drawing model. good job! ten points for Gryffindor!

this new API is provided by paint nodes; each paint node is an element on the render tree — and every time you should paint an actor, you get passed a local root that you can use to attach your nodes. each paint node contains the pipeline state and the geometry to submit. once the tree has been built, Clutter will decide how to paint it. the base entry point for this operation is the ClutterActor::paint_node() virtual function. inside it, you’re supposed to paint only the actor — the children will be painted by Clutter itself. the paint_node() virtual should be considered orthogonal to the paint() one, though the latter will probably remain in 2.0 to give you control over which of your children you may decide to paint. Clutter provides predefined paint nodes for texture, solid colors, text, and even for custom pipelines; to each node you can add a rectangle (with or without texture coordinates), paths, or even Cogl primitive objects if you decide to use the experimental Cogl 2.0 API.

currently, given that we allow app and toolkit developers to use a direct drawing model, we still need to maintain that invariant, otherwise stuff will break; but we can already start migrating towards a retained drawing model, and have it fully in place by the time we hit 2.0. instead of setting up all the transformations and modifying the modelview and clip states, we’ll be able to attach transformation and clip nodes, and even be able to discard sections of the render tree without hitting the GPU. from there, we could go anywhere; we could hand off rendering into a separate thread and never block the main loop; or we could do the reverse, and thread everything else instead — event processing, layouting — without having application code left to deal with the fact that only one thread at a time can access a GL context.

obviously, most developers will not want to care about this; apps usually draw textures and text anyway, fancy as they may be. app developers should get a better API to achieve that, though, and the current model of sub-classes of ClutterActor is not serving them well enough; if you sub-class ClutterTexture you get a ton of behaviours, and most of them are really not at all nice, especially if all you want was to get some image data on the screen. I won’t even speak about ClutterCairoTexture, which encodes an implementation detail (that is not even true nowadays) into the class structure.

so, for 1.10 I introduced the ClutterContent interface, and a couple of trivial implementations for displaying image data and for drawing using Cairo. the classes are side-effect-free because they only know about one thing: painting some state. implementing a ClutterContent to paint something custom is easier than sub-classing ClutterActor, just like it’s easier to implement a ClutterLayoutManager to manage the layout policy of the children of an actor. all the cleverness on where and when to paint the content associated to an actor is where it belongs: inside the actor itself, leaving you to care just about what to paint.

  1. yes, it’s a signal, which means that you can also attach a handler to an existing actor and completely change how said actor paints itself; this is incredibly evil, and will not be possible in 2.0, so if you’re doing that, stop right now, or I will tell mom, and you won’t be invited to the Buffy marathon next time. []

Had a dream

as I wrote already in a previous blog post, if you try and compile an existing Clutter application with the current master, the first thing you will notice is that the compiler will start complaining about deprecated symbols.

a lot.

some of these symbols are little used API variants, or baggage we’ve been stringing along since the 0.x days and that we never managed to deprecate until now — and if you’ve been using them, then I’m not sure I want to know why, and you’ll have to trust me when I say that you’re better off not using them.

on the other hand, many of the deprecated symbols have been pretty central as to how a Clutter app is built and works; clutter_container_add_actor()? clutter_actor_raise()? ClutterBox? clutter_timeline_set_loop()?

in reality, not much has changed per se: the deprecation warnings will tell you how to port an app from the old API to the new one, and in basically all cases it’s juts a matter of changing functions or classes; plus, deprecated classes and functions will still work until we break API and release Clutter 2.0.

what really changed is how a Clutter app should be written from the get go — and this has more to do with the intent of the API, more than the actual form of the API.

case in point: if you look at the replacement for many of the deprecated functionality, as well as the new API introduced in 1.10, you will notice that it is overwhelmingly inside the ClutterActor class; the 1.9 development cycle stats for the clutter-actor.[ch] files alone are:


 git diff --stat clutter-1.8... clutter/clutter-actor.[ch]
 clutter/clutter-actor.c |20516 +++++++++++++++++++++++++++++------------------
 clutter/clutter-actor.h |  803 +-
 2 files changed, 13350 insertions(+), 7969 deletions(-)

so ClutterActor just gained around 5000 lines1.

this growth reflects one of the fundamental tenets of how Clutter should be used:

it’s all about actors

Actors are not the base, abstract class for elements on the UI: they are now a concrete class that should be used directly, instead of through sub-classes. the ClutterActor class is the element of the scene graph; it holds children, it paints them, it lays them out. there is one API to learn, one class that holds the keys to all the behaviour, and one class to inherit from for custom controls.

obviously, ClutterActor cannot do everything by itself; but instead of creating sub-classes to specialize the behaviour right within Clutter, a delegation pattern was preferred. layout is now deferred to ClutterLayoutManager; painting is delegated to ClutterContent.

delegation means that composition is the approach for creating apps; Clutter is, now more than ever, like a set of blocks that can be composed together to achieve a compelling, dynamic user interface.

let’s start from an actual example: whereas until 1.8 you had to use the ClutterContainer interface as the public side for building and manipulating the actor tree, now ClutterActor owns the entire list of public entry points for adding, removing, and iterating children; this also applies to the implementation of container actors: the ClutterContainer interface is implemented directly by the ClutterActor class, so you can just subclass the latter and use the default implementation without having to care about internal children, or memory management, or mapping and unmapping. even painting and picking by default will do the right thing — so you don’t have to care any more. when you subclass the ClutterActor class you can now concentrate only on the things your class has to do — instead of having to care about Clutter internals.

moving all the API from within the containers to the actors also meant being able to add a bunch of convenience functions for manipulating and iterating the actor tree; usually, these functions had to be provided by container classes, and thus had to be re-implemented over, and over, and over again. now, instead, you can get the first and last child of an actor, and iterate over their siblings; or you can create a simple, stack allocated iterator structure, and safely iterate over the children of an actor. you can insert actors at a specific index in the paint and allocation sequence, or you can replace a child atomically. finally, you can remove, or destroy, all the children of an actor in one fell swoop.

implementing the Container interface inside ClutterActor also allowed us to seamlessly migrate the ClutterLayoutManager delegate over to ClutterActor; this means that every actor can now delegate the layout of its children to any layout manager without requiring weird incantations.2

building the actor tree, though, it’s just part of the job of creating a Clutter app; we’ll see in the next blog post what changes happened when you want to fill an app with content…

  1. yes, I’m cheating a little bit, as a lot of documentation is inlined inside the source code, so that balloons the size of the delta []
  2. the layout manager API still needs some adaptations, which will come in the 1.12 time frame []

Calamity Song

I have written a bunch of blog posts about the Clutter Apocalypses that have landed in Git, as well as how I see the Clutter API evolving after this cycle and towards the 2.0 API break; they should appear in the next few hours, staggered a bit to avoid clogging the intertubes.

hopefully, I won’t bore you to death — but I’ll understand if you want to filter me out.

I’ll keep the comments section open, but feel free to use the clutter-devel mailing list: it’s much, much better than a comment in a blog.