mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-26 15:36:14 +01:00
b090a079f7
Stopping signal emission from an emission hook is, and always has been, actually forbidden. Update the documentation not to lie to the reader. https://bugzilla.gnome.org/show_bug.cgi?id=773355
496 lines
24 KiB
XML
496 lines
24 KiB
XML
<?xml version='1.0' encoding="UTF-8"?>
|
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
|
]>
|
|
<chapter id="chapter-signal">
|
|
<title>The GObject messaging system</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:
|
|
<informalexample><programlisting>
|
|
return_type function_callback (… , gpointer user_data);
|
|
</programlisting></informalexample>
|
|
</para></listitem>
|
|
<listitem><para>
|
|
the <parameter>user_data</parameter> 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 <link linkend="GClosure"><type>GClosure</type></link> 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.
|
|
<footnote><para>
|
|
In practice, closures sit at the boundary of language runtimes: if you are
|
|
writing Python code and one of your Python callbacks receives a signal from
|
|
a GTK+ widget, 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 <link linkend="GCClosure"><type>GCClosure</type></link> type which
|
|
is a specific implementation of closures to be used with C/C++ callbacks.
|
|
</para>
|
|
<para>
|
|
A <link linkend="GClosure"><type>GClosure</type></link> provides simple services:
|
|
<itemizedlist>
|
|
<listitem><para>
|
|
Invocation (<function><link linkend="g-closure-invoke">g_closure_invoke</link></function>): this is what closures
|
|
were created for: they hide the details of callback invocation from the
|
|
callback invoker.</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><link linkend="g-closure-add-finalize-notifier">g_closure_add_finalize_notifier</link></function>
|
|
(finalization notification), <function><link linkend="g-closure-add-invalidate-notifier">g_closure_add_invalidate_notifier</link></function>
|
|
(invalidation notification) and
|
|
<function><link linkend="g-closure-add-marshal-guards">g_closure_add_marshal_guards</link></function> (invocation notification).
|
|
There exist symmetric deregistration functions for finalization and invalidation
|
|
events (<function><link linkend="g-closure-remove-finalize-notifier">g_closure_remove_finalize_notifier</link></function> and
|
|
<function><link linkend="g-closure-remove-invalidate-notifier">g_closure_remove_invalidate_notifier</link></function>) but not for the invocation
|
|
process.
|
|
<footnote><para>
|
|
Closures are reference counted 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 simple <link linkend="GCClosure"><type>GCClosure</type></link>s
|
|
which have a pretty minimal API or the even simpler <function><link linkend="g-signal-connect">g_signal_connect</link></function>
|
|
functions (which will be presented a bit later).
|
|
</para>
|
|
|
|
<para>
|
|
<function><link linkend="g-cclosure-new">g_cclosure_new</link></function> will create a new closure which can invoke the
|
|
user-provided callback_func with the user-provided
|
|
<parameter>user_data</parameter> as its last parameter. When the closure
|
|
is finalized (second stage of the destruction process), it will invoke
|
|
the <parameter>destroy_data</parameter> function if the user has
|
|
supplied one.
|
|
</para>
|
|
|
|
<para>
|
|
<function><link linkend="g-cclosure-new-swap">g_cclosure_new_swap</link></function> will create a new closure which can invoke the
|
|
user-provided <parameter>callback_func</parameter> with the
|
|
user-provided <parameter>user_data</parameter> as its first parameter
|
|
(instead of being the
|
|
last parameter as with <function><link linkend="g-cclosure-new">g_cclosure_new</link></function>). When the closure
|
|
is finalized (second stage of the destruction process), it will invoke
|
|
the <parameter>destroy_data</parameter> 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>
|
|
A generic C closure marshaller is available as
|
|
<link linkend="g-cclosure-marshal-generic"><function>g_cclosure_marshal_generic</function></link>
|
|
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.
|
|
</para>
|
|
|
|
<para>
|
|
An example of a custom marshaller is given below, illustrating how
|
|
<type>GValue</type>s 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.
|
|
<informalexample><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></informalexample>
|
|
</para>
|
|
|
|
<para>
|
|
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.
|
|
</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 windowing system and generates a GTK+ event in the form of a signal emission
|
|
on the widget 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:
|
|
<informalexample><programlisting>
|
|
return_type function_callback (gpointer instance, …, gpointer user_data);
|
|
</programlisting></informalexample>
|
|
</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><link linkend="g-signal-newv">g_signal_newv</link></function>,
|
|
<function><link linkend="g-signal-new-valist">g_signal_new_valist</link></function> or <function><link linkend="g-signal-new">g_signal_new</link></function> functions:
|
|
<informalexample><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></informalexample>
|
|
The number of parameters to these functions is a bit intimidating but they are relatively
|
|
simple:
|
|
<itemizedlist>
|
|
<listitem><para>
|
|
<parameter>signal_name</parameter>: is a string which can be used to uniquely identify a given signal.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<parameter>itype</parameter>: is the instance type on which this signal can be emitted.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<parameter>signal_flags</parameter>: partly defines the order in which closures which were connected to the
|
|
signal are invoked.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<parameter>class_closure</parameter>: 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>
|
|
<parameter>accumulator</parameter>: 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.
|
|
For example, an accumulator could ignore
|
|
<literal>NULL</literal> returns from closures; or it
|
|
could build a list of the values returned by the
|
|
closures.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<parameter>accu_data</parameter>: this pointer will be passed down to each invocation of the
|
|
accumulator during emission.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<parameter>c_marshaller</parameter>: this is the default C marshaller for any closure which is connected to
|
|
this signal.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<parameter>return_type</parameter>: this is the type of the return value of the signal.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<parameter>n_params</parameter>: this is the number of parameters this signal takes.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<parameter>param_types</parameter>: 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 <emphasis>any</emphasis> of the instances of the type which supports that signal.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
You can use <function><link linkend="g-signal-override-class-closure">g_signal_override_class_closure</link></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><link linkend="g-signal-connect">g_signal_connect</link></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><link linkend="g-signal-add-emission-hook">g_signal_add_emission_hook</link></function>
|
|
and removed with <function><link linkend="g-signal-remove-emission-hook">g_signal_remove_emission_hook</link></function>.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="signal-emission">
|
|
<title>Signal emission</title>
|
|
|
|
<para>
|
|
Signal emission is done through the use of the <function><link linkend="g-signal-emit">g_signal_emit</link></function> family
|
|
of functions.
|
|
<informalexample><programlisting>
|
|
void g_signal_emitv (const GValue *instance_and_params,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
GValue *return_value);
|
|
</programlisting></informalexample>
|
|
<itemizedlist>
|
|
<listitem><para>
|
|
The <parameter>instance_and_params</parameter> 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>
|
|
<parameter>signal_id</parameter> identifies the signal to invoke.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<parameter>detail</parameter> 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>
|
|
<parameter>return_value</parameter> 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.
|
|
If no closure is invoked during
|
|
emission, the <parameter>return_value</parameter> is nonetheless initialized to zero/null.
|
|
</para></listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
|
|
<para>
|
|
Signal emission can be decomposed in 5 steps:
|
|
<orderedlist>
|
|
<listitem><para>
|
|
<literal>RUN_FIRST</literal>: if the
|
|
<link linkend="G-SIGNAL-RUN-FIRST:CAPS"><literal>G_SIGNAL_RUN_FIRST</literal></link> flag was used
|
|
during signal registration and if there exists a class closure for this signal,
|
|
the class closure is invoked.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<literal>EMISSION_HOOK</literal>: if any emission hook was added to
|
|
the signal, they are invoked from first to last added. Accumulate return values.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<literal>HANDLER_RUN_FIRST</literal>: if any closure were connected
|
|
with the <function><link linkend="g-signal-connect">g_signal_connect</link></function> family of
|
|
functions, and if they are not blocked (with the <function><link linkend="g-signal-handler-block">g_signal_handler_block</link></function>
|
|
family of functions) they are run here, from first to last connected.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<literal>RUN_LAST</literal>: if the <literal>G_SIGNAL_RUN_LAST</literal>
|
|
flag was set during registration and if a class closure
|
|
was set, it is invoked here.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<literal>HANDLER_RUN_LAST</literal>: if any closure were connected
|
|
with the <function>g_signal_connect_after</function> family of
|
|
functions, if they were not invoked during <literal>HANDLER_RUN_FIRST</literal> and if they
|
|
are not blocked, they are run here, from first to last connected.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<literal>RUN_CLEANUP</literal>: if the <literal>G_SIGNAL_RUN_CLEANUP</literal> flag
|
|
was set during registration and if a class closure was set,
|
|
it is invoked here. Signal emission is completed here.
|
|
</para></listitem>
|
|
</orderedlist>
|
|
</para>
|
|
|
|
<para>
|
|
If, at any point during emission (except in <literal>RUN_CLEANUP</literal> or
|
|
<literal>EMISSION_HOOK</literal> state), one of the closures stops the signal emission with
|
|
<function><link linkend="g-signal-stop-emission">g_signal_stop_emission</link></function>,
|
|
emission jumps to <literal>RUN_CLEANUP</literal> 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 <literal>RUN_FIRST</literal> state.
|
|
</para>
|
|
|
|
<para>
|
|
The accumulator function is invoked in all states, after invocation
|
|
of each closure (except in <literal>RUN_EMISSION_HOOK</literal> and
|
|
<literal>RUN_CLEANUP</literal>). 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 <literal>RUN_CLEANUP</literal> state.
|
|
</para>
|
|
|
|
<para>
|
|
If no accumulator function was provided, the value returned by the last handler
|
|
run will be returned by <function><link linkend="g-signal-emit">g_signal_emit</link></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, in one form or another.
|
|
</para>
|
|
|
|
<para>
|
|
Of the three main connection functions,
|
|
only one has an explicit detail parameter as a <link linkend="GQuark"><type>GQuark</type></link>:
|
|
<link linkend="g-signal-connect-closure-by-id"><function>g_signal_connect_closure_by_id</function></link>.
|
|
<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><link linkend="g-quark-from-string">g_quark_from_string</link></function> and <function><link linkend="g-quark-to-string">g_quark_to_string</link></function>.
|
|
</para>
|
|
</footnote>
|
|
</para>
|
|
<para>
|
|
The two other functions,
|
|
<link linkend="g-signal-connect-closure"><function>g_signal_connect_closure</function></link> and
|
|
<link linkend="g-signal-connect-data"><function>g_signal_connect_data</function></link>
|
|
hide the detail parameter in the signal name identification.
|
|
Their <parameter>detailed_signal</parameter> parameter is a
|
|
string which identifies the name of the signal to connect to.
|
|
The format of this string should match
|
|
<emphasis>signal_name::detail_name</emphasis>. For example,
|
|
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> detail.
|
|
Internally, the detail string is transformed to a GQuark if it is present.
|
|
</para>
|
|
|
|
<para>
|
|
Of the four main signal emission functions, one hides it in its
|
|
signal name parameter:
|
|
<link linkend="g-signal-connect"><function>g_signal_connect</function></link>.
|
|
The other three have an explicit detail parameter as a
|
|
<link linkend="GQuark"><type>GQuark</type></link> again:
|
|
<link linkend="g-signal-emit"><function>g_signal_emit</function></link>,
|
|
<link linkend="g-signal-emitv"><function>g_signal_emitv</function></link> and
|
|
<link linkend="g-signal-emit-valist"><function>g_signal_emit_valist</function></link>.
|
|
</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.
|
|
If a closure's detail does not match the detail provided by the user, it
|
|
will not be invoked (even though it is connected to a signal which is
|
|
being emitted).
|
|
</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 in before the closure's marshalling code runs. For example, this is used extensively
|
|
by the <link linkend="GObject-notify"><structfield>notify</structfield></link> 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 for that signal.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
</chapter>
|
|
|