Closures are central to the concept of asynchronous signal delivery
which is widely used throughout GTK+ and GNOME applications. A closure is an
abstraction, a generic representation of a callback. It is a small structure
which contains three objects:
-
a function pointer (the callback itself) whose prototype looks like:
the user_data pointer which is passed to the callback upon invocation of the closure
a function pointer which represents the destructor of the closure: whenever the
closure's refcount reaches zero, this function will be called before the closure
structure is freed.
The GClosure structure represents the common functionality of all
closure implementations: there exists a different closure implementation for
each separate runtime which wants to use the GObject type system.
The GObject library provides a simple GCClosure type which
is a specific implementation of closures to be used with C/C++ callbacks.
A GClosure provides simple services:
If you are using C or C++
to connect a callback to a given event, you will either use simple GCClosures
which have a pretty minimal API or the even simpler g_signal_connect
functions (which will be presented a bit later).
g_cclosure_new will create a new closure which can invoke the
user-provided callback_func with the user-provided
user_data as its last parameter. When the closure
is finalized (second stage of the destruction process), it will invoke
the destroy_data function if the user has
supplied one.
g_cclosure_new_swap will create a new closure which can invoke the
user-provided callback_func with the
user-provided user_data as its first parameter
(instead of being the
last parameter as with g_cclosure_new). When the closure
is finalized (second stage of the destruction process), it will invoke
the destroy_data function if the user has
supplied one.
Non-C closures (for the fearless)
As was explained above, closures hide the details of callback invocation. In C,
callback invocation is just like function invocation: it is a matter of creating
the correct stack frame for the called function and executing a call
assembly instruction.
C closure marshallers transform the array of GValues which represent
the parameters to the target function into a C-style function parameter list, invoke
the user-supplied C function with this new parameter list, get the return value of the
function, transform it into a GValue and return this GValue to the marshaller caller.
A generic C closure marshaller is available as
g_cclosure_marshal_generic
which implements marshalling for all function types using libffi. Custom
marshallers for different types are not needed apart from performance
critical code where the libffi-based marshaller may be too slow.
An example of a custom marshaller is given below, illustrating how
GValues can be converted to a C function call. The
marshaller is for a C function which takes an integer as its first
parameter and returns void.
There exist other kinds of marshallers, for example there is a generic
Python marshaller which is used by all Python closures (a Python closure
is used to invoke a callback written in Python). This Python marshaller
transforms the input GValue list representing the function parameters
into a Python tuple which is the equivalent structure in Python.