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.
tb = gtk_text_view_get_buffer (tv) is an instance
method on the instance tv. The caller requests
tv to give tb, which is a GtkTextBuffer
instance connected to tv.activate signal on GApplication
object. When the application is activated, the signal is emitted. Then
the handler, which has been connected to the signal, is invoked.The caller of methods or signals are usually out of the object. One of the difference between these two is that the object is active or passive. In methods, objects passively respond to the caller. In signals, objects actively send signals to handlers.
GObject signals are registered, connected and emitted.
g_signal_connect family
functions. A default handler is always called on any instance of the
class.g_signal_connect or its family functions. The connection is
usually done out of the object. One important thing is that signals are
connected on a certain instance. Suppose there exist two GtkButton
instances A, B and a function C. Even if you connected the “clicked”
signal on A to C, B and C are not connected.In TfeTextView, two signals are registered.
tv->file is changed.tfe_text_view_open
doesn’t return the status because it can’t get the status from the file
chooser dialog. (Instead, the call back function gets the status.) This
signal is emitted instead of the return value of the function.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
);
}g_signal_new
function is used. The signal “change-file” has no default handler
(object method handler) so the offset (the line 9) is set to zero. You
usually don’t need a default handler. If you need it, use
g_signal_new_class_handler function instead of
g_signal_new. See GObject
API Reference for further information.g_signal_new is the signal id. The
type of signal id is guint, which is the same as unsigned int. It is
used in the function g_signal_emit.G_TYPE_INT is a type of
integer. Such fundamental types are described in GObject
reference manual.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)tv points the instance on which the signal
is emitted.user_data comes from the fourth
argument of g_signal_connect.parameter (response-id) comes from the
fourth argument of g_signal_emit.The values of the type TfeTextViewOpenResponseType are
defined in tfetextview.h.
/* "open-response" signal response */
enum TfeTextViewOpenResponseType
{
TFE_OPEN_RESPONSE_SUCCESS,
TFE_OPEN_RESPONSE_CANCEL,
TFE_OPEN_RESPONSE_ERROR
};TFE_OPEN_RESPONSE_SUCCESS when
tfe_text_view_open has successfully opened a file and read
it.TFE_OPEN_RESPONSE_CANCEL when
the user has canceled.TFE_OPEN_RESPONSE_ERROR when an
error has occurred.A signal and a handler are connected by the function macro
g_signal_connect. There are some similar function macros
like g_signal_connect_after,
g_signal_connect_swapped and so on. However,
g_signal_connect is used most often. The signals
“change-file” and “open-response” are connected to their callback
functions out of the TfeTextView object. Those callback functions are
defined by users.
For example, callback functions are defined in
src/tfe6/tfewindow.c and their names are
file_changed_cb and open_response_cb. They
will be explained later.
g_signal_connect (GTK_TEXT_VIEW (tv), "change-file", G_CALLBACK (file_changed_cb), nb);
g_signal_connect (TFE_TEXT_VIEW (tv), "open-response", G_CALLBACK (open_response_cb), nb);A signal is emitted on the instance. A function
g_signal_emit is used to emit the signal. The following
lines are extracted from src/tfetextview/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);