How to create a cookiecutter for GTK projects

Cookiecutter is a small command-line Python utility used to generate projects from templates. It is largely used in the Python world, in particular for Django projects. You can find it here:

Cookiecutter GitHub repository: https://github.com/cookiecutter/cookiecutter

Cookiecutter Documentation: https://cookiecutter.readthedocs.io/

Despite its Python origin and vocation, Cookiecutter is a general-purpose tool. It can be used (ad is actually used) to generate any kind of software project. You can see a collection of Cookiecutters templates here:

https://github.com/search?q=cookiecutter&type=Repositories

Cookiecutter can also be used to create custom-tailored cookiecutter templates.

Things to know

Behind the scenes, Cookiecutter uses the same Jinja “template engine” used by Python’s Flask web framework:

https://jinja.palletsprojects.com/

This means that it just replace every “placeholder” found in a file (and in a file tree) with the value found in a given JSON file.

For example, if Cookiecutter finds this line in a file:

This file was created by {{author_name}}

And it has a JSON file with this line:

"author_name" = "Donald Duck"

Cookiecutter will just give you this line:

This file was created by Donald Duck

These new values are contained in a file called cookiecutter.json

By default, Cookiecutter processes a whole directory tree and all the files it contains giving you a new directory tree with the same files. Each file will contain the new values.

Weird file and directory names

Besides this, you have to be aware that Cookiecutter takes a part of its variables directly from the file system, in particular from the names of directories and files that are part of the source tree. This is the reason why, in a Cookiecutter source tree, you can see directories with names like this:

{{cookiecutter.directory_name}}

No matter how weird they can be, these names are perfectly legal on Linux (even if they make it hard to work on the command line, for example using the “cd” command) and Cookiecutter can use them to create file and directory names that depend on the content of its JSON file and/or are supplied by the user.

This simple structure makes it very easy to build your own cookiecutter template for your specific needs.

A GTK / Glade Cookiecutter example

As a starting point for our example, I will use the template suggested by Programmer’s Notes in Chapter 4 of his “GTK Glade Programming Tutorial” that you can find here:

https://prognotes.net/2015/07/gtk-3-glade-c-programming-template/

This template is intended to create a C-Language template for developing a GTK3 application for Linux using the Glade GUI designer.

The source tree

In a “regular” source tree, you would have this structure:

$ tree .                                                                                                                                        
.
├── glade
│   └── main_window.glade
├── makefile
└── src
    └── gtk_app.c

Replacing the usual file names with the “parametric” ones that will be used by Cookiecutter, we get the following source tree.

$ tree .
.
├── glade
│   └── main_window.glade
├── makefile
└── src
    └── {{cookiecutter.main_c_source_filename}}.c

Please note the {{cookiecutter.main_c_source_filename}}.c name for the main .c file.

Given that the top-level directory name must be “parametric”, we are forced to enclose the whole source tree in a “hosting” directory with a parametric Jinja name, like this:

$ tree .                                                                                                                                        
.
├── {{cookiecutter.directory_name}}
│   ├── glade
│   │   └── main_window.glade
│   ├── makefile
│   └── src
│       └── {{cookiecutter.main_c_source_filename}}.c
├── cookiecutter.json
├── LICENSE
└── README.md

Please note the {{cookiecutter.directory_name}} top-level directory name. This will be the name of the directory containing our “project” (or “source tree”).

Please note, as well, that the enclosing directory contains a bunch of auxiliary files, like README.md, LICENSE and – most important! – the cookiecutter.json file that contains the values for the variables used by Cookiecutter. These files are only part of the Cookiecutter template and will not be part of the resulting GTK/Glade project.

The main.c file

The main.c file does not contains anything that must depend on the user’s choices and can be left unmodified:

#include 

int main(int argc, char *argv[])
{
    GtkBuilder      *builder; 
    GtkWidget       *window;

    gtk_init(&argc, &argv);

    // builder = gtk_builder_new();
    // gtk_builder_add_from_file (builder, "glade/window_main.glade", NULL);
    // Update October 2019: The line below replaces the 2 lines above
    builder = gtk_builder_new_from_file("glade/main_window.glade");

    window = GTK_WIDGET(gtk_builder_get_object(builder, "main_window"));
    gtk_builder_connect_signals(builder, NULL);

    g_object_unref(builder);

    gtk_widget_show(window);                
    gtk_main();

    return 0;
}

// called when window is closed
void on_window_main_destroy()
{
    gtk_main_quit();
}

As you can see, it is exactly the same as in the original articles.

The main_window.glade file

The glade file is a XML file that describes the structure of the program’s GUI. It contains a title tag that depends on the user’s choices and for this reason, you can see a Jinja tag inside it:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.16.1 -->
<interface>
  <requires lib="gtk+" version="3.10"/>
  <object class="GtkWindow" id="main_window">
    <property name="can_focus">False</property>
    <property name="title" translatable="yes">{{cookiecutter.main_window_title}} Main Window</property>
    <property name="default_width">640</property>
    <property name="default_height">480</property>
    <signal name="destroy" handler="on_main_window_destroy" swapped="no"/>
    <child>
      <placeholder/>
    </child>
  </object>
</interface>

Please note the

{{cookiecutter.main_window_title}}

Injia tag for the main window title.

The makefile

The c makefile contains a couple of references to file names that depend on the user’s choice and must be “parametrized” accordingly:

TARGET={{cookiecutter.main_c_source_filename}}

# compiler
CC=gcc
# debug
DEBUG=-g
# optimisation
OPT=-O0
# warnings
WARN=-Wall

PTHREAD=-pthread

CCFLAGS=$(DEBUG) $(OPT) $(WARN) $(PTHREAD) -pipe

GTKLIB=`pkg-config --cflags --libs gtk+-3.0`

# linker
LD=gcc
LDFLAGS=$(PTHREAD) $(GTKLIB) -export-dynamic

OBJS=   {{cookiecutter.main_c_source_filename}}.o

all: $(OBJS)
    $(LD) -o $(TARGET) $(OBJS) $(LDFLAGS)
    
{{cookiecutter.main_c_source_filename}}.o: src/{{cookiecutter.main_c_source_filename}}.c
    $(CC) -c $(CCFLAGS) src/{{cookiecutter.main_c_source_filename}}.c $(GTKLIB) -o {{cookiecutter.main_c_source_filename}}.o
    
clean:
    rm -f *.o $(TARGET)

Please note the {{…}} Jinja tags.

How to use your new cookiecutter

Using this Cookiecutter template is as easy as to invoke the following command in your Linux terminal.

cookiecutter name-of-you-hosting-directory

On my Linux box, this boils down to:

cookiecutter /home/alex/Templates/Cookiecutters/cookiecutter_gtk_glade

If you use my example GitHub repository, you can use this command line:

cookiecutter https://github.com/alexbottoni/cookiecutter_gtk_glade.git

This command will download the template from GitHub and use it to generate a new GTK/Glade project in the directory of your choice. You will be asked:

  • A “directory_name” for the top-level directory of your source tree. It defaults to “gtk_glade_app”.
  • A “main_c_source_filename” for the name of your main C language file. It defaults to “main”.
  • A “main_window_title” for the top-level window of your GUI. It defaults to “Main Window”.

Source Code of this article

You can find the source code for this article here:

https://github.com/alexbottoni/cookiecutter_gtk_glade

Alex Bottoni

How to create a cookiecutter for GTK projects