mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-08-02 07:23:41 +02:00
Initial revision
This commit is contained in:
520
docs/reference/gobject/tut_gsignal.xml
Normal file
520
docs/reference/gobject/tut_gsignal.xml
Normal file
@@ -0,0 +1,520 @@
|
||||
<?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>
|
Reference in New Issue
Block a user