GObject
GObject is a library that is a base for many other Gnome libraries (like GTK). It is a common base layer providing OOP paradigm to the C language. It may be seen as an alternative to C++ or Objective C, since it enables developers to create classes, but in this case, directly in C (however, in a rather tedious way, since it’s still “just” C)!
GObject is a part of GLib and uses the same version numbers. GLib contains:
- GObject - type system
- GThread - threading
- GIO - I/O operations
- others…
Some features of GObject that are often used in GTK apps are:
- the
GObject
root base type - signals (like events in .NET)
History
GObject has been created in the 90s, and the design hasn’t changed much since then. It’s been created before C++ has been standardized (and probably this is why it was even created instead of just using C++).
GObject was originally a part of GIMP Toolkit, which was created for GIMP. Later, GTK was extracted from GIMP to become a standalone thing.
Implementation
The base type of all types in GTK is
GTypeInstance (also
GObject inherits from it). However, we usually use GObject
as a base when we want to
refer to anything in the GTK world, since it implements the core things such as
signals or properties (it’s a bit more complicated than that).
Instances and Classes
GTK types have separate structs for instances and classes, e.g. there is
GObject
(instance) and GObjectClass
. The stuff in GObjectClass
is shared
among all GObjects (a list of signals, properties, CSS classes, etc.), while
GObject
contains instance-specific data.
Here’s an example of types that we could find in GLib:
The “Thing” and “ThingClass” structs are connected via GTypeInstance
and
GTypeClass
:
So, for example, every instance of GtkButton
will have a pointer to a (common)
instance of GtkButtonClass
. There are even macros that allow us to retrieve a
ThingClass from Thing, like
GTK_BUTTON_GET_CLASS,
(it’s an equivalent of ((GTypeInstance*)instance)->g_type
).
There are lots of other macros, some of them just cast one type to another to make the code more readable (plus, they can do some type checks for safety).
Registration
Every type in the GObject inheritance tree (also our custom types) needs to be registered. When registering we need to provide a bunch of information:
- what is the size of the instance
- what is the size of the class
- what’s the init function of the instance type
- what’s the init function of the class type
Thanks to the registration, the instantation of the new objects of the registered type will be simplified later on, and it will properly set up the new object using the GObject type system. Otherwise, we’d have to do a bunch of things manually, probably making some mistakes in the process and also making the code completely unreadable.
The registration process requires us to follow some conventions, like creating a
duet of instance and class types that we talked about before (and the class type
needs to have Class
postfix!)
The registration returns a GType
.
Bindings
The GObject libraries are written in the C language. However, there are a bunch of bindings for many other programming languages that open the toolkit to a vast group of developers. Examples of supported languages include:
- C (obviously)
- JavaScript
- Python
- Rust
- Vala
- C#
- and more…
Since there are a lot of GObject-based libraries, there is an established way of generating bindings for them - GObject Introspection. The bindings, under the hood, call the C libraries code via mechanisms similar to PInvoke.