Fun to Program – GNOME

Date: 2013/08/16 (initial publish), 2021/08/08 (last update)

Source: en/fun2-00016.md

Previous Post Top Next Post

TOC

This was originally written and created around 2013 and may require to be updated. (2021)

GNOME

The choice of the best GUI program practice is not simple since there are many choices for GUI platforms, many outdated documentations, new features without updated tutorials, and future uncertainties.

Despite people had very negative reaction to the GNOME3 due to its new default user experience, I chose it as my GUI example platform for its fundamental internal technical merits. We can always customize the user experience part.

Here is my best effort to capture the recent GUI framework history for GNOME and best sources for references. (The latest stable is GNOME3.4 as of 2012 Summer.)

GNOME history

GTK+ is the GUI toolkit for GNOME and is build on the top of C with GLib and GObject. It requires many chores with boiler plate macro definitions when used directly from a C program. Its modularity as a GUI toolkit has evolved roughly as follows.

GNOME has evolved significantly with its http://en.wikipedia.org/wiki/Inter-process_communication[inter-process communication (IPC)] structure. Its history is roughly as follows.

GNOME3 applications are just plain GTK+3 applications. There is no code bloat by CORBA any more.

https://live.gnome.org/GObjectIntrospection/Users[The language binding system based on GObject-Introspection] can provide:

GObject-Introspection xml data of each library can be found under the /usr/share/gir-1.0 directory.

Glib and GObject

Dynamic memory management using malloc() etc. is a big headache when coding with C.:

Such complication can be avoided using libraries such as Glib and GObject.

GLib is a general-purpose utility library, which provides many useful data types, macros, type conversions, string utilities, file utilities, a mainloop abstraction, utility data structures, and so on.

GString offered in GLib is a data structure and associated methods offering text buffers which grow automatically as text is added with the proper dynamic memory management.

Source to convert to upper case.

#include <stdlib.h>
#include <glib.h>
#include <glib/gprintf.h>

int main(int argc, char** argv) {
    GString a;
    if (argc == 2) {
    	a = *g_string_new(argv[1]);
    	g_printf("input  = '%s'\n", a.str);
    	a.str = g_ascii_strup(a.str, a.len);
    	g_printf("OUTPUT = '%s'\n", a.str);
    } else {
    	g_printf("%s put_word_to_be_printed_uppercase\n", argv[0]);
    }
    return EXIT_SUCCESS;
}

If we try to guess the library name and header location, it is not easy to get them right.

Manual failed compilation

$ gcc -Wall -I/usr/include/glib-2.0 -lglib-2.0 -o upper-ng upper.c
In file included from /usr/include/glib-2.0/glib/galloca.h:34:0,
                 from /usr/include/glib-2.0/glib.h:32,
                 from upper.c:2:
/usr/include/glib-2.0/glib/gtypes.h:34:24: fatal error: glibconfig.h: No such fil...
 #include <glibconfig.h>
                        ^
compilation terminated.

Many modern libraries provide *.pc files in their development packages. You can use it with pkg-config to get proper compilation options for the glib library. Let’s look for such thing for glib.

Search the development package of Glib

$ apt-cache search 'libglib[0-9.-]*-dev'
libglib2.0-dev - Development files for the GLib library

If the libglib2.0-dev package has not been installed, install it now.

Search the right *.pc file for Glib for use with pkg-config.

Search the right *.pc file for Glib

$ grep -e "^Description\|^Name\|^Requires" \
   $(dpkg -L libglib2.0-dev|grep -e "/pkgconfig/")| \
   sed -ne "s/^.*\/pkgconfig\//.../p"
...gmodule-export-2.0.pc:Name: GModule
...gmodule-export-2.0.pc:Description: Dynamic module loader for GLib
...gmodule-export-2.0.pc:Requires: glib-2.0
...glib-2.0.pc:Name: GLib
...glib-2.0.pc:Description: C Utility Library
...glib-2.0.pc:Requires.private: libpcre
...gio-unix-2.0.pc:Name: GIO unix specific APIs
...gio-unix-2.0.pc:Description: unix specific headers for glib I/O library
...gio-unix-2.0.pc:Requires: gobject-2.0,gio-2.0
...gmodule-no-export-2.0.pc:Name: GModule
...gmodule-no-export-2.0.pc:Description: Dynamic module loader for GLib
...gmodule-no-export-2.0.pc:Requires: glib-2.0
...gio-2.0.pc:Name: GIO
...gio-2.0.pc:Description: glib I/O library
...gio-2.0.pc:Requires: glib-2.0 gobject-2.0
...gio-2.0.pc:Requires.private: gmodule-no-export-2.0
...gthread-2.0.pc:Name: GThread
...gthread-2.0.pc:Description: Thread support for GLib
...gthread-2.0.pc:Requires: glib-2.0
...gmodule-2.0.pc:Name: GModule
...gmodule-2.0.pc:Description: Dynamic module loader for GLib
...gmodule-2.0.pc:Requires: glib-2.0
...gobject-2.0.pc:Name: GObject
...gobject-2.0.pc:Description: GLib Type, Object, Parameter and Signal Library
...gobject-2.0.pc:Requires: glib-2.0

The glib-2.0.pc file is the right file.

The glib-2.0.pc file found on the Debian wheezy system.

prefix=/usr
exec_prefix=${prefix}
libdir=${prefix}/lib/x86_64-linux-gnu
includedir=${prefix}/include

glib_genmarshal=glib-genmarshal
gobject_query=gobject-query
glib_mkenums=glib-mkenums

Name: GLib
Description: C Utility Library
Version: 2.32.3
Requires.private: libpcre
Libs: -L${libdir} -lglib-2.0 
Libs.private: -pthread -lrt  -lpcre    
Cflags: -I${includedir}/glib-2.0 -I${libdir}/glib-2.0/include 

The right compile and link options used by Glib is given as follows.

Compile and link options used by Glib

$ pkg-config --cflags --libs glib-2.0|fold -w72
-I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include  -l
glib-2.0

TIP: The Debian wheezy system on amd64 architecture has its *.pc file at /usr/lib/x86_64-linux-gnu/pkgconfig/glib-2.0.pc. Please note the additional Multi-Arch specific /x86_64-linux-gnu/ in its path.

By using this, the upper.c program can be compiled without error.

Compilation of upper.c with Glib

$ gcc -Wall `pkg-config --cflags --libs glib-2.0` -o upper upper.c

By adding the -v option, the compilation details are exposed.

Compilation of upper.c with Glib with the -v option

$ gcc -v -Wall `pkg-config --cflags --libs glib-2.0` -o upper-v upper.c
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.8/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.8.1-9' --with-bu...
Thread model: posix
gcc version 4.8.1 (Debian 4.8.1-9)
COLLECT_GCC_OPTIONS='-v' '-Wall' '-I' '/usr/include/glib-2.0' '-I' '/usr/lib/x86_...
 /usr/lib/gcc/x86_64-linux-gnu/4.8/cc1 -quiet -v -I /usr/include/glib-2.0 -I /usr...
GNU C (Debian 4.8.1-9) version 4.8.1 (x86_64-linux-gnu)
    compiled by GNU C version 4.8.1, GMP version 5.1.2, MPFR version 3.1.1-p2, MP...
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../x86...
#include "..." search starts here:
#include <...> search starts here:
 /usr/include/glib-2.0
 /usr/lib/x86_64-linux-gnu/glib-2.0/include
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.
GNU C (Debian 4.8.1-9) version 4.8.1 (x86_64-linux-gnu)
    compiled by GNU C version 4.8.1, GMP version 5.1.2, MPFR version 3.1.1-p2, MP...
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 7de91109c57f16a4863bda169a999c04
COLLECT_GCC_OPTIONS='-v' '-Wall' '-I' '/usr/include/glib-2.0' '-I' '/usr/lib/x86_...
 as -v -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include --6...
GNU assembler version 2.23.52 (x86_64-linux-gnu) using BFD version (GNU Binutils ...
COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4....
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8...
COLLECT_GCC_OPTIONS='-v' '-Wall' '-I' '/usr/include/glib-2.0' '-I' '/usr/lib/x86_...
 /usr/lib/gcc/x86_64-linux-gnu/4.8/collect2 --sysroot=/ --build-id --eh-frame-hdr...

When reading GLib Reference Manual (via web or devhelp) and the source of GLib, please note that GLib is written using its own fundamental type system.

You can also find a code which manages reference counted objects in Linux kernel:

These looks very much like Gobject.

Fundamental fixed size data types

GLib uses its own fixed size data types.

Fundamental variable size data types

Glib offers its own variable size data types with associated routines such as memory allocation for many utility data structures such as GString.

GObject

GObject provides a generic type system to register arbitrary single-inherited flat and deep derived types as well as interfaces for structured types in C on top of GLib fundamental data types.

C with GLib and GObject offers an alternative to C++ with its Standard library although it requires many chores with http://developer.gnome.org/gobject/stable/gtype-conventions.html[boiler plate macro definitions].

The GTK+ GUI toolkit is build on the top of C with GLib and GObject. If you wish to simplify this coding process, please think about Vala. For more see the following section on this document and the followings:

See more at:

GTK+3

Although we are at GTK+3, we have many older documentations for GTK+2 but not enough ones for GTK+3.

Those older documentations for GTK+2 contain useful contents as long as they are used carefully.

For pure C programs, migrating from GTK+2 to GTK3+ is basically as easy as changing from “gtk+-2.0” to “gtk+-3.0” in pkg-config argument. In case of troubles such as missing GtkObject and many missing GDK API issues, see http://developer.gnome.org/gtk3/3.0/migrating.html[GTK+ 3 Reference Manual: Part V. Migrating from Previous Versions of GTK+].

Here are basic references:

Glade

Glade is the UI design tool for GTK+. Its output is an XML file and can be loaded directly to GTK+. If you wish to simplify the GUI coding process with many UI widgets under any language, please think about using Glade.

See:

PyGObject

Python bindings of GTK+ has evolved.

So we focus on the latest PyGObject for GTK+3 and recommend you to start with:

Unfortunately, as of 2012 on Debian wheezy, we can not find good reference documentations of GTK+3 and its related libraries for Python.

We can create a usable reference documentation of GTK+3 and related libraries by yourself using the g-ir-doc-tool command from the gobject-introspection package as explained in https://live.gnome.org/GObjectIntrospection/Doctools[GObject Introspection Doctools].

$ g-ir-doc-tool --language Python -o ./output_dir /usr/share/gir-1.0/Gtk-3.0.gir
$ yelp ./output_dir/index.page

Despite the efforts to make GTK+3 PyGObject as compatible to the older GTK+2 PyGTK as possible, the differences are still huge. See http://pfrields.fedorapeople.org/presentations/OhioLF2011/PyGObject.pdf[Graduating to GUI (PDF)].

Please note older PyGTK for GTK+2 are still used widely as of now. The new GTK+3 Python codes using PyGObject such as accerciser, caribou-preferences, gdebi-gtk, gnome-shell-timer-config, software-center, and software-properties-gtk provide us with good examples.

Vala

Vala is a programming language specifically designed to ease the traditional C coding process for GNOME3. The Vala compiler generates C codes using the object system of GNOME with GLib, GObject, etc. Vala offers capabilities such as:

Writing codes for GNOME with the plain C is very tedious and error prone process. But Writing codes for GNOME in Vala is very simple and straigtfrward process just like writing codes under high-level languages such as Python, Java, or MONO/C#.

TIP: Vala does not free you from thinking in C. Think Vala as a nice pre-processor.

Let’s start here:

In Vala, GLib and GObject objects are available as default. Almost any libraries written in C can be accessed from Vala by declaring using ...; at the top using Vala bindings defined as VAPI files located in the /usr/share/vala*/vapi/ directory.

Vala binding to GObject-based libraries are generated automatically as:

https://live.gnome.org/Vala/ExternalBindings[Vala binding to non-GObject-based C libraries] are manually generated and their VAPI files do not contain “generated by vapigen” in it.

The C API is always available in the pertinent manpage, info page, or documentations accessed via devhelp. But Vala API is a bit difficult to get at this moment and explained as below.

C API names of many libraries are mapped to Vala ones with the similar naming convention as GLib naming convention as:

The exact mapping from C API names to Vala ones is defined in *.vapi (Vala API) files found in /usr/share/vala*/vapi/. For example, on Debian wheezy:

These *.vapi (Vala API) files are written in Vala language with extensive use of the attributes such as CCode. Here are some cliches used in *.vapi files:

Here are some reminders for errors when using Gtk.Builder with Vala.

Let me explain the last case a bit more. If the signal signature is

public class Area : Object {
    public signal void clicked (int x, int y);
}

then the handler method must have exactly these parameters in order to work with Gtk.Builder’s auto-connect:


public void on_clicked (Area source, int x, int y) { }

Vala can’t recognize this mistake, because auto-connection happens at runtime an it doesn’t know at compile-time which method will be connected to which signal.

See also:

JavaScript

JavaScript programming language is selected to be the embedded language of GNOME Shell as Gjs. See:

I am not going into details now.

Previous Post Top Next Post