Cambalache 0.12.0 Released!

I am pleased to announce a new release of Cambalache a new RAD tool for Gtk 3 and 4!

Version 0.12.0 packs a year’s worth of new features and lots of improvements and bugfixes.

Workspace CSS support

Does your application use custom CSS? Now you can see CSS changes live in the workspace. All you need to do is add a new CSS file in the project and specify if you want it to be global or for one UI file in particular.

Keep in mind that GtkBuilder does not support CSS inline so your application still needs to load the CSS at runtime.

GtkBuildable Custom Tags

In an ideal world object properties would be enough to define your application UI but in reality it is not, so Gtk Widgets can define customs tags in their GtkBuildable implementation such as GtkWidget <style> or GtkComboBoxText <items>

This feature was missing in Cambalache, mostly because I do not want to add custom code to handle each case one by one, as you can imagine this would become really hard to keep up and maintain.

So I decided on a generic component that relies on minimum metadata to create the UI automatically. So let me know if your favorite Class is missing a custom tag!

Property Bindings

Another important feature missing is setting up properties binding directly in the property. While technically it was always possible to create a GBinding object, clicking on a property label and selecting the source object and property is much easier.

User Templates

Back in the day one of the main features of Glade 3 was being able to extend the widgets available to use without having to modify the source code. This was done by creating a XML widget catalog unfortunately this is a high bar for every application as it required not only writing an XML file describing all the metadata but also having a library to load the new types.

Having all of your application’s UI files in the same project allows exposing all the templates for use without any extra steps, all you need to do is have all your templates types in the same project and you will be able to use them immediately.

The only current limitation is that you wont be able to use any custom properties since they are defined in code and Cambalache does not have access to the GType. For that we still going to need to create a catalog file similar to Glade.

XML Fragments

Have you ever been in the position where you are forced to write the whole UI XML file by hand just because the shiny new (or old) feature you need is not supported?

Fear no more!! Custom XML fragments comes to the rescue!

This new feature sounds fancy but it just a way to manually define any XML fragment that you want to append to an object or UI even if it is not valid GtkBuilder.

This should be handy in lots of different situation from defining <menu> objects to setting custom properties in your customs widgets!

External object references

GtkBuilder lets you expose external objects to be reference inside the XML description, but Cambalache does not export broken references, instead it will let you declare which external object you will expose in your application using a special type “(external)” that only let you define its id.

Where to get it?

You can download the flatpak bundle from flathub

flatpak install --user flathub ar.xjuan.Cambalache

Run this first if you do not have flathub repo in your host

flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo

You can also get the source code from gitlab (see README.md for instructions)

git clone https://gitlab.gnome.org/jpu/cambalache.git

BTW I will be making point releases as soon as translations are updated!

enjoy!

 

Juan Pablo

Milonga in Flathub!

Cambalache 0.7.4 is now available in Flathub here

For the impatient, simply run this to install it:

flatpak install --user flathub ar.xjuan.Cambalache

Cambalache is a new RAD tool that enables the creation of user interfaces for Gtk and the GNOME desktop environment. It’s main target is Gtk 4 but it has been designed from the ground up to support other versions. It is released under LGPL v2.1 license and you can get the source code and file issues here

These are the relevant new features:

  • Interactive introduction
  • Workspace Gtk theme selection
  • Template support
  • New translations, German and Czech
  • Sponsors credit section

Interactive Introduction

Even tough the workflow is similar to Glade, there are some key differences like multiple UI files support in the same project, which means new concepts like import and export where introduced. Since I do not like writing documentation, who does? I made an interactive tutorial to show up the work flow.

Workspace Gtk theme

Would not be nice to have a way to easily change the theme of your app to see how it looks?

Thanks to rendering widgets out of process, setting a different theme for the workspace is trivial to implement. All I had to do is set the theme name in the renderer’s GtkSetting. Keep in mind that flatpak application can not access your host themes, you have to install flatpak Gtk theme extensions!

Template support

All modern applications should use templates extensively! So 0.7.4 has basic support for templates, all you have to do it toggle the Object Id check button of the toplevel widget you want as your template. In the near future I will add the option to use all the templates in a project as just another widget class.

New translations

Thanks to two new contributors Phil and Vojtěch Cambalache now has 3 translations.

  • de by PhilProg
  • cs by Vojtěch Perník
  • es

If you want to see it translated in your language, open an issue with a new MR and I will merge it asap.

Sponsors Credits Section

You can financially support development on Patreon, other options like Liberapay are under consideration.

My goal is to have a steady stream of donations so that I can dedicate at least one day a week to development and hire a part time QA engineer. This would help ensure continuous improvements and keep up with bugs reports.

So many many thanks to all the people that supports Cambalache!

  • Patrick Griffis
  • Platon workaccount
  • Sonny Piers
  • Felipe Borges
  • Javier Jardón

 

Merengue: Cambalache’s workspace

Lemon pie with Italian meringueCambalache is a new RAD tool that enables the creation of user interfaces for Gtk and the GNOME desktop environment, it’s main focus is on the newly released Gtk 4 library but it has been designed from the ground up to support other versions.

It started as a proof of concept data model for Glade meant to try out all the crazy ideas I had during the years about how a clean model should be.

A few months later I had a pretty good data model that matched GObject type system quite well and did not depend on GtkBuilder nor GObject.

The model could:

  • Import and export multiple UI at once
  • Support plain (no custom tags) GtkBuilder features
    • Objects
    • Properties
    • Signals
    • Children
    • Packing/layout properties
  • Undo / Redo stack
  • History command compression and grouping

With that in mind one late night while holding my newborn daughter in one hand, I decided it was time to put it to test so I fired up Glade with the other hand and started a GUI prototype which quickly evolved into Cambalache, as my few dozen Twitter followers can assess. @XjuanAr

At this point the GUI supported most of the data model features.

One big difference with Glade is that Cambalache supports multiple UI in the same project so you need to ‘export all’ in order to create them as you can see at the end of the screencast bellow.

At this point I had a very specialized XML editor but… there is always a but, what about the workspace? the place where the UI is shown, rearranged, edited…

For the workspace my requirements are:

  • It should look and feel as close to the real UI as possible
  • Support multiple toolkits (Gtk 3, 4, 2 if really needed, libreoffice?)
  • Out of process to avoid loosing data on an eventual crash
  • It should look and feel as close to the real UI as possible, really!

Obviously adding the widgets directly like we did in Glade would not work if we want to support more than one version of Gtk since you can not mix them in the same process.

So we need a way to render widgets in a different process and show them somehow in the workspace… GtkPlug/GtkSocket would only work on X11.

Merengue enters the picture!

Fortunately this was not the first time I had to deal with such problem (See Maxwell) this reminded me of Alexander Larsson’s excellent project called Broadway a Gdk backend for the web. Ideally I would use an embedded Wayland compositor widget instead of a webview and broadway, but unfortunately there is only an old non working prototype called Wakefield and finishing it is a project on its own. In any case replacing the webview with a wayland compositor widget would be trivial.

Merengue is the name of the process Cambalache uses to render the UI while the user creates it, it is a regular Gtk 3 or Gtk 4 application depending on the version your project is targeting that just connects to Broadway and talks to the main application in JSON trough stdout/stdin pipes.

I will be talking more about Cambalache and the rationale behind starting a new project instead of porting Glade at GUADEC

See you there!

UPDATE: Cambalache source code released under the LGPL 2.1, get it here!

GUADEC a la española

Tapas, jamón are the first words that come to my mind after this year GUADEC in Almería

One of the best part of traveling is discovering new customs and trying new things…

 

 

 

 

Do you want tomato with your toast for breakfast?

– Sure!

 

 

 

What about tuna?

– why not!

 

 

 

 

But more important than food, for me GUADEC is always about the people, meeting new people, people you always respected (still can not believe I meet the legendary JH) or putting a face to an irc nickname or email (albfan, never expected you to be so tall!) and of course catching up with old friends because being able to continue talking with someone like if it was yesterday when in fact it was a year, is priceless.

This GUADEC was special to me because it was the first time I did not talked about Glade, instead I showed a new library called Maxwell I made working at Endless.

What is Maxwell?

Maxwell is a proof of concept library that extends WebKitWebView and lets you embed/pack Gtk widgets in it as a regular Gtk container.

Etymology

The project started inspired by the Broadway Gdk backend which lets you run any Gtk application over HTTP using HTML5 and web sockets which was named after X Consortium’s Broadway release where one of its key features was X-Agent 96.

X Agent 96 => Agent 86 => Maxwell Smart => Maxwell

How does it work?

The introduction of the split process model in WebKit2 made embedding widgets in WebView rather difficult since part of WebKit operates in one process and the rest like WebCore and JS engine in another (UI/Web process).

Maxwell takes a similar approach to Broadway, all it needs is a way to render widgets in the DOM tree and get events from them.

To render widgets we use a CANVAS element the same size of the widget and a custom URI scheme to get the raw image data from each widget.

/* Get image data from widget */
let xhr = new XMLHttpRequest();
xhr.open('GET', 'maxwell:///widget_id', false);
xhr.responseType = 'arraybuffer';
xhr.send();

/* Render image data in canvas */
let data = new Uint8ClampedArray(xhr.response);
let image = new ImageData(data, canvas.width, canvas.height);
canvas.getContext('2d').putImageData(image, 0, 0);

On the Gtk side, each child is rendered in an offscreen window which we use as the source image data to implement the custom URI scheme handler.

Gtk UI process JavaScript/WebCore
GtkWidget:draw↴
Damage event ⟶ JS child_draw() ⟶ GET maxwell://
URI handler ⟵
↳[offscreen]⟶[GdkPixbuf]⟶GIOStream ⟶ [ImageData]↴
putImageData()

For events all we have to do is properly implement GdkWindow::pick-embedded-child and let Gtk know which child widget should get the event. In order to do so we need to keep track of the elements position relative to WebView’s viewport which can be calculated with getBoundingClientRect().

API

The API is pretty straightforward, all you have to do is name the child widget and add it using regular GtkContainer API.

/* Create a Maxwell Web View */
webview = maxwell_web_view_new ();

/* Create a widget to embed */
entry = gtk_entry_new ();

/* Set a unique name on the widget */
gtk_widget_set_name (entry, "myentry");

/* Add widget to web view container */
gtk_container_add (GTK_CONTAINER (webview), entry);

In order for MaxwellWebView to know where to place a child in the DOM tree you need to add a CANVAS element with a “GtkWidget” class and the unique ID you used as the widget’s name.

<canvas class="GtkWidget" id="myentry"></canvas>

Maxwell will also try to honor width and height style properties set on the canvas element. So for example if you want your widget to expand horizontally you can do:

<canvas class="GtkWidget" style="width: 100%;" id="myentry"></canvas>

You can get it at https://github.com/endlessm/maxwell

Sponsored by GNOME FoundationAs usual I would like to thanks the GNOME Foundation for sponsoring my trip to Spain and making all this possible.

 

 

 

Finally some extra pictures…

Developer Experience Hackfest 2016

Sponsored by GNOME FoundationFirst of all I would like to thanks the GNOME Foundation for sponsoring once again my trip to Brussels for the GNOME Developer Experience Hackfest.
Besides hacking on Glade and attending FOSDEM I had a great time meeting with old friends and making new ones, not to mention the amount and variety of beers consumed!

beerBut beer was not the only thing we had!

wafles

Back on the hacking, together with Tristan we managed to fix several bugs and add the much needed support for id-less objects! This way Glade is one step closer to support every Gtk+ template file.
I will not go into much details since it was already covered by him in his blog post

Pretty workspace

Besides doing some CSS cleanups in the workspace and user survey window to improve theme compatibility I added the modernized original Glade logo to the workspace background as a tribute to Glade roots!
Glade workspace logo

I also got the chance to work on the Glade User Survey results, the final results will be posted soon on Glade’s website once I finish automating the results from the Data Base.

Glade User Survey Preliminary Results

3114 people took the time to fill the survey since 11-11-2013.
54 % of them use it for commercial purposes and 42 % for personal use.
Most users are from the US and Brazil with Germany, China and France as a close third.

USA 10.98 % Italy 3.44 %
Brazil 10.18 % Spain 3.37 %
Germany 6.29 % UK 3.11 %
China 5.59 % Canada 2.37 %
France 4.65 % Poland 2.21 %
Mexico 4.07 % Argentina 1.70 %
Russia 3.85 % Australia 1.47 %
India 3.76 % Turkey 1.44 %

How long have you been programming? (years)

< 1 5.17 % 11 – 20 15.83 %
1 – 2 30.72 % 21 – 30 6.26 %
3 – 5 18.49 % 31 – 40 2.95 %
6 – 10 18.33 % > 40 2.21 %

Not Programmer 16.66 %

Preferred programming languages do you prefer?

Python 50.32 % JavaScript 21.80 %
C 47.01 % C Sharp 15.25 %
CPP 38.59 % Vala 9.24 %
Java 24.85 % Perl 6.96 %
Other 25.49 %

When did you start using Glade? (years ago)

1 58.38 % 4 – 5 5.94 %
2 4.94 % 6 – 10 6.48 %
3 2.79 % > 11 2.98 %

Which version do you normally use?

What is available in my OS 82.72 % Master 1.47 %
Latest stable from sources 9.44 % Other 0.83 %
3.8 for Gtk+ 2 3.94 %

On what operating system?

Linux 58.83 % OSX 1.02 %
Windows 2.69 % BSD 0.96 %
Other 1.25 % Solaris 0.44 %

How often do you use it?

Every day 43.89 % Few days a week 10.82 %
A few times a year 20 % Every week 5.84 %
A few times a month 13.96 % Once a month 3.94 %

What level of Glade user would you say you are?

Beginner 78.29 %
Intermediate 16.44 %
Advanced 3.78 %

Under what kind of license(s) do you release the software you used Glade to create?

Free Software 42.19 % None 25.72 %
Open Source 34.32 % Commercial 9.5 %

In which field(s) is the software you used Glade to create generally used?

Desktop applications 42.77 % Industrial applications 8.95 %
Academic 18.68 % Embedded applications 7.35 %
Educational 13.48 % Accounting 4.56 %
Scientific 12.13 % Medical 2.92 %

In your opinion what is the biggest problem with Glade?

Lack of documentation 66.89 %
Other 11.23 %
Lack of publicity/exposure 9.79 %
Lack of official binary releases for other OS (Win32, OSX) 5.78 %
Lack of professional training 2.63 %
Lack of professional support 1.5 %

18 % of users found a bug, 6.9 % reported it and 21.96 % contributed to the project.

Porting widgets to the new template API… the LAZY way!

First of all I want to thanks everyone involved in GUADEC organization specially to the GNOME foundation for sponsoring me once again.

It is been great meeting with old friends and making new ones!

So after Tristan’s talk UI developer experience with Glade/GtkBuilder where he talked about the new template API some good friend of us, lets see if you can guess who, came and ask:

friend: How do I port my widgets to the new templates stuff?
friend: I do not want to redo all of them in glade
me: What kind of widgets?
friend: “A grid with some s#it in it!”
me: hmmm…
 

So we talked about it and told him if that he was that lazy not to redo all widgets in glade manually he could do some function that iterate over containers and spit some xml to get at least the hierarchy right.

As we all know the lazier a programmer is the better, since it will end up writing a program to do its chores!

Anyways I did!

I made a function you can paste in your program and use it together with libgladeui api to dump a runtime GtkWidget to an xml definition.

#include <gladeui/glade.h>

/* Create a Glade project */
GladeProject *project = glade_project_new ();

/* add as many widgets as you want in the project */
glade_project_add_widget_from_object (project, widget, NULL);

/* And then save it to a file */
glade_project_save (project, "myclass.ui", NULL);

And that is all you have to do if the widget is simple enough.
You will have to mark internal children manually since there is no easy way to introspect them, say for example you want to dump a GtkDialog derived widget…

#include <gladeui/glade.h>

/* Create a Glade project */
GladeProject *project = glade_project_new ();

/* We need to mark every internal children manually */
INTERNAL_CHILD (gtk_dialog_get_action_area (GTK_DIALOG (widget)),
                "action_area");
INTERNAL_CHILD (gtk_dialog_get_content_area (GTK_DIALOG (widget)),
                "vbox");

/* add as many widgets as you want in the project */
glade_project_add_widget_from_object (project, widget, NULL);

/* And then save it to a file */
glade_project_save (project, "myclass.ui", NULL);

Here is the cut&paste code glade_dump.c

This is obviously hacky code, it was not heavily tested and will probably make gladeui and gtk API complain a lot but it works pretty well for what is intended.

BTW you have to link with gladeui-2.0 library for this code to work!

I think that is all, happy porting!

Sponsored by GNOME Foundation

GtkBuilder and external objects

What if you want to reference an object you created from a GtkBuilder script? or even more add children to a container created outside the scope of GtkBuilder?

You can not!

But do not worry, a simple API like the following will allow us to reference any external object from builder.

void gtk_builder_expose_object (GtkBuilder *builder,
                                const gchar *name,
                                GObject *object);

Now consider a GtkBuilder script like this…

<interface>
  <object class="GtkButton" id="button">
    <property name="image" external-object="True">image</property>
    <signal name="clicked" handler="on_button_clicked"
     object="builder" external-object="yes"/>
  </object>
</interface>

All you have to do is tell builder which objects are external setting the “external-object” parameter then is as simple as calling gtk_builder_expose_object() to actually expose it.
Please note that the external-object parameter is needed to avoid naming space conflicts.

GtkWidget *image = gtk_image_new ();
GtkBuilder *builder = gtk_builder_new ();
gtk_builder_expose_object (builder, "image", G_OBJECT (image));
gtk_builder_expose_object (builder, "builder", G_OBJECT (builder));
gtk_builder_add_from_string (builder, buffer, -1, &error);

Ok but what about adding children to an existing container ?¿

The first idea was to use a fragment of builder xml format (basically the &ltchild&gt tag) and a new API gtk_builder_add_to_parent_*() but then I realize that would prevent us from setting properties on the external object and also it will not allow us to define anarchist objects that is objects outside the container hierarchy like for example a GtkAction.

So instead, I decided to add a new element: <template>

This new element is similar to <object> with the only difference it will be used as an entry point for the external object referenced by the template id.
Now with a template defined by this xml you can add children and set properties on an external object called “mybox”

<?xml version="1.0"?>
<interface>
  <!-- interface-requires gtk+ 3.0 -->
  <template class="GtkBox" id="mybox">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <child>
      <object id="entry">
        <property name="visible">True</property>
        <property name="can_focus">True</property>
      </object>
      <packing>
        <property name="expand">False</property>
        <property name="fill">True</property>
        <property name="position">0</property>
      </packing>
    </child>
    <child>
      <object id="button">
        <property name="label">gtk-apply</property>
        <property name="visible">True</property>
        <property name="can_focus">True</property>
        <property name="receives_default">True</property>
        <property name="use_stock">True</property>
      </object>
      <packing>
        <property name="expand">False</property>
        <property name="fill">True</property>
        <property name="position">1</property>
      </packing>
    </child>
  </template>
</interface>

by simply using gtk_builder_add_from_string() in conjunction with gtk_builder_expose_object() like this:

builder = gtk_builder_new ();
mybox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
g_object_ref_sink (mybox);
gtk_builder_expose_object (builder, "mybox", G_OBJECT (mybox));
gtk_builder_add_from_string (builder, buffer, -1, &error);

Pretty simple is not it?

Patch available @ Bugzilla #688205 or if you prefer git this is the branch I been working on

git checkout -b composite-templates origin/composite-templates

Embeding GtkBuilder UI definitions into GObject classes!

Wait, what?

Back in the day Glade used to generate code which was messy if was not handled properly, eventually everyone agreed it was better to use libglade instead and load the UI interface from a xml file, something that got consolidated with the advent of GtkBuilder in GTK+

So if it’s better for applications, shouldn’t be the same for classes?

I believe so, this is why I am continuing the work that Tristan started in composite-widget-templates GTK+ branch  in my own branch named composite-template.

The idea is pretty simple,  instead of hand coding composite children in _init(), like most widget classes do or in _constructor() where they should all we need to do is set a template in _class_init() as follow

gtk_container_class_set_template (container_class,
                                  "foobar.ui",
                                  GTK_CONTAINER_TEMPLATE_FILE);

and voilà! GtkContainer class will build your children from that template using GtkBuilder at construction time. If you need to expose an internal child then all you have to do is declare it as follow

gtk_container_class_set_template (container_class,
                                  "foobar.ui",
                                  GTK_CONTAINER_TEMPLATE_FILE);
gtk_container_class_declare_internal_child
    (container_class, TRUE,
     G_STRUCT_OFFSET (FooBarPrivate, vbox),
     "vbox");

And if you do not like the idea of depending on a file, like I do, for your widget class to work you can use a string or even better a GResource.

but Juan, what about performance?

Obviously there is some extra overhead in the parsing but is not going to be significant in a medium/big size project that already uses GtkBuilder for it’s main interface. That being said if we want to optimize things the easy way would be to use EXI (Efficient XML Interchange) format which is basically a XML binary format, it would save use some memory space and the need to actually parse the UI definition. The hard way  would be to rethink GtkBuilder internal data model and transform it into a binary format that can be saved persistently. Implementing either of these approaches at the GMarkup level would not only be helpful for composite classes but more importantly for applications with big UI files.

Really wait, Say that again!

Ok, I should probably had started with an example, lets say you have a login dialog like this

With the following C source: foo-login-dialog.h foo-login-dialog.c

This code show the differences implementing a composite object the regular way and using templates. Note that USE_TEMPLATE macro is used to choose either implementation at compile time.

#include "foo-login-dialog.h"
 
struct _FooLoginDialogPrivate
{
  GtkWidget *username_entry;
  GtkWidget *password_entry;
};
 
enum
{
  LOGIN,
 
  LAST_SIGNAL
};
 
static guint login_dialog_signals[LAST_SIGNAL] = { 0 };
 
G_DEFINE_TYPE (FooLoginDialog, foo_login_dialog, GTK_TYPE_DIALOG);
 
void
on_dialog_response (FooLoginDialog *dialog, gint response_id)
{
  FooLoginDialogPrivate *priv = dialog->priv;
  const gchar *username, *password;
 
  if (response_id != GTK_RESPONSE_OK) return;
 
  username = gtk_entry_get_text (GTK_ENTRY (priv->username_entry));
  password = gtk_entry_get_text (GTK_ENTRY (priv->password_entry));
 
  g_signal_emit (dialog, login_dialog_signals[LOGIN], 0,
                 username, password);
}
 
static void
foo_login_dialog_init (FooLoginDialog *dialog)
{
  FooLoginDialogPrivate *priv;
 
  priv = G_TYPE_INSTANCE_GET_PRIVATE (dialog,
                                      FOO_TYPE_LOGIN_DIALOG,
                                      FooLoginDialogPrivate);
  dialog->priv = priv;
 
#ifndef USE_TEMPLATE
  GtkWidget *content_area;
  GtkWidget *action_area;
  GtkWidget *grid;
  GtkWidget *label;
  GtkWidget *button;
 
  content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
  action_area = gtk_dialog_get_action_area (GTK_DIALOG (dialog));
 
  grid = gtk_grid_new ();
  g_object_set (grid, "margin", 6, NULL);
  gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
  gtk_grid_set_row_spacing (GTK_GRID (grid), 4);
  gtk_box_pack_start (GTK_BOX (content_area), grid, TRUE, TRUE, 0);
 
  label = gtk_label_new ("User name:");
  gtk_widget_set_halign (label, GTK_ALIGN_END);
  gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
  priv->username_entry = gtk_entry_new ();
  gtk_widget_set_hexpand (priv->username_entry, TRUE);
  gtk_grid_attach (GTK_GRID (grid), priv->username_entry,
                   1, 0, 1, 1);
 
  label = gtk_label_new ("Password:");
  gtk_widget_set_halign (label, GTK_ALIGN_END);
  gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1);
  priv->password_entry = gtk_entry_new ();
  gtk_widget_set_hexpand (priv->password_entry, TRUE);
  gtk_entry_set_visibility (GTK_ENTRY (priv->password_entry),
                            FALSE);
  gtk_entry_set_activates_default (GTK_ENTRY (priv->password_entry),
                                   TRUE);
  gtk_grid_attach (GTK_GRID (grid), priv->password_entry,
                   1, 1, 1, 1);
 
  button = gtk_button_new_from_stock ("gtk-cancel");
  gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button,
                                GTK_RESPONSE_CANCEL);
 
  button = gtk_button_new_from_stock ("gtk-ok");
  gtk_widget_set_can_default (button, TRUE);
  gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button,
                                GTK_RESPONSE_OK);
  gtk_widget_grab_default (button);
 
  g_signal_connect_swapped (priv->username_entry, "activate",
                            G_CALLBACK (gtk_widget_grab_focus),
                            priv->password_entry);
 
  gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
  g_signal_connect (dialog, "response",
                    G_CALLBACK (on_dialog_response),
                    NULL);
#endif
}
 
static void
foo_login_dialog_finalize (GObject *object)
{
  G_OBJECT_CLASS (foo_login_dialog_parent_class)->finalize (object);
}
 
static void
foo_login_dialog_login (FooLoginDialog *self,
                        const gchar *username,
                        const gchar *password)
{
  g_message ("%s user: [%s] password: [%s]",
             __func__, username, password);
}
 
static void
foo_login_dialog_class_init (FooLoginDialogClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  GtkDialogClass *parent_class = GTK_DIALOG_CLASS (klass);
 
  g_type_class_add_private (klass, sizeof (FooLoginDialogPrivate));
 
  object_class->finalize = foo_login_dialog_finalize;
 
  klass->login = foo_login_dialog_login;
 
  login_dialog_signals[LOGIN] =
    g_signal_new ("login",
                  G_OBJECT_CLASS_TYPE (klass),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (FooLoginDialogClass, login),
                  NULL, NULL,
                  NULL,
                  G_TYPE_NONE, 2,
                  G_TYPE_STRING, G_TYPE_STRING);
 
#ifdef USE_TEMPLATE
  gtk_container_class_set_template (GTK_CONTAINER_CLASS (klass),
                                    "foologindialog.ui",
                                    GTK_CONTAINER_TEMPLATE_FILE);
  gtk_container_class_declare_internal_child
    (GTK_CONTAINER_CLASS (klass), TRUE,
     G_STRUCT_OFFSET (FooLoginDialogPrivate, username_entry),
     "username_entry");
  gtk_container_class_declare_internal_child
    (GTK_CONTAINER_CLASS (klass), TRUE,
     G_STRUCT_OFFSET (FooLoginDialogPrivate, password_entry),
     "password_entry");
#endif  
}
 
GtkDialog *
foo_login_dialog_new ()
{
  return g_object_new (FOO_TYPE_LOGIN_DIALOG, NULL);
}

main.c: a simple program using such class, this is included in foo-login-dialog.c for convenience

#include <gtk/gtk.h>
#include "foo-login-dialog.h"
 
int main (int argc, char **argv)
{
  GtkDialog *dialog;
 
  gtk_init (&argc, &argv);
 
  dialog = foo_login_dialog_new ();
  gtk_widget_show_all (GTK_WIDGET (dialog));
 
  gtk_dialog_run (dialog);
}

You can compile it with a line like this

gcc -export-dynamic -o foo-login-dialog main.c foo-login-dialog.c \
 `pkg-config --libs --cflags gtk+-3.0` -DUSE_TEMPLATE

GtkBuilder template “foologindialog.ui”

<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <!-- interface-requires gtk+ 3.0 -->
  <template class="FooLoginDialog" parent="GtkDialog" id="this">
    <property name="can_focus">False</property>
    <property name="border_width">5</property>
    <property name="type_hint">dialog</property>
    <signal name="response" handler="on_dialog_response" swapped="no"/>
    <child internal-child="vbox">
      <object id="dialog-vbox1">
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <property name="spacing">2</property>
        <child internal-child="action_area">
          <object id="dialog-action_area1">
            <property name="can_focus">False</property>
            <property name="layout_style">end</property>
            <child>
              <object id="button1">
                <property name="label">gtk-cancel</property>
                <property name="use_action_appearance">False</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <property name="use_action_appearance">False</property>
                <property name="use_stock">True</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object id="button2">
                <property name="label">gtk-ok</property>
                <property name="use_action_appearance">False</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="can_default">True</property>
                <property name="has_default">True</property>
                <property name="receives_default">True</property>
                <property name="use_action_appearance">False</property>
                <property name="use_stock">True</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">1</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="pack_type">end</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object id="grid1">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="row_spacing">4</property>
            <property name="column_spacing">6</property>
            <child>
              <object id="label1">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="halign">end</property>
                <property name="label" translatable="yes">User name:</property>
              </object>
              <packing>
                <property name="left_attach">0</property>
                <property name="top_attach">0</property>
                <property name="width">1</property>
                <property name="height">1</property>
              </packing>
            </child>
            <child>
              <object id="label2">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="halign">end</property>
                <property name="label" translatable="yes">Password:</property>
              </object>
              <packing>
                <property name="left_attach">0</property>
                <property name="top_attach">1</property>
                <property name="width">1</property>
                <property name="height">1</property>
              </packing>
            </child>
            <child>
              <object id="username_entry">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="hexpand">True</property>
                <property name="invisible_char"></property>
                <signal name="activate" handler="gtk_widget_grab_focus" object="password_entry" swapped="yes"/>
              </object>
              <packing>
                <property name="left_attach">1</property>
                <property name="top_attach">0</property>
                <property name="width">1</property>
                <property name="height">1</property>
              </packing>
            </child>
            <child>
              <object id="password_entry">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="hexpand">True</property>
                <property name="visibility">False</property>
                <property name="invisible_char"></property>
                <property name="activates_default">True</property>
              </object>
              <packing>
                <property name="left_attach">1</property>
                <property name="top_attach">1</property>
                <property name="width">1</property>
                <property name="height">1</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
      </object>
    </child>
    <action-widgets>
      <action-widget response="-6">button1</action-widget>
      <action-widget response="-5">button2</action-widget>
    </action-widgets>
  </template>
</interface>
<?xml version="1.0" encoding="UTF-8"?>
<interface>

Since this example sets the template from a relative path the file foologindialog.ui has to be in the current working directory when you run the program.
And last but not least you need composite-templates Gtk+ branch for this to work

$ git clone git://git.gnome.org/gtk+
$ cd gtk+
$ git checkout -b composite-templates origin/composite-templates