I’ve been asked to review the GNOME 3 Application Development Guide for Beginners; I went through the book in about half a day and wrote this somewhat short review afterwards, and published on G+; sadly, I used a limited distribution, and G+ does not allow changing that without resharing your own post. given that I wanted to push it on the blog, I took the chance to review some of the stuff I wrote, and expand it.

my initial impression of the GNOME 3 Application Development Guide for Beginners book is fairly positive: the topics covered are interesting, and the book never loses itself in them, so that beginners will not feel utterly stranded after the first three chapters, as it too often happens with “for beginners” books. I appreciated the “pop quiz” sections, as well as the small sections that recommended improvements to the example code.

obviously, writing a book enshrines a certain set of requirements and APIs, and that is problematic when there is high churn – like what happens in GNOME 3, especially in terms of development tools (libraries and applications) and overall experience. for instance, the section on Clutter (which is the one I can immediately give feedback on, given my position) still uses the deprecated “default stage”, and yet it uses the new ClutterActor easing state for animations; the default stage was deprecated at long last in Clutter 1.10, but its use was not recommended since the days of 1.0; the actor easing state API was introduced in the same release that deprecated the default stage. also, the example code published in the Clutter section does not use any of the layout managers provided by Clutter, preferring the fixed positioning of the actors, which is perfectly fine on its own; the book, though, then proceeds to mention the amount of code necessary to get something on the screen, compared to the equivalent code in GTK, that uses boxes and grids. in general, that’s an utterly fair thing to say: Clutter sits at a lower-level than GTK, and it doesn’t have complex constructs like GTK does; I’m pretty sure, though, there are better examples than a row of boxes that could have used a BoxLayout, or a FlowLayout, or a GridLayout, or a TableLayout; or better examples than using an explicit PangoFontDescription instance with a ClutterText to set a specific font name and size, instead of using the ClutterText:font-name property which wraps the whole thing for the developer’s convenience. in short: Clutter is more “raw” than GTK, but there are convenience APIs for developers.

it’s been a long time ((this year is actually my 10th bug-versary)) since I started off as a beginner in developing with (and) GNOME, so all I can say about book for beginners is whether they are using what I write in the way I think it’s supposed to be used; as far as I’m concerned, apart from a couple of issues, this book is indeed providing a solid base for people that want to begin developing for GNOME and with GNOME.

the price is pretty accessible, compared to the cost of similar books: I’ve paid much, much more for an introductory book on Core Animation, or on Perl books; the ebook version, if you dislike the dead tree version, comes in various formats, including PDF and Kindle.

I’m not going to give votes or anything: it’d be a pointless number on an equally pointless scale; but if you’re a beginner, I think this book may be fairly interesting to you, if you want to start coding with GNOME technologies.

This is Why We Fight

one thing that bugged me since the implementation of the Clutter animation framework in its current form was the property access API in GObject — especially the boxing/unboxing of GValues. since GLib 2.28 2.24 we had a new macro (G_VALUE_COLLECT_INIT) that avoided doing unnecessary work, but the end result of setting a property was still:

  • box it inside a GValue
  • call the set_property implementation of your class
  • unbox the GValue
  • call the public setter function
  • set the value inside the private data structure
  • free the GValue

there are at least two unnecessary steps, there: the boxing inside GValue should only be necessary for transformation purposes — i.e. taking a GValue and running the transformation function from the passed value type to the property type — but that path should not be taken for variadic arguments functions like g_object_set() since the type used to read the value from the va_list is the property type itself and no transformation is necessary or possble; and calling the set_property() implementation, which is just a huge switch on the property id used when installing the property on a class, just to then call the public accessors. now, try modifying five or so properties at the same time on a hundred objects at 60 frames per second. you can probably get away with it — but only just.

last year, Rob Staudinger proposed some code that provided property access through both accessor functions and direct structure member access through field offset. sadly, I felt that his API was still repeating the same issues of the GParamSpec API: constructors with different signatures (try remembering the arguments and their order between integer properties, enumeration properties, string and boxed properties); reliance on a big switch inside the class implementation; and a general lack of integration with GObject itself.

the last point is mostly what interested me; GParamSpec is meant to be used as a validation tool for a value; it describes the constraints, the default, the prerequisite type, etc.. it’s used to describe properties, but that’s almost a side-effect — a GParamSpec can exist in a vacuum, and can be used regardless of GObject itself. if we wanted to access an object property, the object class should be far more involved in this. we should be able to tie the property description to the structure field that backs it in the implementation; we should be able to define the functions that access it; and we should be able to even provide a default implementation of these accessor functions without requiring developers to actually write them.

another issue with the current state of affairs with GObject properties is the amount of code you have to write. let’s look at a simple class mapping a bunch of fields to properties. right now, you’d have to write every single accessor pair, with hand-written validation; you’d have to hard-code the defaults in three places (the GParamSpec, the instance init function and the accessors); and you’d have to write the set_property() and the get_property() implementation, which end up calling the public accessors anyway because you want to do validation and notification of changes in one place only.

almost all of this code could be autogenerated, even through the C pre-processor.

so, to make a long story short, during the past couple of weeks I started fleshing out the implementation of a new property API for GObject — GProperty.

GProperty is still based on GParamSpec, but it hides all the nasty so you only get a bunch of constructors with the same signature (no more trips to devhelp to check out the <code>g_param_spec_enum()</code> order of arguments) and a generic API for setting constraints like ranges, default values and prerequisite types. plus, you get to specify the field and/or the accessor functions:

  test_object_property[PROP_FOO] =
    g_int8_property_new ("foo", G_PROPERTY_READWRITE,
                         G_STRUCT_OFFSET (TestObjectPrivate, foo),
                         NULL, /* setter */
                         NULL  /* getter */);

  test_object_property[PROP_BAR] =
    g_float_property_new ("bar", G_PROPERTY_READWRITE,
                          -1,
                          test_object_set_bar,
                          test_object_get_bar);

  g_object_class_install_properties (object_class,
                                     G_N_ELEMENTS (test_object_property),
                                     test_object_property);

there are a bunch of other features (automatic atomic properties, macros for auto-generating accessors, per-class default value overriding) for which I’ll just point you again to the bug and the GLib branch; today, though, I wanted to verify whether one of the reasons for working on this — making generic property access faster — actually benefited from these changes. it turns out that it really does: calling g_object_set() in a tight loop with simple values (integers and floating point) improved from the equivalent, GParamSpec-based classic implementation by 2.10x on my Core 2 Duo; if you throw a string into the mix, the improvement is by 1.5x. my initial ballpark figures were way smaller, so I was pleasantly surprised.

hopefully, this work will get more eyeballs during this cycle — and it’ll land in time for 2.32 (and Gnome 3.2).

Code Quality

Morten, it’s actually my fault.

the patch that was submitted was the incorrect one; I’ve been fixing the implementation since then, mostly because the API is correct — and went through different eyeballs to ensure that — and we wanted to land it before the GLib freeze. the implementation, alas, has issues — and not just the ones you saw.

as I said, it’s definitely my fault: I reviewed the original in a way that was less than acceptable. I sincerely apologize for that.

okay, having said that, and resuming my usual self: bitching on planet GNOME is not going to get anything fixed. insulting the maintainer when the issue lies mostly in a “patch lieutenant” (such as myself) is also not how polite people deal with errors.

finally, saying that the code needs to be taken out back is a lame cop-out and it is an untenable position for anyone contributing. the code went in, there were issues, so it needs to be fixed. if we waited for perfect code the amount of merged we’d get would be zero. that code has been in the bug for the past 6 months, and it’s been discussed in the past IRC meetings, with public minutes and logs.

so, please: file bugs. I’ll try to close them faster than you can open them.

Walk the line

I’ve noticed that I haven’t blogged about JSON-GLib in a while.

since the last time, I release version 0.10, which had a lot of fixes in the JSON ⬌ GObject transformation code, thanks to the contributions of Tristan Van Berkom. the 0.10 release allowed to transform all GObject properties of fundamental types — and to register transformation functions for boxed types as well. it also had bugs fixes coming from Clutter and other projects using JSON-GLib.

now we’re near the 0.12 release — I released the first release candidate on August 2nd, and I plan to do another release candidate along with the GNOME 2.31.90 snapshot.

for this cycle I’ve had the contribution of Luca Bruno, who wrote a JsonBuilder class which provides a simple API for building JSON trees. JsonBuilder has been inspired by JSONWriter and by GVariantBuilder:

JsonBuilder *builder = json_builder_new ();

json_builder_begin_object (builder);

json_builder_set_member_name (builder, "url");
json_builder_add_string_value (builder, "http://www.gnome.org/img/flash/two-thirty.png");

json_builder_set_member_name (builder, "size");
json_builder_begin_array (builder);
json_builder_add_int_value (builder, 652);
json_builder_add_int_value (builder, 242);
json_builder_end_array (builder);

json_builder_end_object (builder);

JsonGenerator *gen = json_generator_new ();
json_generator_set_root (json_builder_get_root (builder));
char *str = json_generator_to_data (generator);

g_object_unref (generator);
g_object_unref (builder);

/* "str" now contains the string:
 * { "url" : "http://www.gnome.org/img/flash/two-thirty.png", "size" : [ 652, 242 ] }
 */

in the same spirit, I had a fun two hours hacking session that resulted in an XmlReader-like API for JSON trees, called JsonReader:

/* str contains the JSON from the example above */
JsonParser *parser = json_parser_new ();
json_parser_load_from_data (parser, str, -1, NULL);

JsonReader *reader = json_reader_new (json_parser_get_root (parser));

json_reader_read_member (reader, "url");
const char *url = json_reader_get_string_value (reader);
json_reader_end_member (reader);

json_reader_read_member (reader, "size");

json_reader_read_element (reader, 0);
int width = json_reader_get_int_value (reader);
json_reader_end_element (reader);

json_reader_read_element (reader, 1);
int height = json_reader_get_int_value (reader);
json_reader_end_element (reader);

json_reader_end_member (reader);

g_object_unref (reader);
g_object_unref (parser);

I also added support for parsing (synchronously and asynchronously) JSON from a GInputStream and generating stringified JSON to a GOutputStream (in this case, only synchronously). this means that JSON-GLib now depends on GIO.

for the next cycle, which is going to be fairly relaxed in terms of duration, I’m planning some new features like support for the JSON Schema draft in the JsonParser class; and a sensible implementation of a Path API for direct access of members.

if you have bug reports, feature requests, or code you want to contribute, feel free to hop in Bugzilla and file a new ticket.

have fun!

Constraints

last time, I described the Effects in Clutter as anything that should affect the way an actor paints itself without sub-classing.

this kind of modification of the behaviour of an Actor can also be applied to other areas, and leads to defining three different kinds of modifiers:

  • Effects, which modify the way an actor paints itself
  • Actions, which modify the way an actor responds to user events
  • Constraints, which modify the way an actor is positioned or sized

being capable of being dragged using the pointer can be defined as an action: it changes the way an Actor responds to user events (button press, motion, button release). in the same way, update the X position using the X position of another actor is a constraint placed on an Actor.

Clutter already has signals, properties and virtual functions for dealing with these modifiers, and they can be seen as the building blocks. What’s missing is a set of classes that wrap those building blocks into something that leads to run-time composition of effects, actions and constraints on top of an existing Actor class.

last week I started working on the implementation of these modifiers, and now I’m pretty close to a finalized API for Clutter 1.4. the usage of an action is pretty simple:

  ClutterAction *action = clutter_drag_action_new ();
  g_signal_connect (action, "drag-motion",
                    G_CALLBACK (on_drag_motion),
                    NULL);

  clutter_actor_add_action (some_actor, action)
  clutter_actor_set_reactive (actor, TRUE);

the simplest implementation of a ClutterDragAction::drag-motion signal handler is:

  static void
  on_drag_motion (ClutterDragAction *action,
                  ClutterActor      *actor,
                  float              delta_x,
                  float              delta_y)
  {
    clutter_actor_move_by (actor, delta_x, delta_y);
  }

there’s no fundamental difference for the constraints API; for instance, this positions an actor in the middle of another:

  ClutterConstraint *constraint;

  constraint = clutter_align_constraint_new (parent, CLUTTER_ALIGN_X_AXIS, 0.5);
  clutter_actor_add_constraint (some_actor, constraint);

  constraint = clutter_align_constraint_new (parent, CLUTTER_ALIGN_Y_AXIS, 0.5);
  clutter_actor_add_constraint (some_actor, constraint);

it’s important to note that parent in this case can be any actor, and not necessarily the scene graph parent of some_actor.

this example binds the X coordinate of an actor to the X coordinate of another one, while keeping it Y aligned at the center of its parent:

  ClutterConstraint *constraint;

  constraint = clutter_bind_constraint_new (source, CLUTTER_BIND_X, 0.0);
  clutter_actor_add_constraint_with_name (some_actor, "x-bind", source);

  constraint = clutter_align_constraint_new (parent, CLUTTER_ALIGN_Y_AXIS, 0.5);
  clutter_actor_add_constraint_with_name (some_actor, "y-bind", constraint);

Update: I’ve updated the example to use the newly added add_constraint_with_name() instead of set_name()+add_constraint(); I also changed the constraint names.

now, I’ve added a call to clutter_actor_meta_set_name() in the mix because I might decide to animate the offset property of the ClutterBindConstraint using a specific syntax for ClutterAnimation ((the change is contained in ClutterActor so I’m not over-complicating the parsing code in the animation class itself; which also means that ClutterAnimator and the upcoming ClutterState classes will be able to use the same syntax to address action, effect and constraint properties)):

  float new_offset = clutter_actor_get_width (source) + h_padding;
  clutter_actor_animate (some_actor, CLUTTER_EASE_OUT_CUBIC, 500,
                         "@constraints.x-bind.offset", new_offset,
                         "opacity", 128,
                         NULL);

the new syntax is still type checked, so you’ll get warnings if you’re using the wrong type or the wrong interval ((I’m still considering using a dotted notation; I might switch to a colon notation, or a slash notation. and yes: I know that it looks like the syntax for key access in CoreAnimation; it turns out that there aren’t many new ways to access an item in a path)).

caveat: obviously, a constraint only applies to an actor that is in a fixed positioning layout manager.

the new classes and API are available in the wip/actor-actions branch here and wip/constraints branch here; there are also a couple of interactive tests that show you how actions and constraints can be used with existing actors. if all goes according to plan, I’ll merge them by the end of the week — following Frederic’s blog post, I want to make a 1.3 snapshot release in time for GNOME 2.31.2.