GTK+ / Gnome Application Development | |||
---|---|---|---|
<<< Previous | Home | Next >>> |
Obviously, to subclass GtkWidget, you will have to be familiar with the base class. This section offers a brief tour of the GtkWidget class and instance structs, and some important GTK+ routines that aren't very common in everyday programming.
A GtkWidget instance looks like this:
typedef struct _GtkWidget GtkWidget; struct _GtkWidget { GtkObject object; guint16 private_flags; guint8 state; guint8 saved_state; gchar *name; GtkStyle *style; GtkRequisition requisition; GtkAllocation allocation; GdkWindow *window; GtkWidget *parent; }; |
The private_flags, state, and saved_state fields should all be accessed with macros, if at all. Some of these macros will come up as we discuss widget implementations. The state field stores the widget's state as described in the section called Widget States in the chapter called GTK+ Basics. saved_state is used to save the widget's previous state when the current state is GTK_STATE_INSENSITIVE; when the widget is re-sensitized, its original state is restored. As the section called Widget States in the chapter called GTK+ Basics explains, the current state can be accessed with the GTK_WIDGET_STATE() macro.
The name of a widget is used in a gtkrc file to group widgets together for customization purposes. By default, the name of a widget is the type name registered with the object system (in GTK+, this type name is always the name of the instance struct, such as "GtkLabel"). Particular widgets can be given a different name with gtk_widget_set_name(); for example, if you want a particular label to appear in a different font, you can give it a name like "FunkyFontLabel" and then specify a different font for that name in a gtkrc shipped with your application.
The requisition and allocation fields store the last requested and allocated size of the widget, respectively. the section called Size Negotiation will have more to say about this.
The window field stores the widget's GdkWindow, or the widget's parent's GdkWindow if the widget has none. The parent field is a pointer to the widget's parent container; it will be NULL if the widget is not inside a container.
There are a truly huge number of class functions in GtkWidgetClass. Thankfully, in most cases you only have to override a few of them. Here is the code:
typedef struct _GtkWidgetClass GtkWidgetClass; struct _GtkWidgetClass { GtkObjectClass parent_class; guint activate_signal; guint set_scroll_adjustments_signal; /* Basics */ void (* show) (GtkWidget *widget); void (* show_all) (GtkWidget *widget); void (* hide) (GtkWidget *widget); void (* hide_all) (GtkWidget *widget); void (* map) (GtkWidget *widget); void (* unmap) (GtkWidget *widget); void (* realize) (GtkWidget *widget); void (* unrealize) (GtkWidget *widget); void (* draw) (GtkWidget *widget, GdkRectangle *area); void (* draw_focus) (GtkWidget *widget); void (* draw_default) (GtkWidget *widget); void (* size_request) (GtkWidget *widget, GtkRequisition *requisition); void (* size_allocate) (GtkWidget *widget, GtkAllocation *allocation); void (* state_changed) (GtkWidget *widget, GtkStateType previous_state); void (* parent_set) (GtkWidget *widget, GtkWidget *previous_parent); void (* style_set) (GtkWidget *widget, GtkStyle *previous_style); /* Accelerators */ gint (* add_accelerator) (GtkWidget *widget, guint accel_signal_id, GtkAccelGroup *accel_group, guint accel_key, GdkModifierType accel_mods, GtkAccelFlags accel_flags); void (* remove_accelerator) (GtkWidget *widget, GtkAccelGroup *accel_group, guint accel_key, GdkModifierType accel_mods); /* Explicit focus */ void (* grab_focus) (GtkWidget *widget); /* Events */ gint (* event) (GtkWidget *widget, GdkEvent *event); gint (* button_press_event) (GtkWidget *widget, GdkEventButton *event); gint (* button_release_event) (GtkWidget *widget, GdkEventButton *event); gint (* motion_notify_event) (GtkWidget *widget, GdkEventMotion *event); gint (* delete_event) (GtkWidget *widget, GdkEventAny *event); gint (* destroy_event) (GtkWidget *widget, GdkEventAny *event); gint (* expose_event) (GtkWidget *widget, GdkEventExpose *event); gint (* key_press_event) (GtkWidget *widget, GdkEventKey *event); gint (* key_release_event) (GtkWidget *widget, GdkEventKey *event); gint (* enter_notify_event) (GtkWidget *widget, GdkEventCrossing *event); gint (* leave_notify_event) (GtkWidget *widget, GdkEventCrossing *event); gint (* configure_event) (GtkWidget *widget, GdkEventConfigure *event); gint (* focus_in_event) (GtkWidget *widget, GdkEventFocus *event); gint (* focus_out_event) (GtkWidget *widget, GdkEventFocus *event); gint (* map_event) (GtkWidget *widget, GdkEventAny *event); gint (* unmap_event) (GtkWidget *widget, GdkEventAny *event); gint (* property_notify_event) (GtkWidget *widget, GdkEventProperty *event); gint (* selection_clear_event) (GtkWidget *widget, GdkEventSelection *event); gint (* selection_request_event) (GtkWidget *widget, GdkEventSelection *event); gint (* selection_notify_event) (GtkWidget *widget, GdkEventSelection *event); gint (* proximity_in_event) (GtkWidget *widget, GdkEventProximity *event); gint (* proximity_out_event) (GtkWidget *widget, GdkEventProximity *event); gint (* visibility_notify_event) (GtkWidget *widget, GdkEventVisibility *event); gint (* client_event) (GtkWidget *widget, GdkEventClient *event); gint (* no_expose_event) (GtkWidget *widget, GdkEventAny *event); /* Selection */ void (* selection_get) (GtkWidget *widget, GtkSelectionData *selection_data, guint info, guint time); void (* selection_received) (GtkWidget *widget, GtkSelectionData *selection_data, guint time); /* Source side drag signals */ void (* drag_begin) (GtkWidget *widget, GdkDragContext *context); void (* drag_end) (GtkWidget *widget, GdkDragContext *context); void (* drag_data_get) (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time); void (* drag_data_delete) (GtkWidget *widget, GdkDragContext *context); /* Target side drag signals */ void (* drag_leave) (GtkWidget *widget, GdkDragContext *context, guint time); gboolean (* drag_motion) (GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time); gboolean (* drag_drop) (GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time); void (* drag_data_received) (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time); /* Action signals */ void (* debug_msg) (GtkWidget *widget, const gchar *string); /* Padding for future expansion */ GtkFunction pad1; GtkFunction pad2; GtkFunction pad3; GtkFunction pad4; }; |
Most of the functions in GtkWidgetClass are registered as default handlers for signals. The exceptions are show_all and hide_all, which are class functions only. Of course, GtkWidgetClass inherits the five class functions and single signal ("destroy") from GtkObjectClass. This chapter will describe the important methods in more detail; also, the section called Events in the chapter called GDK Basics is important for understanding the event methods. the section called GtkWidget In Detail describes the default implementation of each method in some detail.
You may notice that GtkWidgetClass contains two signal identifiers in addition to function pointers. These are 0 by default; otherwise, they indicate the signal to emit to "activate" the widget, or to set its scroll adjustments.
The activate_signal is emitted when the user presses the space bar or Enter key while the widget is focused; for buttons, it will be the "clicked" signal, for menu items, the "activate" signal.
The set_scroll_adjustments_signal is used by GtkScrolledWindow to set the scroll adjustments used by the widget. GtkLayout, GtkCList, and others have a signal to set the scroll adjustments.
These two hacks are necessary because GTK+ 1.2 does not support interfaces or multiple inheritance. (A future version of GTK+ may support interfaces similar in spirit to Java's interfaces.) Ideally, there would be "GtkActivatable" and "GtkScrollable" base classes or interfaces, and all widgets supporting these actions would derive from them. Including the two signal IDs in GtkWidgetClass is a short-term workaround.