mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-05 08:56:16 +01:00
521 lines
23 KiB
XML
521 lines
23 KiB
XML
<?xml version='1.0' encoding="ISO-8859-1"?>
|
|
<chapter id="chapter-signal">
|
|
<title>Signals</title>
|
|
|
|
<sect1 id="closure">
|
|
<title>Closures</title>
|
|
|
|
<para>
|
|
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:
|
|
<itemizedlist>
|
|
<listitem><para>a function pointer (the callback itself) whose prototype looks like:
|
|
<programlisting>
|
|
return_type function_callback (... , gpointer user_data);
|
|
</programlisting>
|
|
</para></listitem>
|
|
<listitem><para>
|
|
the user_data pointer which is passed to the callback upon invocation of the closure
|
|
</para></listitem>
|
|
<listitem><para>
|
|
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.
|
|
</para></listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
|
|
<para>
|
|
The <type>GClosure</type> structure represents the common functionality of all
|
|
closure implementations: there exist a different Closure implementation for
|
|
each separate runtime which wants to use the GObject type system.
|
|
<footnote><para>
|
|
In Practice, Closures sit at the boundary of language runtimes: if you are
|
|
writing python code and one of your Python callback receives a signal from
|
|
one of GTK+ widgets, the C code in GTK+ needs to execute your Python
|
|
code. The Closure invoked by the GTK+ object invokes the Python callback:
|
|
it behaves as a normal C object for GTK+ and as a normal Python object for
|
|
python code.
|
|
</para></footnote>
|
|
The GObject library provides a simple <type>GCClosure</type> type which
|
|
is a specific implementation of closures to be used with C/C++ callbacks.
|
|
</para>
|
|
<para>
|
|
A <type>GClosure</type> provides simple services:
|
|
<itemizedlist>
|
|
<listitem><para>
|
|
Invocation (<function>g_closure_invoke</function>): this is what closures
|
|
were created for: they hide the details of callback invocation from the
|
|
callback invocator.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
Notification: the closure notifies listeners of certain events such as
|
|
closure invocation, closure invalidation and closure finalization. Listeners
|
|
can be registered with <function>g_closure_add_finalize_notifier</function>
|
|
(finalization notification), <function>g_closure_add_invalidate_notifier</function>
|
|
(invalidation notification) and
|
|
<function>g_closure_add_marshal_guards</function> (invocation notification).
|
|
There exist symmetric de-registration functions for finalization and invalidation
|
|
events (<function>g_closure_remove_finalize_notifier</function> and
|
|
<function>g_closure_remove_invalidate_notifier</function>) but not for the invocation
|
|
process.
|
|
<footnote><para>
|
|
Closures are refcounted and notify listeners of their destruction in a two-stage
|
|
process: the invalidation notifiers are invoked before the finalization notifiers.
|
|
</para></footnote>
|
|
</para></listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
|
|
<sect2>
|
|
<title>C Closures</title>
|
|
|
|
<para>
|
|
If you are using C or C++
|
|
to connect a callback to a given event, you will either use the simple <type>GCClosure</type>s
|
|
which have a pretty minimal API or the even simpler <function>g_signal_connect</function>
|
|
functions (which will be presented a bit later :).
|
|
<programlisting>
|
|
GClosure* g_cclosure_new (GCallback callback_func,
|
|
gpointer user_data,
|
|
GClosureNotify destroy_data);
|
|
GClosure* g_cclosure_new_swap (GCallback callback_func,
|
|
gpointer user_data,
|
|
GClosureNotify destroy_data);
|
|
GClosure* g_signal_type_cclosure_new (GType itype,
|
|
guint struct_offset);
|
|
</programlisting>
|
|
</para>
|
|
|
|
<para>
|
|
<function>g_cclosure_new</function> will create a new closure which can invoke the
|
|
user-provided callback_func with the user-provided user_data as 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.
|
|
</para>
|
|
|
|
<para>
|
|
<function>g_cclosure_new_swap</function> will create a new closure which can invoke the
|
|
user-provided callback_func with the user-provided user_data as first parameter (instead of being the
|
|
last parameter as with <function>g_cclosure_new</function>). When the closure
|
|
is finalized (second stage of the destruction process), it will invoke the destroy_data
|
|
function if the user has supplied one.
|
|
</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>non-C closures (for the fearless).</title>
|
|
|
|
<para>
|
|
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 <emphasis>call</emphasis>
|
|
assembly instruction.
|
|
</para>
|
|
|
|
<para>
|
|
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.
|
|
</para>
|
|
|
|
<para>
|
|
The following code implements a simple marshaller in C for a C function which takes an
|
|
integer as first parameter and returns void.
|
|
<programlisting>
|
|
g_cclosure_marshal_VOID__INT (GClosure *closure,
|
|
GValue *return_value,
|
|
guint n_param_values,
|
|
const GValue *param_values,
|
|
gpointer invocation_hint,
|
|
gpointer marshal_data)
|
|
{
|
|
typedef void (*GMarshalFunc_VOID__INT) (gpointer data1,
|
|
gint arg_1,
|
|
gpointer data2);
|
|
register GMarshalFunc_VOID__INT callback;
|
|
register GCClosure *cc = (GCClosure*) closure;
|
|
register gpointer data1, data2;
|
|
|
|
g_return_if_fail (n_param_values == 2);
|
|
|
|
data1 = g_value_peek_pointer (param_values + 0);
|
|
data2 = closure->data;
|
|
|
|
callback = (GMarshalFunc_VOID__INT) (marshal_data ? marshal_data : cc->callback);
|
|
|
|
callback (data1,
|
|
g_marshal_value_peek_int (param_values + 1),
|
|
data2);
|
|
}
|
|
</programlisting>
|
|
</para>
|
|
|
|
<para>
|
|
Of course, there exist other kinds of marshallers. For example, James Henstridge
|
|
wrote a generic Python marshaller which is used by all python Closures (a python closure
|
|
is used to have python-based callback be invoked by the closure invocation process).
|
|
This python marshaller transforms the input GValue list representing the function
|
|
parameters into a Python tupple which is the equivalent structure in python (you can
|
|
look in <function>pyg_closure_marshal</function> in <filename>pygtype.c</filename>
|
|
in the <emphasis>pygtk</emphasis> module in Gnome cvs server).
|
|
</para>
|
|
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 id="signal">
|
|
<title>Signals</title>
|
|
|
|
<para>
|
|
GObject's signals have nothing to do with standard UNIX signals: they connect
|
|
arbitrary application-specific events with any number of listeners.
|
|
For example, in GTK+, every user event (keystroke or mouse move) is received
|
|
from the X server and generates a GTK+ event under the form of a signal emission
|
|
on a given object instance.
|
|
</para>
|
|
|
|
<para>
|
|
Each signal is registered in the type system together with the type on which
|
|
it can be emitted: users of the type are said to <emphasis>connect</emphasis>
|
|
to the signal on a given type instance when they register a closure to be
|
|
invoked upon the signal emission. Users can also emit the signal by themselves
|
|
or stop the emission of the signal from within one of the closures connected
|
|
to the signal.
|
|
</para>
|
|
|
|
<para>
|
|
When a signal is emitted on a given type instance, all the closures
|
|
connected to this signal on this type instance will be invoked. All the closures
|
|
connected to such a signal represent callbacks whose signature looks like:
|
|
<programlisting>
|
|
return_type function_callback (gpointer instance, ... , gpointer user_data);
|
|
</programlisting>
|
|
</para>
|
|
|
|
<sect2 id="signal-registration">
|
|
<title>Signal registration</title>
|
|
|
|
<para>
|
|
To register a new signal on an existing type, we can use any of <function>g_signal_newv</function>,
|
|
<function>g_signal_new_valist</function> or <function>g_signal_new</function> functions:
|
|
<programlisting>
|
|
guint g_signal_newv (const gchar *signal_name,
|
|
GType itype,
|
|
GSignalFlags signal_flags,
|
|
GClosure *class_closure,
|
|
GSignalAccumulator accumulator,
|
|
gpointer accu_data,
|
|
GSignalCMarshaller c_marshaller,
|
|
GType return_type,
|
|
guint n_params,
|
|
GType *param_types);
|
|
</programlisting>
|
|
The number of parameters to these functions is a bit intimidating but they are relatively
|
|
simple:
|
|
<itemizedlist>
|
|
<listitem><para>
|
|
signal_name: is a string which can be used to uniquely identify a given signal.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
itype: is the instance type on which this signal can be emitted.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
signal_flags: partly defines the order in which closures which were connected to the
|
|
signal are invoked.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
class_closure: this is the default closure for the signal: if it is not NULL upon
|
|
the signal emission, it will be invoked upon this emission of the signal. The
|
|
moment where this closure is invoked compared to other closures connected to that
|
|
signal depends partly on the signal_flags.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
accumulator: this is a function pointer which is invoked after each closure
|
|
has been invoked. If it returns FALSE, signal emission is stopped. If it returns
|
|
TRUE, signal emission proceeds normally. It is also used to compute the return
|
|
value of the signal based on the return value of all the invoked closures.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
accumulator_data: this pointer will be passed down to each invocation of the
|
|
accumulator during emission.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
c_marshaller: this is the default C marshaller for any closure which is connected to
|
|
this signal.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
return_type: this is the type of the return value of the signal.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
n_params: this is the number of parameters this signal takes.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
param_types: this is an array of GTypes which indicate the type of each parameter
|
|
of the signal. The length of this array is indicated by n_params.
|
|
</para></listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
|
|
<para>
|
|
As you can see from the above definition, a signal is basically a description
|
|
of the closures which can be connected to this signal and a description of the
|
|
order in which the closures connected to this signal will be invoked.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="signal-connection">
|
|
<title>Signal connection</title>
|
|
|
|
<para>
|
|
If you want to connect to a signal with a closure, you have three possibilities:
|
|
<itemizedlist>
|
|
<listitem><para>
|
|
You can register a class closure at signal registration: this is a
|
|
system-wide operation. i.e.: the class_closure will be invoked during each emission
|
|
of a given signal on all the instances of the type which supports that signal.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
You can use <function>g_signal_override_class_closure</function> which
|
|
overrides the class_closure of a given type. It is possible to call this function
|
|
only on a derived type of the type on which the signal was registered.
|
|
This function is of use only to language bindings.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
You can register a closure with the <function>g_signal_connect</function>
|
|
family of functions. This is an instance-specific operation: the closure
|
|
will be invoked only during emission of a given signal on a given instance.
|
|
</para></listitem>
|
|
</itemizedlist>
|
|
It is also possible to connect a different kind of callback on a given signal:
|
|
emission hooks are invoked whenever a given signal is emitted whatever the instance on
|
|
which it is emitted. Emission hooks are used for example to get all mouse_clicked
|
|
emissions in an application to be able to emit the small mouse click sound.
|
|
Emission hooks are connected with <function>g_signal_add_emission_hook</function>
|
|
and removed with <function>g_signal_remove_emission_hook</function>.
|
|
</para>
|
|
|
|
<para>
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="signal-emission">
|
|
<title>Signal emission</title>
|
|
|
|
<para>
|
|
Signal emission is done through the use of the <function>g_signal_emit</function> family
|
|
of functions.
|
|
<programlisting>
|
|
void g_signal_emitv (const GValue *instance_and_params,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
GValue *return_value);
|
|
</programlisting>
|
|
<itemizedlist>
|
|
<listitem><para>
|
|
The instance_and_params array of GValues contains the list of input
|
|
parameters to the signal. The first element of the array is the
|
|
instance pointer on which to invoke the signal. The following elements of
|
|
the array contain the list of parameters to the signal.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
signal_id identifies the signal to invoke.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
detail identifies the specific detail of the signal to invoke. A detail is a kind of
|
|
magic token/argument which is passed around during signal emission and which is used
|
|
by closures connected to the signal to filter out unwanted signal emissions. In most
|
|
cases, you can safely set this value to zero. See <xref linkend="signal-detail"/> for
|
|
more details about this parameter.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
return_value holds the return value of the last closure invoked during emission if
|
|
no accumulator was specified. If an accumulator was specified during signal creation,
|
|
this accumulator is used to calculate the return_value as a function of the return
|
|
values of all the closures invoked during emission.
|
|
<footnote><para>
|
|
James (again!!) gives a few non-trivial examples of accumulators:
|
|
<quote>
|
|
For instance, you may have an accumulator that ignores NULL returns from
|
|
closures, and only accumulates the non-NULL ones. Another accumulator may try
|
|
to return the list of values returned by the closures.
|
|
</quote>
|
|
</para></footnote>
|
|
If no closure is invoked during
|
|
emission, the return_value is nonetheless initialized to zero/null.
|
|
</para></listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
|
|
<para>
|
|
Internally, the GValue array is passed to the emission function proper,
|
|
<function>signal_emit_unlocked_R</function> (implemented in <filename>gsignal.c</filename>).
|
|
Signal emission can be decomposed in 5 steps:
|
|
<itemizedlist>
|
|
<listitem><para>
|
|
<emphasis>RUN_FIRST</emphasis>: if the G_SIGNAL_RUN_FIRST flag was used
|
|
during signal registration and if there exist a class_closure for this signal,
|
|
the class_closure is invoked. Jump to <emphasis>EMISSION_HOOK</emphasis> state.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<emphasis>EMISSION_HOOK</emphasis>: if any emission hook was added to
|
|
the signal, they are invoked from first to last added. Accumulate return values
|
|
and jump to <emphasis>HANDLER_RUN_FIRST</emphasis> state.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<emphasis>HANDLER_RUN_FIRST</emphasis>: if any closure were connected
|
|
with the <function>g_signal_connect</function> family of
|
|
functions, and if they are not blocked (with the <function>g_signal_handler_block</function>
|
|
family of functions) they are run here, from first to last connected.
|
|
Jump to <emphasis>RUN_LAST</emphasis> state.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<emphasis>RUN_LAST</emphasis>: if the G_SIGNAL_RUN_LAST
|
|
flag was set during registration and if a class_closure
|
|
was set, it is invoked here. Jump to
|
|
<emphasis>HANDLER_RUN_LAST</emphasis> state.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<emphasis>HANDLER_RUN_LAST</emphasis>: if any closure were connected
|
|
with the <function>g_signal_connect_after</function> family of
|
|
functions, if they were not invoked during HANDLER_RUN_FIRST and if they
|
|
are not blocked, they are run here, from first to last connected.
|
|
Jump to <emphasis>RUN_CLEANUP</emphasis> state.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<emphasis>RUN_CLEANUP</emphasis>: if the G_SIGNAL_RUN_CLEANUP flag
|
|
was set during registration and if a class_closure was set,
|
|
it is invoked here. Signal emission is completed here.
|
|
</para></listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
|
|
<para>
|
|
If, at any point during emission (except in RUN_CLEANUP state), one of the
|
|
closures or emission hook stops the signal emission with
|
|
<function>g_signal_stop</function>, emission jumps to CLEANUP state.
|
|
</para>
|
|
|
|
<para>
|
|
If, at any point during emission, one of the closures or emission hook
|
|
emits the same signal on the same instance, emission is restarted from
|
|
the RUN_FIRST state.
|
|
</para>
|
|
|
|
<para>
|
|
The accumulator function is invoked in all states, after invocation
|
|
of each closure (except in EMISSION_HOOK and CLEANUP). It accumulates
|
|
the closure return value into the signal return value and returns TRUE or
|
|
FALSE. If, at any point, it does not return TRUE, emission jumps to CLEANUP state.
|
|
</para>
|
|
|
|
<para>
|
|
If no accumulator function was provided, the value returned by the last handler
|
|
run will be returned by <function>g_signal_emit</function>.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
|
|
<sect2 id="signal-detail">
|
|
<title>The <emphasis>detail</emphasis> argument</title>
|
|
|
|
<para>All the functions related to signal emission or signal connection have a parameter
|
|
named the <emphasis>detail</emphasis>. Sometimes, this parameter is hidden by the API
|
|
but it is always there, under one form or another.
|
|
</para>
|
|
|
|
<para>
|
|
Of the three main connection functions,
|
|
only one has an explicit detail parameter as a <type>GQuark</type>
|
|
<footnote>
|
|
<para>A GQuark is an integer which uniquely represents a string. It is possible to transform
|
|
back and forth between the integer and string representations with the functions
|
|
<function>g_quark_from_string</function> and <function>g_quark_to_string</function>.
|
|
</para>
|
|
</footnote>:
|
|
<programlisting>
|
|
gulong g_signal_connect_closure_by_id (gpointer instance,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
GClosure *closure,
|
|
gboolean after);
|
|
</programlisting>
|
|
The two other functions hide the detail parameter in the signal name identification:
|
|
<programlisting>
|
|
gulong g_signal_connect_closure (gpointer instance,
|
|
const gchar *detailed_signal,
|
|
GClosure *closure,
|
|
gboolean after);
|
|
gulong g_signal_connect_data (gpointer instance,
|
|
const gchar *detailed_signal,
|
|
GCallback c_handler,
|
|
gpointer data,
|
|
GClosureNotify destroy_data,
|
|
GConnectFlags connect_flags);
|
|
</programlisting>
|
|
Their detailed_signal parameter is a string which identifies the name of the signal
|
|
to connect to. However, the format of this string is structured to look like
|
|
<emphasis>signal_name::detail_name</emphasis>. Connecting to the signal
|
|
named <emphasis>notify::cursor_position</emphasis> will actually connect to the signal
|
|
named <emphasis>notify</emphasis> with the <emphasis>cursor_position</emphasis> name.
|
|
Internally, the detail string is transformed to a GQuark if it is present.
|
|
</para>
|
|
|
|
<para>
|
|
Of the four main signal emission functions, three have an explicit detail parameter as a
|
|
<type>GQuark</type> again:
|
|
<programlisting>
|
|
void g_signal_emitv (const GValue *instance_and_params,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
GValue *return_value);
|
|
void g_signal_emit_valist (gpointer instance,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
va_list var_args);
|
|
void g_signal_emit (gpointer instance,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
...);
|
|
</programlisting>
|
|
The fourth function hides it in its signal name parameter:
|
|
<programlisting>
|
|
void g_signal_emit_by_name (gpointer instance,
|
|
const gchar *detailed_signal,
|
|
...);
|
|
</programlisting>
|
|
The format of the detailed_signal parameter is exactly the same as the format used by
|
|
the <function>g_signal_connect</function> functions: <emphasis>signal_name::detail_name</emphasis>.
|
|
</para>
|
|
|
|
<para>
|
|
If a detail is provided by the user to the emission function, it is used during emission to match
|
|
against the closures which also provide a detail. The closures which provided a detail will not
|
|
be invoked (even though they are connected to a signal which is being emitted) if their detail
|
|
does not match the detail provided by the user.
|
|
</para>
|
|
|
|
<para>This completely optional filtering mechanism is mainly used as an optimization for signals
|
|
which are often emitted for many different reasons: the clients can filter out which events they are
|
|
interested into before the closure's marshalling code runs. For example, this is used extensively
|
|
by the <emphasis>notify</emphasis> signal of GObject: whenever a property is modified on a GObject,
|
|
instead of just emitting the <emphasis>notify</emphasis> signal, GObject associates as a detail to this
|
|
signal emission the name of the property modified. This allows clients who wish to be notified of changes
|
|
to only one property to filter most events before receiving them.
|
|
</para>
|
|
|
|
<para>As a simple rule, users can and should set the detail parameter to zero: this will disable completely
|
|
this optional filtering.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
</chapter>
|