If either of the signals the program connects to is
emitted, the corresponding callback is called. Our
"delete_event" callback
ends the gtk_main() event
loop by calling
gtk_main_quit(); this causes gtk_main() to return, ending the
program. The "clicked"
callback replaces the text from the label with the
same text in reverse. Notice that the label was
passed to the callback as the user_data parameter to gtk_signal_connect().
A common mistake is to assume that all signals use
the same kind of callback---not true. Each signal
requires a callback with a particular type signature
and particular behavior. The
"clicked" signal has a very common callback
type; its callback receives a pointer to the widget
emitting the signal and any
user_data provided by the programmer. This
callback must return void or memory corruption
is likely to occur.
"delete_event", on the
other hand, is something of a special case. It
accepts three arguments; the first and last are
analagous to "clicked",
while the second is a pointer to the event which
triggered the signal (events
are messages from X to the application, reporting
mouse movements, key presses, and the like). The
"delete_event" callback
returns a "magic" value---if FALSE is returned, GTK+ will
destroy the window; if
TRUE is returned, GTK+ will do nothing. Return
TRUE if you need to
do something other than destroy the window; for
example, you might want to warn the user about an
unsaved document.
Widget header files are the best quick reference for
callback signatures. The "class structure" for the
widget will have a space for a default signal
handler; your handler should be modeled on the
default one. For example, in
gtk/gtkbutton.h the
GtkButton class struct looks like this:
struct _GtkButtonClass
{
GtkBinClass parent_class;
void (* pressed) (GtkButton *button);
void (* released) (GtkButton *button);
void (* clicked) (GtkButton *button);
void (* enter) (GtkButton *button);
void (* leave) (GtkButton *button);
};
|
the chapter called The
GTK+ Object and Type System explains exactly
what a class struct is for; for now, just pay
attention to the function pointers, and note that
they correspond to signals. To get from this:
void (* clicked) (GtkButton *button);
|
to this:
static void button_click_cb(GtkWidget* w, gpointer data);
|
simply add a gpointer
data to the class struct function's signature.
In Hello, World I've also changed the type from GtkButton* to GtkWidget*; this is common, since
it can be more convenient to have a GtkWidget*. The argument will
always be the GtkButton
emitting the signal.
Another example may be useful; here is "delete_event" from gtk/gtkwidget.h:
gint (* delete_event) (GtkWidget *widget,
GdkEventAny *event);
|
and the callback from Hello, World:
static gint delete_event_cb(GtkWidget* w, GdkEventAny* e, gpointer data);
|
That's all there is to it. You can write simple GTK+
applications using only the information presented in
this section. GTK+ and Gnome are powerful application
development tools because you can think about real
functionality, instead of struggling to get a window
on the screen.