Signals

Signals

Each object is encapsulated in Gtk programming. And it is not recommended to use global variables because they are prone to make the program complicated. So, we need something to communicate between objects. There are two ways to do so.

The caller of the function or the handler connected to the signal is usually out of the object. One of the difference between these two is that the object is active or passive. In functions the object passively responds to the caller. In signals the object actively sends a signal to the handler.

GObject signals are registered, connected and emitted.

  1. Signals are registered with the object type on which they are emitted. The registration is done usually when the object class is initialized.
  2. Signals are connected to handlers by g_connect_signal or its family functions. The connection is usually done out of the object.
  3. When Signals are emitted, the connected handlers are invoked. Signals are emitted on the instance of the object.

Signal registration

In TfeTextView, two signals are registered.

A static variable or array is used to store signal ID.

enum {
  CHANGE_FILE,
  OPEN_RESPONSE,
  NUMBER_OF_SIGNALS
};

static guint tfe_text_view_signals[NUMBER_OF_SIGNALS];

Signals are registered in the class initialization function.

static void
tfe_text_view_class_init (TfeTextViewClass *class) {
  GObjectClass *object_class = G_OBJECT_CLASS (class);

  object_class->dispose = tfe_text_view_dispose;
  tfe_text_view_signals[CHANGE_FILE] = g_signal_new ("change-file",
                                 G_TYPE_FROM_CLASS (class),
                                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
                                 0 /* class offset */,
                                 NULL /* accumulator */,
                                 NULL /* accumulator data */,
                                 NULL /* C marshaller */,
                                 G_TYPE_NONE /* return_type */,
                                 0     /* n_params */
                                 );
  tfe_text_view_signals[OPEN_RESPONSE] = g_signal_new ("open-response",
                                 G_TYPE_FROM_CLASS (class),
                                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
                                 0 /* class offset */,
                                 NULL /* accumulator */,
                                 NULL /* accumulator data */,
                                 NULL /* C marshaller */,
                                 G_TYPE_NONE /* return_type */,
                                 1     /* n_params */,
                                 G_TYPE_INT
                                 );
}

The handlers are declared as follows.

/* "change-file" signal handler */
void
user_function (TfeTextView *tv,
               gpointer user_data)

/* "open-response" signal handler */
void
user_function (TfeTextView *tv,
               TfeTextViewOpenResponseType response-id,
               gpointer user_data)

The values of the parameter is defined in tfetextview.h because they are public.

/* "open-response" signal response */
enum
{
  TFE_OPEN_RESPONSE_SUCCESS,
  TFE_OPEN_RESPONSE_CANCEL,
  TFE_OPEN_RESPONSE_ERROR
};

Signal connection

A signal and a handler are connected by the function g_signal_connect. There are some similar functions like g_signal_connect_after, g_signal_connect_swapped and so on. However, g_signal_connect is the most common. The signals “change-file” is connected to a callback function out of the TfeTextView object. In the same way, the signals “open-response” is connected to a callback function out of the TfeTextView object. Those callback functions are defined by users.

In the program tfe, callback functions are defined in tfenotebook.c. And their names are file_changed and open_response. They will be explained later.

g_signal_connect (GTK_TEXT_VIEW (tv), "change-file", G_CALLBACK (file_changed), nb);

g_signal_connect (TFE_TEXT_VIEW (tv), "open-response", G_CALLBACK (open_response), nb);

Signal emission

Signals are emitted on an instance. The type of the instance is the second argument of g_signal_new. The relationship between the signal and object type is determined when the signal is registered.

A function g_signal_emit is used to emit the signal. The following lines are extracted from tfetextview.c. Each line comes from a different line.

g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_SUCCESS);
g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_CANCEL);
g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_ERROR);