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.
- GTK+1.0 (1998): just separated from GIMP.
- GTK+1.2 (1999): reasonable shape for general applications.
- GTK+2.0 (2002): for GNOME2 based on GLib, GObject, GIO, ATK, GDK, GdkPixbuff
- GTK+3.0 (2011): for GNOME3 based on GLib, GObject, GIO, ATK, GDK, GdkPixbuff, Pango
- GTK+3.0 works with Cairo, Clutter, and GObject-introspection, …
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.
- GNOME1 (1999): CORBA (= Bonobo + libIDL + ORBit) as IPC established.
- GNOME2 (2002): Antialiased fonts, UNICODE support (internationalization), HIG compliance (accessibility), …
- GNOME2 cycle: IPC migrated from CORBA to D-Bus.
- GNOME3 (2011): D-Bus as IPC established. (CORBA deprecated)
- GNOME3 cycle: GObject-Introspection is introduced.
- Vala is becoming a popular choice to write applications for the native binary target instead of traditional and complicated C code with many boiler plate macro definitions.
- Python with PyGObject is a popular choice to write applications under the high level interpreter language with JIT compilation.
- Javascript is becoming the choice for the embedded language of applications with the Gjs binding.
- GNOME3 cycle: GObject-Introspection is introduced.
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:
- tighter binding including the memory management than the generic language binding systems such as SWIG can, and
- more consistent binding across different languages.
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.:
- Virtual Memory Allocation And Paging in The GNU C Library manual
- C dynamic memory allocation (Wikipedia)
- mmap (Wikipedia)
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.
- Types prefixed by “g” which are equivalent of ones in standard C
gchar
gint
gshort
glong
gfloat
gdouble
- Unsined types prefixed by “gu” which are equivalent of unsined ones in standard C
guchar
guint
gushort
gulong
- Integer types with platform independent specified bit size
gint8
guint8
gint16
guint16
gint32
guint32
gint64
guint64
- Untyped pointer alias
gpointer
: C99 typevoid*
gconstpointer
: C99 typeconst void*
- New types which are not part of standard C
gboolean
: value=TRUE or FALSEgsize
: C99 unsigned integer typesize_t
(usually 64bit or 32bit)gssize
: C99 signed integer typessize_t
(usually 64bit or 32bit)goffset
: C99 typeoff64_t
gintptr
: C99 typeintptr_t
guintptr
: C99 typeuintptr_t
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
.
GList
: Doubly-Linked Lists – linked lists that can be iterated over in both directionsGSList
: Singly-Linked Lists – linked lists that can be iterated in one directionGQueue
: Double-ended Queues – double-ended queue data structureGSequence
: Sequences – scalable listsGTrashStack
: Trash Stacks – maintain a stack of unused allocated memory chunksGHashTable
: Hash Tables – associations between keys and values so that given a key the value can be found quicklyGString
: Strings – text buffers which grow automatically as text is addedGStringChunk
: String Chunks – efficient storage of groups of stringsGArray
: Arrays – arrays of arbitrary elements which grow automatically as elements are addedGPtrArray
: Pointer Arrays – arrays of pointers to any type of data, which grow automatically as new elements are addedGByteArray
: Byte Arrays – arrays of bytesGTree
: Balanced Binary Trees – a sorted collection of key/value pairs optimized for searching and traversing in orderGNode
: N-ary Trees – trees of data with any number of branchesGQuark
: Quarks – a 2-way association between a string and a unique integer identifierGData
: Keyed Data Lists – lists of data elements which are accessible by a string or GQuark identifierDatasets
– associate groups of data elements with particular memory locations
GVariantType
: GVariantType – introduction to the GVariant type systemGVariant
: GVariant – strongly typed value datatypeGVariant Format Strings
– varargs conversion of GVariantsGVariant Text Format
– textual representation of GVariants
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:
- GLib (wikipedia)
- GObject (wikipedia)
- GLib (upstream doc), or via
devhelp
- GObject (upstream doc), or via
devhelp
- Manage C data using the GLib collections by Tom Copeland. (IBM DW, Date: 28 Jun 2005)
- Glib-C: C as an alternative Object Oriented Environment (PDF) by Steven Hendrickx. (2004)
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:
- GTK+ (wikipedia)
- GTK+ (upstream doc), or via
devhelp
- GTK+ 3 Reference Manual
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:
- Glade Tutorials (pointers)
- Tips and tutorials related to GTK+ toolkit (2009-2010)
- GTK+ and Glade3 GUI Programming Tutorial (2007)
- GTK+ 2.0 Tree View Tutorial (2005)
- Glade Catalog Tutorial (2009)
- Glade User Interface Designer Reference Manual (API for Glade 3.6)
- Tutorial: A GUI application using Python & gtk.Builder (2009, Video)
- Learn how to use Glade GUI from video.
- Disregard details of Python code since it is based on gtk.Builder from PyGTK for GTK+2 and outdated.
PyGObject
Python bindings of GTK+ has evolved.
- PyGTK for GTK+2: (deprecated))
- starting code with “
import pygtk
” (newer), or “import gtk
” (older)
- starting code with “
- PyGObject for GTK+3: (recommended)
- starting code with “
from gi.repository import Gtk
” (current)
- starting code with “
So we focus on the latest PyGObject for GTK+3 and recommend you to start with:
- The Python GTK+ 3 Tutorial (2012)
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:
- access to the modern object oriented language features such as
class
, - access to the automatic memory management system based on the reference counting,
- access to all C libraries, and
- generation of native binaries with the C API.
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:
- generating GObject Introspection GIR file (stored in the
/usr/share/gir-1.0
directory) - generation the VAPI binding from the GIR file with
vapigen
- tweaking the binding generation with metadata and custom code
- their VAPI files contain “generated by vapigen” in it.
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:
- C API:
g_topic_foobar()
- Vala API:
GLib.Topic.foobar()
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:
- Glib:
/usr/share/vala-0.16/vapi/glib-2.0.vapi
- GObject:
/usr/share/vala-0.16/vapi/gobject-2.0.vapi
- GTK+:
/usr/share/vala-0.16/vapi/gtk+-3.0.vapi
- POSIX:
/usr/share/vala-0.16/vapi/posix.vapi
(libc/libm library) - CURSES:
/usr/share/vala-0.16/vapi/curses.vapi
(curses library)
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:
[CCode (cprefix ...)]
- This is primarily used for namespaces. While when left to its
own devices valac will simply concatenate the parent names to
generate C type names, setting the
cprefix
allows you to override this. For instance, assuming you have a classFoo.Bar.Baz
, setting a cprefix of “Fubar
” on a yourBar
namespace will result in a C name of “FubarBaz
” for theBaz
class.
- This is primarily used for namespaces. While when left to its
own devices valac will simply concatenate the parent names to
generate C type names, setting the
[CCode (lower_case_cprefix ...)]
- This overrides everything up to the start of
the method name. For instance, a method named
Foo.Bar.baz
would normally result in a C name offoo_bar_baz
. However, if you set thelower_case_cprefix
of thebar
class to be “fb_
”, the resulting C name would be “fb_baz
”.
- This overrides everything up to the start of
the method name. For instance, a method named
[CCode (cname ...)]
- This sets the C name to exactly what you specify here. For
instance, if you set the
cname
of aFoo.Bar.baz
method to “bacon
”, the name of theFoo.Bar.baz
function in C will be “bacon
”.
- This sets the C name to exactly what you specify here. For
instance, if you set the
Here are some reminders for errors when using Gtk.Builder with Vala.
-
Forgetting to use
[CCode (instance_pos = -1)]
when using instance methods instead of static methods as handlers -
Forgetting to mangle the handler method names in Glade, e.g. from
FooBar.my_handler
tofoo_bar_my_handler
-
Not using the right signature for the handler. One missing parameter or one parameter too much will result in a segmentation fault.
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:
- Vala - Compiler for the GObject type system – Homepage
- Vala - Documentation – Sample Code
- Vala - Manual (Draft)
- Hackers’ Guide to Vala
- C API documentation found in
devhelp
or for GLib, GObject, and GTK+.
JavaScript
JavaScript programming language is selected to be the embedded language of GNOME Shell as Gjs. See:
- JavaScript (Mozilla)
- JavaScript (GNOME)
- GNOME Shell
- GNOME Shell: Technology
- GNOME Shell: Extensions
- GNOME Shell: Step by step tutorial to create extensions
I am not going into details now.
Previous Post | Top | Next Post |