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. 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 connect 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. 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: return_type function_callback (gpointer instance, ... , gpointer user_data);
To register a new signal on an existing type, we can use any of 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); The number of parameters to these functions is a bit intimidating but they are relatively simple:
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. If you want to connect to a signal with a closure, you have three possibilities:
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
Signal emission is done through the use of the void g_signal_emitv (const GValue *instance_and_params, guint signal_id, GQuark detail, GValue *return_value);
Internally, the GValue array is passed to the emission function proper,
If, at any point during emission (except in RUN_CLEANUP state), one of the
closures or emission hook stops the signal emission with
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. 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.
If no accumulator function was provided, the value returned by the last handler
run will be returned by All the functions related to signal emission or signal connection have a parameter named the detail. Sometimes, this parameter is hidden by the API but it is always there, under one form or another. Of the three main connection functions, only one has an explicit detail parameter as a GQuark [11]: gulong g_signal_connect_closure_by_id (gpointer instance, guint signal_id, GQuark detail, GClosure *closure, gboolean after); The two other functions hide the detail parameter in the signal name identification: 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); 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 signal_name::detail_name. Connecting to the signal named notify::cursor_position will actually connect to the signal named notify with the cursor_position name. Internally, the detail string is transformed to a GQuark if it is present. Of the four main signal emission functions, three have an explicit detail parameter as a GQuark again: 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, ...); The fourth function hides it in its signal name parameter: void g_signal_emit_by_name (gpointer instance, const gchar *detailed_signal, ...);
The format of the detailed_signal parameter is exactly the same as the format used by
the 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 the closures' detail does not match the detail provided by the user, they will not be invoked (even though they are connected to a signal which is being emitted). 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 notify signal of GObject: whenever a property is modified on a GObject, instead of just emitting the notify 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. As a simple rule, users can and should set the detail parameter to zero: this will disable completely this optional filtering. [10] James (again!!) gives a few non-trivial examples of accumulators: “ 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. ” [11] 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
|