In a GTK+ program, you will never receive GDK events
directly. Instead, all events are passed to a GtkWidget, which emits a corresponding
signal. You handle events by connecting handlers to GtkWidget signals.
The X server sends each X client a stream of events.
Events are sent and received in the order of their
occurrence. GDK converts each
XEvent it receives into a GdkEvent, then places events in a
queue. GTK+ monitors GDK's event queue; for each event
received, it decides which widget (if any) should receive
the event. The GtkWidget base
class defines signals for most event types (such as "button_press_event"); it also
defines a generic "event"
signal. The GTK+ main loop calls
gtk_widget_event() to deliver an event to a widget;
this function first emits the
"event" signal, then emits a signal for the
specific event type (if appropriate). Some events are
handled in special ways; notably, drag-and-drop events do
not directly correspond to drag-and-drop signals.
In general, events go to the widget owning the GdkWindow the event occurred
on. However, there are certain special cases.
if a widget has the grab (i.e., if
gtk_grab_add() was called, see the section called Grabs in
the chapter called GTK+ Basics), certain
events will only be forwarded to the widget with the
grab, or the children of that widget. Events that occur
on other widgets are ignored. Only certain user-initiated
events such as button events and key events are affected
by a grab.
Widget sensitivity (see the section called
Sensitivity in the chapter called GTK+
Basics) also affects where events are sent.
Events representing user interaction are not forwarded to
insensitive widgets.
As you might expect, widgets with no associated GdkWindow do not originate
events; X only sends events to windows. There is one
exception: containers synthesize expose events for their
windowless children.
The GTK+ main loop propagates
certain events from child widgets to their parent
containers. That is, for each event, a signal is emitted
first from a child widget, then from its immediate
parent, then from the parent's parent, and so on. For
example, if you click a
GtkMenuItem, it ignores the button press and lets
the menu it's a part of handle it. Some events are not
propagated;
Table 4 gives details.
Event propagation ends once a widget "handles" the event.
This ensures that only one user-visible change results
from any user action. Handlers for
GtkWidget's event signals must return a gint value. Recall that the last
signal handler to run determines the return value of a
signal emission---see
the section called Emitting A Signal in the
chapter called The GTK+ Object and Type
System. All event signals are GTK_RUN_LAST, so the return value
will come from:
-
The last handler connected with
gtk_signal_connect_after(), if any.
-
Otherwise, the widget's default signal handler, if
any.
-
Otherwise, the last handler connected with gtk_signal_connect(), if any.
-
Otherwise, the default return value is FALSE.
If the emission of an event signal returns TRUE, the GTK+ main loop will stop
propagating the current event. If it returns FALSE, the main loop will propagate
the event to the widget's parent. Recall that each event
results in two signal emissions: a generic "event" signal and a specific signal
(such as "button_press_event"
or "key_press_event"). If either emission returns TRUE, event propagation ends. The
return value from the generic
"event" signal has one additional effect: if TRUE, the second, more specific
signal will not be emitted.
Table 4
summarizes how GtkWidget
signals correspond to event types, which events are
affected by an active grab, and which events are
propagated from parent to child. Signal handlers for all
event signals should return a
gint and take three arguments: the widget emitting
the signal, the event which triggered the signal, and a
user data pointer.
Table 4. GtkWidget
Events
Event Type
|
GtkWidget Signal
|
Propagated?
|
Grabbed?
|
GDK_DELETE
|
"delete_event"
|
No
|
No
|
GDK_DESTROY
|
"destroy_event"
|
No
|
No
|
GDK_EXPOSE
|
"expose_event"
|
No
|
No
|
GDK_MOTION_NOTIFY
|
"motion_notify_event"
|
Yes
|
Yes
|
GDK_BUTTON_PRESS
|
"button_press_event"
|
Yes
|
Yes
|
GDK_2BUTTON_PRESS
|
"button_press_event"
|
Yes
|
Yes
|
GDK_3BUTTON_PRESS
|
"button_press_event"
|
Yes
|
Yes
|
GDK_BUTTON_RELEASE
|
"button_release_event"
|
Yes
|
Yes
|
GDK_KEY_PRESS
|
"key_press_event"
|
Yes
|
Yes
|
GDK_KEY_RELEASE
|
"key_release_event"
|
Yes
|
Yes
|
GDK_ENTER_NOTIFY
|
"enter_notify_event"
|
No
|
Yes
|
GDK_LEAVE_NOTIFY
|
"leave_notify_event"
|
No
|
Yes [PD] footnote!
|
GDK_FOCUS_CHANGE
|
"focus_in_event", "focus_out_event"
|
No
|
No
|
GDK_CONFIGURE
|
"configure_event"
|
No
|
No
|
GDK_MAP
|
"map_event"
|
No
|
No
|
GDK_UNMAP
|
"unmap_event"
|
No
|
No
|
GDK_PROPERTY_NOTIFY
|
"property_notify_event"
|
No
|
No
|
GDK_SELECTION_CLEAR
|
"selection_clear_event"
|
No
|
No
|
GDK_SELECTION_REQUEST
|
"selection_request_event"
|
No
|
No
|
GDK_SELECTION_NOTIFY
|
"selection_notify_event"
|
No
|
No
|
GDK_PROXIMITY_IN
|
"proximity_in_event"
|
Yes
|
Yes
|
GDK_PROXIMITY_OUT
|
"proximity_out_event"
|
Yes
|
Yes
|
GDK_CLIENT_EVENT
|
"client_event"
|
No
|
No
|
GDK_VISIBILITY_NOTIFY
|
"visibility_notify_event"
|
No
|
No
|
GDK_NO_EXPOSE
|
"no_expose_event"
|
No
|
No
|