EggSettingsFlagAction

Using object bindings with GSettings is generally a snap. However, there are few places where it breaks down. One in particular for us in Builder was with “Flags Types”. A flags type can be thought of as an integer where a bit is either on or off, indicating a feature. You can think of them as a series of booleans.

We use this for the “Draw Spaces” feature in Builder. The data type in memory is a GTypeFlags (GtkSourceDrawSpacesFlags), and the underlying GSettingsSchema reflects that. However, in the schema you define a nickname. The setting is really an array of nicknames, indicating “on”. If the nickname is absent, the flag can be thought of as off. (Each name does map an integer value, which can simplify getting the value as a 32-bit uint). Handy.

We want to bind each item in the flags individually, which to the best of my knowledge cannot be done out of the box with GSettings. So we added a new GAction which can be used to bridge the gap between GtkActionable and GSettings. Simply set the properties to indicate which flag the action should toggle.

EggSignalGroup and EggBindingGroup

Have you ever had to deal with lots of GBinding or signal connection (and therefore disconnections) on indirect objects? A classic example for this is the GtkTextView:buffer GObject property.

It’s not uncommon to find vastly broken code when it comes to this. People will g_signal_connect() and never disconnect. Slightly better is to use g_signal_connect_object()[1]. However even that requires that one of the objects be finalized to work properly.

EggSignalGroup allows you to connect to a bunch of signals on a single target object as a group. You can connect and disconnect them simply by setting the EggSignalGroup:target property. I find this convenient because I can setup the EggSignalGroup in my instance init function, and simply set the target when it becomes available. You can even bind it using g_object_bind_property() for even less application code.

EggSignalGroup *group;

group = egg_signal_group_new (GTK_TYPE_TEXT_VIEW);
egg_signal_group_connect_object (group,
                                 "key-press-event",
                                 G_CALLBACK (press_event),
                                 self,
                                 G_CONNECT_SWAPPED);
egg_signal_group_connect_object (group,
                                 "key-release-event",
                                 G_CALLBACK (release_event),
                                 self,
                                 G_CONNECT_SWAPPED);

/* ... later on */
egg_signal_group_set_target (group, text_view);

/* ... and to disconnect */
g_clear_object (&group);
/* or */
egg_signal_group_set_target (group, NULL);

EggBindingGroup is similar in spirit, but for GBinding. You can create a series of delayed bindings and apply them as a set. Simply set the EggBindingGroup:source property to the GObject instance you would like to bind.

EggBindingGroup *group;

group = egg_binding_group_new ();
egg_binding_group_bind (group, "foo",
                        target, "foo",
                        G_BINDING_SYNC_CREATE);
egg_binding_group_bind (group, "bar",
                        target, "bar",
                        G_BINDING_SYNC_CREATE);

/* later on */
egg_binding_group_set_source (group, my_obj);

[1] g_signal_connect_object() used to be broken, but should work as expected.

GMenu Merging

One of the long missed features of GtkUIManager (at least from a complex application perspective) is menu merging. This is something that gets heavily used in “plug-in oriented” software. And as you might expect, a large code-base will often migrate into this direction simply out of code hygiene.

I implemented something akin to this in Builder so that plugins could easily merge into the application GMenus used by the application. You can find the header and source at egg-menu-manager.h and egg-menu-manager.c respectively.

To make things easier for plug-in authors, we have a feature similar to the automatic resources in GtkApplication. Just place your menus.ui at /org/gnome/builder/plugins/:plugin-name/gtk/menus.ui and it will be automatically loaded and unloaded with your plugin.

Build Panel

Did you know that Builder has a build panel finally? That’s right, you can actually do what the name says now. Of course, we only have one IdeBuildSystem implementation at the moment (autotools), but if you implement that interface, you too can have your project building.

Note that you can write build system implementations in Python or Vala now. That should lower the barrier for contributions quite a bit.

Build Panel

With build output

Never mind the CSS errors in the theme, those will be fixed soon enough ;)

Template-GLib

One of the things necessary in an IDE is the ability to create projects from templates. This is something we’ve been lacking since the beginning, and I’m finally in a position to follow through on it.

So, templates. What is a template? We have a couple layers of templates needed. We have, at a macro level, project templates. These are a collections of files, that get tweaked based on the project options.

Then we have per-file templates. These need to go through various tweaking and can get quite detailed, based on how much you want to do for the user.

I did a quick survey of what was available to reuse, and was not entire satisfied with the options. Thankfully I like programming languages and compilers, and decided to create exactly what I was hoping to find.

The result, was written over the past few days, and is called template-glib. It will look familiar to people who’ve used other template engines. Bits and pieces had inspiration from all over the place. I rather like python’s mako template API, but not much of a fan of the implementation. I also don’t want a bidirectional run-time[1] involved.

Some people really seem to like Go’s text templating. I’ve never used it, but like any language community full of crusaders, they’ll come to your door to let you know why they love it so much. Some things will be familiar to those people.

The API is designed in such a way that parsing and expanding the template are separate operations. If you were to use it in such a fashion, the parsing operation will be much less expensive.

Expanding of templates uses a TmplScope which can have inheritance. That allows for some nifty scoping control as you work your way down. I haven’t finished this to the level I’d like, but “it works”.

You can control resolving of included files using TmplTemplateLocator. This is similar to python mako’s TemplateLookup. Works as advertised.

You can include files, like:
{{include "foo.tmpl"}}

You can cycle through certain types of objects
{{for item in my_list}}
{{item.title}}
{{end}}

You can perform various expressions, including assignment.
{{x=sqrt(10)*sqrt(20)}}

You can call into methods via GObject Introspection.
{{item.short_description("with", "params")}}

You can use expressions in conditionals.
{{if item.year > 2016}}
Current: {{item.title}}
{{else}}
Archived: {{item.title}}
{{end}}

This code is very early, in fact less than a week old, but I’ll keep pushing it forward to add the features we need in Builder. Perhaps you’ll find it useful too. I’d certainly love to see someone make a nice GNOME 3 static blog generator.

You can find the lexer here and the parser here for the expression language.

[1] Bidirectional run-time meaning that objects can live en either the run-time or outside of it, and coordination of GC must occur.

Command line tools

There is one thing that has been important to me for a long time in Builder, but I’ve been unable to solve the problem correctly until recently. And that is command line tools.

I’m not naive enough to believe that I can convince every multi-decade Emacs and Vim user to switch to a Gtk-based application. Even if our emulation of such systems are perfect, the muscle-memory of launching them from the command line is entrenched in work-flows. Because of that, I wanted to export many of our tools via command line tools.

In git, Builder now has support for an ide command line tool. The goal is for plugins to export their features via a command line tool. The added benefit is that it can provide an easier way to test core functionality of your plugin.

These aren’t all finished, but this gives you an idea of where we are going.


# list available commands
ide --list-commands

# -d allows selecting target device
ide build -j 12 -d local

# clone/bootstrap/build, prepares for contribution
ide contribute gtk+

# create a shared library project
ide create-project foo-glib --template=library --with-tests

You get the idea. None of those work as advertised, but you know it goes, that’s the plan.