diff --git a/ChangeLog b/ChangeLog index a6cad6a4878e49576a72744edc69b63767ed0a8a..2e9d069ca1ffd9de7d00a8478262006a7aa97238 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +Thu Aug 13 09:11:11 BST 1998 Tony Gale + + * docs/gtk_tut.sgml: + - Tidy up of the menufactory example from + Andy Kahn + - New section on Range Widgets from + David Huggins-Daines + - Started a new section on 'Advanced Event and Signal + Handling' - used an email from Owen. + - New appendix on Gdk Event Types + - Added the tictactoe full example code to the + 'Code Examples' appendix + Tue Jul 21 12:42:01 1998 Owen Taylor * gdk/gdk.h gdk/gdkfont.c: Added gdk_text/string_extents() - diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index a6cad6a4878e49576a72744edc69b63767ed0a8a..2e9d069ca1ffd9de7d00a8478262006a7aa97238 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,16 @@ +Thu Aug 13 09:11:11 BST 1998 Tony Gale + + * docs/gtk_tut.sgml: + - Tidy up of the menufactory example from + Andy Kahn + - New section on Range Widgets from + David Huggins-Daines + - Started a new section on 'Advanced Event and Signal + Handling' - used an email from Owen. + - New appendix on Gdk Event Types + - Added the tictactoe full example code to the + 'Code Examples' appendix + Tue Jul 21 12:42:01 1998 Owen Taylor * gdk/gdk.h gdk/gdkfont.c: Added gdk_text/string_extents() - diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index a6cad6a4878e49576a72744edc69b63767ed0a8a..2e9d069ca1ffd9de7d00a8478262006a7aa97238 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,16 @@ +Thu Aug 13 09:11:11 BST 1998 Tony Gale + + * docs/gtk_tut.sgml: + - Tidy up of the menufactory example from + Andy Kahn + - New section on Range Widgets from + David Huggins-Daines + - Started a new section on 'Advanced Event and Signal + Handling' - used an email from Owen. + - New appendix on Gdk Event Types + - Added the tictactoe full example code to the + 'Code Examples' appendix + Tue Jul 21 12:42:01 1998 Owen Taylor * gdk/gdk.h gdk/gdkfont.c: Added gdk_text/string_extents() - diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index a6cad6a4878e49576a72744edc69b63767ed0a8a..2e9d069ca1ffd9de7d00a8478262006a7aa97238 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,16 @@ +Thu Aug 13 09:11:11 BST 1998 Tony Gale + + * docs/gtk_tut.sgml: + - Tidy up of the menufactory example from + Andy Kahn + - New section on Range Widgets from + David Huggins-Daines + - Started a new section on 'Advanced Event and Signal + Handling' - used an email from Owen. + - New appendix on Gdk Event Types + - Added the tictactoe full example code to the + 'Code Examples' appendix + Tue Jul 21 12:42:01 1998 Owen Taylor * gdk/gdk.h gdk/gdkfont.c: Added gdk_text/string_extents() - diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index a6cad6a4878e49576a72744edc69b63767ed0a8a..2e9d069ca1ffd9de7d00a8478262006a7aa97238 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,16 @@ +Thu Aug 13 09:11:11 BST 1998 Tony Gale + + * docs/gtk_tut.sgml: + - Tidy up of the menufactory example from + Andy Kahn + - New section on Range Widgets from + David Huggins-Daines + - Started a new section on 'Advanced Event and Signal + Handling' - used an email from Owen. + - New appendix on Gdk Event Types + - Added the tictactoe full example code to the + 'Code Examples' appendix + Tue Jul 21 12:42:01 1998 Owen Taylor * gdk/gdk.h gdk/gdkfont.c: Added gdk_text/string_extents() - diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index a6cad6a4878e49576a72744edc69b63767ed0a8a..2e9d069ca1ffd9de7d00a8478262006a7aa97238 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,16 @@ +Thu Aug 13 09:11:11 BST 1998 Tony Gale + + * docs/gtk_tut.sgml: + - Tidy up of the menufactory example from + Andy Kahn + - New section on Range Widgets from + David Huggins-Daines + - Started a new section on 'Advanced Event and Signal + Handling' - used an email from Owen. + - New appendix on Gdk Event Types + - Added the tictactoe full example code to the + 'Code Examples' appendix + Tue Jul 21 12:42:01 1998 Owen Taylor * gdk/gdk.h gdk/gdkfont.c: Added gdk_text/string_extents() - diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index a6cad6a4878e49576a72744edc69b63767ed0a8a..2e9d069ca1ffd9de7d00a8478262006a7aa97238 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,16 @@ +Thu Aug 13 09:11:11 BST 1998 Tony Gale + + * docs/gtk_tut.sgml: + - Tidy up of the menufactory example from + Andy Kahn + - New section on Range Widgets from + David Huggins-Daines + - Started a new section on 'Advanced Event and Signal + Handling' - used an email from Owen. + - New appendix on Gdk Event Types + - Added the tictactoe full example code to the + 'Code Examples' appendix + Tue Jul 21 12:42:01 1998 Owen Taylor * gdk/gdk.h gdk/gdkfont.c: Added gdk_text/string_extents() - diff --git a/docs/gtk_tut.sgml b/docs/gtk_tut.sgml index d519ddbfc6c546a350974722120d2367216179b6..a948db791538068779327bd5a69b6116f742b25d 100644 --- a/docs/gtk_tut.sgml +++ b/docs/gtk_tut.sgml @@ -10,7 +10,7 @@ name="<imain@gtk.org>">, Tony Gale -July 25th, 1998 +August 13th, 1998 Introduction @@ -482,14 +482,17 @@ static gint button_press_event (GtkWidget *widget, Note that we can declare the second argument as type - - +propagate further. Returning FALSE continues the normal event handling. +See the section on + for more details on this +propagation process. + +For details on the GdkEvent data types, see the appendix entitled +. Stepping Through Hello World @@ -2085,6 +2088,775 @@ removes the need for a variable to hold the list of buttons: + +Range Widgets + +

+The category of range widgets includes the ubiquitous scrollbar +widget and the less common scale widget. Though these two +types of widgets are typically used for vastly different +purposes, they are quite similar in function and implementation. +Range widgets allow the user to visually manipulate a value +within a specified range (hence the name). + +All range widgets share a set of common graphic elements, each +of which has its own X window and receives events. They all +contain a "trough" and a "slider" (what is sometimes called a +"thumbwheel" in other GUI environments). Dragging the slider +with the pointer moves it back and forth within the trough, +while clicking in the trough advances the slider towards the +location of the click, either completely, or by a designated +amount (called a "page"), depending on which button was used. + + +The Scale Widgets +

+Scale widgets are used to set an explicitly numeric parameter +which has a visual correlate, and which the user might be +expected to adjust primarily by sight. For example, the +GtkColorSelection compound widget contains scale widgets which +control the components of the colour being selected. +Typically, the precise value of the number is less important +here than its side-effects, and thus the user should be spared +the effort of reaching for the keyboard. + + +Creating a Scale Widget +

+There are actually two types of scale widget: GtkHScale +widgets, which are horizontal, and GtkVScale widgets, which + +are vertical. (Most programmers seem to favour horizontal +scale widgets). Since they work essentially the same way, +there's no need to treat them separately here. The +following functions, defined in +<gtk/gtkvscale.h> and +<gtk/gtkhscale.h>, create vertical and +horizontal scale widgets, respectively: + + +GtkWidget* gtk_vscale_new( GtkAdjustment *adjustment ); + +GtkWidget* gtk_hscale_new( GtkAdjustment *adjustment ); + + + +below for an explanation of what exactly the +Functions, Signals, and Macros +

+Scale widgets can display their current value as a number +beside the trough. The default behaviour is to show the +value, but you can change this with this function: + + +void gtk_scale_set_draw_value( GtkScale *scale, + gint draw_value ); + + +As you might have guessed, +void gtk_scale_set_digits( GtkScale *scale, + gint digits); + + +where +void gtk_scale_set_value_pos( GtkScale *scale, + GtkPositionType pos ); + + +If you've read the section on the notebook widget, then you +know what the possible values of GtkPositionType and can take one +of the following values: + + +GTK_POS_LEFT +GTK_POS_RIGHT +GTK_POS_TOP +GTK_POS_BOTTOM + + +If you position the value on the "side" +of the trough (e.g. on the top or bottom of a horizontal +scale widget), then it will follow the slider up and down +the trough. + +All the preceding functions are defined in +<gtk/gtkscale.h>. The other signals and +functions defined in the header files for the scale widgets +are either not useful for anyone other than writers of scale +widgets, or are the standard GTK+ type-casting macros and +functions. + + +The Scrollbar Widgets +

+These are your standard, run-of-the-mill scrollbars. As with +the scale widgets, there are separate types for horizontal and +vertical scrollbars. There really isn't much to say about +these. You create them with the following functions: + + +GtkWidget* gtk_hscrollbar_new( GtkAdjustment *adjustment ); + +GtkWidget* gtk_vscrollbar_new( GtkAdjustment *adjustment ); + + +and that's about it (if you don't believe me, look in the +header files!). Again, +The Adjustment Object

+As you might have noticed, there really isn't much to the +various range widgets themselves from the programmer's point +of view. Most of your program's interaction with these +widgets will take place by way of the heretofore mysterious + +Creating a GtkAdjustment +

+You create an adjustment using: + + +GtkObject* gtk_adjustment_new( gfloat value, + gfloat lower, + gfloat upper, + gfloat step_increment, + gfloat page_increment, + gfloat page_size ); + + +It may or may not be obvious by now that the values given to + below +describes the default key and mouse bindings for range +widgets, and how they relate to these increments. The + +GtkObject *adj; + +adj = gtk_adjustment_new (0, first_line, last_line, 1, + window_height - 2, window_height); + + +where last_line - +window_height (or, in more general terms, upper - +page_height). This is a little confusing at first, but +it makes sense if you think about it in terms of what the +user expects to see in a scrolled window when the +scrollbar's slider is moved all the way to the end of the +trough. + +Since the size of the slider on scale widgets is invariable, +to avoid excessive confusion, it's a good idea to set the + +Inside the GtkAdjustment object +

+OK, you say, that's nice, but how do I get at all these +values, and, more importantly, how do I know when the user +has moved the slider around? To answer these questions and +more, let's start by taking a look at +struct _GtkAdjustment +{ + GtkData data; + + gfloat lower; + gfloat upper; + gfloat value; + gfloat step_increment; + gfloat page_increment; + gfloat page_size; +}; + +struct _GtkAdjustmentClass +{ + GtkDataClass parent_class; + + void (* changed) (GtkAdjustment *adjustment); + void (* value_changed) (GtkAdjustment *adjustment); +}; + + +The first thing you should know is that there aren't any +handy-dandy macros or accessor functions for getting the +GTK_ADJUSTMENT (Object) macro does +run-time type checking (as do all the GTK+ type-casting +macros, actually). On the other hand, unless you're writing +a new type of range widget, you probably don't want to + +void gtk_adjustment_set_value( GtkAdjustment *adjustment, + gfloat value ); + + +If you need to change the other fields, and you don't intend +to do this very frequently, it's best to create a new +GtkAdjustment and set it with + below. + +You might have noticed that, while adjustments are not +widgets, they are still a "subclass" of GtkObject. +Therefore, they can (and do) emit signals of their own. + +The various widgets that use the GtkAdjustment object will +emit the "value_changed" signal on an adjustment whenever +they change its value (see below for more detail). This +happens both when user input causes the slider to move on a +range widget, as well as when the program explicitly changes +the value with +void cb_rotate_picture (GtkAdjustment *adj, GtkWidget *picture) +{ + set_picture_rotation (picture, adj->value); +... + + +and connect it to the scale widget's adjustment like this: + + +gtk_signal_connect (GTK_OBJECT (adj), "value_changed", + GTK_SIGNAL_FUNC (cb_rotate_picture), picture); + + +The "changed" signal is somewhat more elusive. It is never +emitted directly due to the +Common Functions, Signals, and Macros

+The GtkRange widget class is fairly complicated internally, +but, like all the "base class" widgets, most of its complexity +is only interesting if you want to hack on it. Also, almost +all of the functions and signals it defines are only really +used in writing derived widgets. There are, however, a few +useful functions and concepts that are defined in gtkrange.h +and are common to all range widgets. + + +Update Policies

+The "update policy" of a range widget defines at what points +during user interaction it will change the <gtk/gtkenums.h> as the enum +GtkUpdateType, are: + + +GTK_UPDATE_POLICY_CONTINUOUS - This is the default. +The "value_changed" signal is emitted continuously, +i.e. whenever the slider is moved by even the tiniest +amount. + + +GTK_UPDATE_POLICY_DISCONTINUOUS - The +"value_changed" signal is only emitted once the slider +has stopped moving and the user has released the mouse +button. + + +GTK_UPDATE_POLICY_DELAYED - The "value_change" +signal is emitted when the user releases the mouse button, +or if the slider stops moving for a short period of +time. + + + +The update policy of a range widget can be set by casting it +using the GTK_RANGE (Widget) macro and passing it +to this function: + + +void gtk_range_set_update_policy( GtkRange *range, + GtkUpdateType policy ); + + + +Getting and setting adjustments +

+Getting and setting the adjustment for a range widget "on +the fly" is done, predictably, with: + + +GtkAdjustment* gtk_range_get_adjustment( GtkRange *range ); + +void gtk_range_set_adjustment( GtkRange *range, + GtkAdjustment *adjustment ); + + + + +gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed"); + + + +Key and Mouse bindings

+All of the GTK+ range widgets react to mouse clicks in more +or less the same way. Clicking button 1 in the trough will +cause its adjustment's +Vertical Range Widgets +

+All vertical range widgets can be operated with the up and +down arrow keys, as well as with the Control-Page Up and +Control-Page Down. + + +Horizontal Range Widgets +

+The left and right arrow keys work as you might expect in +these widgets, moving the slider back and forth by +Control-Left and +Control-Right, while for GtkHScrollbar, it's done +with Control-Home and Control-End. + + +Example

+This example is a somewhat modified version of the "range +widgets" test from +/* example-start rangewidgets rangewidgets.c */ + +#include + +GtkWidget *hscale, *vscale; + +void cb_pos_menu_select (GtkWidget *item, GtkPositionType pos) +{ + /* set the value position on both scale widgets */ + gtk_scale_set_value_pos (GTK_SCALE (hscale), pos); + gtk_scale_set_value_pos (GTK_SCALE (vscale), pos); +} + +void cb_update_menu_select (GtkWidget *item, GtkUpdateType policy) +{ + /* set the update policy for both scale widgets */ + gtk_range_set_update_policy (GTK_RANGE (hscale), policy); + gtk_range_set_update_policy (GTK_RANGE (vscale), policy); +} + +void cb_digits_scale (GtkAdjustment *adj) +{ + /* set the number of decimal places to which adj->vaule is rounded + */ + gtk_scale_set_digits (GTK_SCALE (hscale), (gint) adj->value); + gtk_scale_set_digits (GTK_SCALE (vscale), (gint) adj->value); +} + +void cb_page_size (GtkAdjustment *get, GtkAdjustment *set) +{ + /* set the page size and page increment size of the sample + adjustment to the value specified by the "Page Size" scale */ + set->page_size = get->value; + set->page_increment = get->value; + /* now emit the "changed" signal to reconfigure all the widgets that + are attached to this adjustment */ + gtk_signal_emit_by_name (GTK_OBJECT (set), "changed"); +} + +void cb_draw_value (GtkToggleButton *button) +{ + /* turn the value display on the scale widgets off or on depending + on the state of the checkbutton */ + gtk_scale_set_draw_value (GTK_SCALE (hscale), button->active); + gtk_scale_set_draw_value (GTK_SCALE (vscale), button->active); +} + +/* convenience functions */ + +GtkWidget *make_menu_item (gchar *name, GtkSignalFunc callback, + gpointer data) +{ + GtkWidget *item; + + item = gtk_menu_item_new_with_label (name); + gtk_signal_connect (GTK_OBJECT (item), "activate", + callback, data); + gtk_widget_show (item); + + return item; +} + +void scale_set_default_values (GtkScale *scale) +{ + gtk_range_set_update_policy (GTK_RANGE (scale), + GTK_UPDATE_CONTINUOUS); + gtk_scale_set_digits (scale, 1); + gtk_scale_set_value_pos (scale, GTK_POS_TOP); + gtk_scale_set_draw_value (scale, TRUE); +} + +/* makes the sample window */ + +void create_range_controls (void) +{ + GtkWidget *window; + GtkWidget *box1, *box2, *box3; + GtkWidget *button; + GtkWidget *scrollbar; + GtkWidget *separator; + GtkWidget *opt, *menu, *item; + GtkWidget *label; + GtkWidget *scale; + GtkObject *adj1, *adj2; + + /* standard window-creating stuff */ + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC(gtk_main_quit), + NULL); + gtk_window_set_title (GTK_WINDOW (window), "range controls"); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + /* value, lower, upper, step_increment, page_increment, page_size */ + /* note that the page_size value only makes a difference for + scrollbar widgets, and the highest value you'll get is actually + (upper - page_size). */ + adj1 = gtk_adjustment_new (0.0, 0.0, 101.0, 0.1, 1.0, 1.0); + + vscale = gtk_vscale_new (GTK_ADJUSTMENT (adj1)); + scale_set_default_values (GTK_SCALE (vscale)); + gtk_box_pack_start (GTK_BOX (box2), vscale, TRUE, TRUE, 0); + gtk_widget_show (vscale); + + box3 = gtk_vbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (box2), box3, TRUE, TRUE, 0); + gtk_widget_show (box3); + + /* reuse the same adjustment */ + hscale = gtk_hscale_new (GTK_ADJUSTMENT (adj1)); + gtk_widget_set_usize (GTK_WIDGET (hscale), 200, 30); + scale_set_default_values (GTK_SCALE (hscale)); + gtk_box_pack_start (GTK_BOX (box3), hscale, TRUE, TRUE, 0); + gtk_widget_show (hscale); + + /* reuse the same adjustment again */ + scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adj1)); + /* notice how this causes the scales to always be updated + continuously when the scrollbar is moved */ + gtk_range_set_update_policy (GTK_RANGE (scrollbar), + GTK_UPDATE_CONTINUOUS); + gtk_box_pack_start (GTK_BOX (box3), scrollbar, TRUE, TRUE, 0); + gtk_widget_show (scrollbar); + + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + /* a checkbutton to control whether the value is displayed or not */ + button = gtk_check_button_new_with_label + ("Display value on scale widgets"); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE); + gtk_signal_connect (GTK_OBJECT (button), "toggled", GTK_SIGNAL_FUNC + (cb_draw_value), NULL); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + + /* an option menu to change the position of the value */ + label = gtk_label_new ("Scale Value Position:"); + gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + opt = gtk_option_menu_new(); + menu = gtk_menu_new(); + + item = make_menu_item ("Top", GTK_SIGNAL_FUNC (cb_pos_menu_select), + GINT_TO_POINTER (GTK_POS_TOP)); + gtk_menu_append (GTK_MENU (menu), item); + + item = make_menu_item ("Bottom", GTK_SIGNAL_FUNC (cb_pos_menu_select), + GINT_TO_POINTER (GTK_POS_BOTTOM)); + gtk_menu_append (GTK_MENU (menu), item); + + item = make_menu_item ("Left", GTK_SIGNAL_FUNC (cb_pos_menu_select), + GINT_TO_POINTER (GTK_POS_LEFT)); + gtk_menu_append (GTK_MENU (menu), item); + + item = make_menu_item ("Right", GTK_SIGNAL_FUNC (cb_pos_menu_select), + GINT_TO_POINTER (GTK_POS_RIGHT)); + gtk_menu_append (GTK_MENU (menu), item); + + gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu); + gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0); + gtk_widget_show (opt); + + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + + /* yet another option menu, this time for the update policy of the + scale widgets */ + label = gtk_label_new ("Scale Update Policy:"); + gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + opt = gtk_option_menu_new(); + menu = gtk_menu_new(); + + item = make_menu_item ("Continuous", + GTK_SIGNAL_FUNC (cb_update_menu_select), + GINT_TO_POINTER (GTK_UPDATE_CONTINUOUS)); + gtk_menu_append (GTK_MENU (menu), item); + + item = make_menu_item ("Discontinuous", + GTK_SIGNAL_FUNC (cb_update_menu_select), + GINT_TO_POINTER (GTK_UPDATE_DISCONTINUOUS)); + gtk_menu_append (GTK_MENU (menu), item); + + item = make_menu_item ("Delayed", + GTK_SIGNAL_FUNC (cb_update_menu_select), + GINT_TO_POINTER (GTK_UPDATE_DELAYED)); + gtk_menu_append (GTK_MENU (menu), item); + + gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu); + gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0); + gtk_widget_show (opt); + + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + + /* a GtkHScale widget for adjusting the number of digits on the + sample scales. */ + label = gtk_label_new ("Scale Digits:"); + gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + adj2 = gtk_adjustment_new (1.0, 0.0, 5.0, 1.0, 1.0, 0.0); + gtk_signal_connect (GTK_OBJECT (adj2), "value_changed", + GTK_SIGNAL_FUNC (cb_digits_scale), NULL); + scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2)); + gtk_scale_set_digits (GTK_SCALE (scale), 0); + gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0); + gtk_widget_show (scale); + + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + + /* And, one last GtkHScale widget for adjusting the page size of the + scrollbar. */ + label = gtk_label_new ("Scrollbar Page Size:"); + gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + adj2 = gtk_adjustment_new (1.0, 1.0, 101.0, 1.0, 1.0, 0.0); + gtk_signal_connect (GTK_OBJECT (adj2), "value_changed", + GTK_SIGNAL_FUNC (cb_page_size), adj1); + scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2)); + gtk_scale_set_digits (GTK_SCALE (scale), 0); + gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0); + gtk_widget_show (scale); + + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + button = gtk_button_new_with_label ("Quit"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC(gtk_main_quit), + NULL); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + gtk_widget_show (window); +} + +int main (int argc, char *argv[]) +{ + gtk_init(&argc, &argv); + + create_range_controls(); + + gtk_main(); + + return 0; +} + +/* example-end */ + + Miscallaneous Widgets @@ -6328,7 +7100,7 @@ tree, and connects all the signals for the relevant objects, so you can see when they are emitted. -/* example-start tree tree.c */ +/* example-start tree tree.h */ #include @@ -6872,14 +7644,14 @@ of the global variables used in the menufactory.c file. extern "C" { #endif /* __cplusplus */ -void get_main_menu (GtkWidget **menubar, GtkAcceleratorTable **table); -void menus_create(GtkMenuEntry *entries, int nmenu_entries); +void get_main_menu (GtkWidget *, GtkWidget **menubar); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __MENUFACTORY_H__ */ + /* example-end */ @@ -6893,11 +7665,7 @@ And here is the menufactory.c file. #include "mfmain.h" - -static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path); -static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path); -void menus_init(void); -void menus_create(GtkMenuEntry * entries, int nmenu_entries); +static void print_hello(GtkWidget *widget, gpointer data); /* this is the GtkMenuEntry structure used to create new menus. The @@ -6910,131 +7678,39 @@ void menus_create(GtkMenuEntry * entries, int nmenu_entries); static GtkMenuEntry menu_items[] = { - {"

/File/New", "N", NULL, NULL}, - {"
/File/Open", "O", NULL, NULL}, - {"
/File/Save", "S", NULL, NULL}, - {"
/File/Save as", NULL, NULL, NULL}, - {"
/File/", NULL, NULL, NULL}, - {"
/File/Quit", "Q", file_quit_cmd_callback, "OK, I'll quit"}, - {"
/Options/Test", NULL, NULL, NULL} + {"
/File/New", "N", print_hello, NULL}, + {"
/File/Open", "O", print_hello, NULL}, + {"
/File/Save", "S", print_hello, NULL}, + {"
/File/Save as", NULL, NULL, NULL}, + {"
/File/", NULL, NULL, NULL}, + {"
/File/Quit", "Q", file_quit_cmd_callback, "OK, I'll quit"}, + {"
/Options/Test", NULL, NULL, NULL} }; -/* calculate the number of menu_item's */ -static int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]); -static int initialize = TRUE; -static GtkMenuFactory *factory = NULL; -static GtkMenuFactory *subfactory[1]; -static GHashTable *entry_ht = NULL; - -void get_main_menu(GtkWidget ** menubar, GtkAcceleratorTable ** table) +static void +print_hello(GtkWidget *widget, gpointer data) { - if (initialize) - menus_init(); - - if (menubar) - *menubar = subfactory[0]->widget; - if (table) - *table = subfactory[0]->table; + printf("hello!\n"); } -void menus_init(void) +void get_main_menu(GtkWidget *window, GtkWidget ** menubar) { - if (initialize) { - initialize = FALSE; - - factory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR); - subfactory[0] = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR); - - gtk_menu_factory_add_subfactory(factory, subfactory[0], "
"); - menus_create(menu_items, nmenu_items); - } -} + int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]); + GtkMenuFactory *factory; + GtkMenuFactory *subfactory; -void menus_create(GtkMenuEntry * entries, int nmenu_entries) -{ - char *accelerator; - int i; - - if (initialize) - menus_init(); - - if (entry_ht) - for (i = 0; i < nmenu_entries; i++) { - accelerator = g_hash_table_lookup(entry_ht, entries[i].path); - if (accelerator) { - if (accelerator[0] == '\0') - entries[i].accelerator = NULL; - else - entries[i].accelerator = accelerator; - } - } - gtk_menu_factory_add_entries(factory, entries, nmenu_entries); - - for (i = 0; i < nmenu_entries; i++) - if (entries[i].widget) { - gtk_signal_connect(GTK_OBJECT(entries[i].widget), "install_accelerator", - (GtkSignalFunc) menus_install_accel, - entries[i].path); - gtk_signal_connect(GTK_OBJECT(entries[i].widget), "remove_accelerator", - (GtkSignalFunc) menus_remove_accel, - entries[i].path); - } -} + factory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR); + subfactory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR); -static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path) -{ - char accel[64]; - char *t1, t2[2]; - - accel[0] = '\0'; - if (modifiers & GDK_CONTROL_MASK) - strcat(accel, ""); - if (modifiers & GDK_SHIFT_MASK) - strcat(accel, ""); - if (modifiers & GDK_MOD1_MASK) - strcat(accel, ""); + gtk_menu_factory_add_subfactory(factory, subfactory, "
"); + gtk_menu_factory_add_entries(factory, menu_items, nmenu_items); + gtk_window_add_accelerator_table(GTK_WINDOW(window), subfactory->table); - t2[0] = key; - t2[1] = '\0'; - strcat(accel, t2); - - if (entry_ht) { - t1 = g_hash_table_lookup(entry_ht, path); - g_free(t1); - } else - entry_ht = g_hash_table_new(g_str_hash, g_str_equal); - - g_hash_table_insert(entry_ht, path, g_strdup(accel)); - - return TRUE; + if (menubar) + *menubar = subfactory->widget; } -static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path) -{ - char *t; - - if (entry_ht) { - t = g_hash_table_lookup(entry_ht, path); - g_free(t); - - g_hash_table_insert(entry_ht, path, g_strdup("")); - } -} - -void menus_set_sensitive(char *path, int sensitive) -{ - GtkMenuPath *menu_path; - - if (initialize) - menus_init(); - - menu_path = gtk_menu_factory_find(factory, path); - if (menu_path) - gtk_widget_set_sensitive(menu_path->widget, sensitive); - else - g_warning("Unable to set sensitivity for menu which doesn't exist: %s", path); -} /* example-end */ @@ -7058,6 +7734,7 @@ void file_quit_cmd_callback(GtkWidget *widget, gpointer data); #endif /* __cplusplus */ #endif /* __MFMAIN_H__ */ + /* example-end */ @@ -7071,15 +7748,12 @@ And mfmain.c #include "mfmain.h" #include "menufactory.h" - int main(int argc, char *argv[]) { GtkWidget *window; GtkWidget *main_vbox; GtkWidget *menubar; - GtkAcceleratorTable *accel; - gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); @@ -7094,8 +7768,7 @@ int main(int argc, char *argv[]) gtk_container_add(GTK_CONTAINER(window), main_vbox); gtk_widget_show(main_vbox); - get_main_menu(&menubar, &accel); - gtk_window_add_accelerator_table(GTK_WINDOW(window), accel); + get_main_menu(window, &menubar); gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0); gtk_widget_show(menubar); @@ -7114,6 +7787,7 @@ void file_quit_cmd_callback (GtkWidget *widget, gpointer data) g_print ("%s\n", (char *) data); gtk_exit(0); } + /* example-end */ @@ -7571,9 +8245,6 @@ When you do come to understand all the functions of a new undocumented widget, please consider writing a tutorial on it so others may benifit from your time. - - Adjustments -

Toolbar

@@ -7581,9 +8252,6 @@ from your time. Fixed Container

- Range Controls -

- Curves

@@ -8282,6 +8950,169 @@ the ones above. The function pointed to by the first argument to gtk_idle_add will be called whenever the opportunity arises. As with the others, returning FALSE will stop the idle function from being called. + +Advanced Event and Signal Handling

+ + +guint gtk_signal_connect( GtkObject *object, + const gchar *name, + GtkSignalFunc func, + gpointer func_data ); + +guint gtk_signal_connect_after( GtkObject *object, + const gchar *name, + GtkSignalFunc func, + gpointer func_data ); + +guint gtk_signal_connect_object( GtkObject *object, + const gchar *name, + GtkSignalFunc func, + GtkObject *slot_object ); + +guint gtk_signal_connect_object_after( GtkObject *object, + const gchar *name, + GtkSignalFunc func, + GtkObject *slot_object ); + +guint gtk_signal_connect_full( GtkObject *object, + const gchar *name, + GtkSignalFunc func, + GtkCallbackMarshal marshal, + gpointer data, + GtkDestroyNotify destroy_func, + gint object_signal, + gint after ); + +guint gtk_signal_connect_interp( GtkObject *object, + const gchar *name, + GtkCallbackMarshal func, + gpointer data, + GtkDestroyNotify destroy_func, + gint after ); + +void gtk_signal_connect_object_while_alive( GtkObject *object, + const gchar *signal, + GtkSignalFunc func, + GtkObject *alive_object ); + +void gtk_signal_connect_while_alive( GtkObject *object, + const gchar *signal, + GtkSignalFunc func, + gpointer func_data, + GtkObject *alive_object ); + +void gtk_signal_disconnect( GtkObject *object, + guint handler_id ); + +void gtk_signal_disconnect_by_func( GtkObject *object, + GtkSignalFunc func, + gpointer data ); + + + +Blocking and Unblocking Signal Handlers +

+ +void gtk_signal_handler_block( GtkObject *object, + guint handler_id); + +void gtk_signal_handler_block_by_func( GtkObject *object, + GtkSignalFunc func, + gpointer data ); + +void gtk_signal_handler_block_by_data( GtkObject *object, + gpointer data ); + +void gtk_signal_handler_unblock( GtkObject *object, + guint handler_id ); + +void gtk_signal_handler_unblock_by_func( GtkObject *object, + GtkSignalFunc func, + gpointer data ); + +void gtk_signal_handler_unblock_by_data( GtkObject *object, + gpointer data ); + + + +Emitting and Stopping Signals +

+ +void gtk_signal_emit( GtkObject *object, + guint signal_id, + ... ); + +void gtk_signal_emit_by_name( GtkObject *object, + const gchar *name, + ... ); + +void gtk_signal_emitv( GtkObject *object, + guint signal_id, + GtkArg *params ); + +void gtk_signal_emitv_by_name( GtkObject *object, + const gchar *name, + GtkArg *params ); + +guint gtk_signal_n_emissions( GtkObject *object, + guint signal_id ); + +guint gtk_signal_n_emissions_by_name( GtkObject *object, + const gchar *name ); + +void gtk_signal_emit_stop( GtkObject *object, + guint signal_id ); + +void gtk_signal_emit_stop_by_name( GtkObject *object, + const gchar *name ); + + + +Signal Emission and Propagation +

+Signal emission is the process wherby GTK+ runs all handlers for a +specific object and signal. + +First, note that the return value from a signal emission is the +return value of the last handler executed. Since event signals +are all of type GTK_RUN_LAST, this will be the default (GTK+ supplied) +default handler, unless you connect with gtk_signal_connect_after(). + +The way an event (say GTK_BUTTON_PRESS) is handled, is: + +Start with the widget where the event occured. + +Emit the generic "event" signal. If that signal handler returns +a value of TRUE, stop all processing. + +Otherwise, emit a specific, "button_press_event" signal. If that +returns TRUE, stop all processing. + +Otherwise, go to the widget's parent, and repeat the above steps. + +Contimue until some signal handler returns TRUE, or until the +top-level widget is reached. + + +Some consequences of the above are: + +Your handler's return value will have no effect if there is a +default handler, unless you connect with gtk_signal_connect_after(). + +To prevent the default handler from being run, you need to connect +with gtk_signal_connect() and use gtk_signal_emit_stop_by_name() - the +return value only affects whether the signal is propagated, not the +current emission. + + Managing Selections @@ -11636,6 +12467,12 @@ name="rajat@ix.netcom.com" for the excellent job on the Pixmap tutorial. Michael K. Johnson for info and code for popup menus. +David Huggins-Daines for the Range Widgets and Tree Widget +sections. + +Stefan Mars for the GtkCList section

And to all of you who commented and helped refine this document. @@ -11674,6 +12511,439 @@ not make any guarentee that the information is even accurate. + + GDK Event Types

+The follwing data types are passed into event handlers by GTK+. For +each data type listed, the signals that use this data type are listed. + + + GdkEvent + + drag_end_event + + + GdkEventType + + GdkEventAny + + delete_event + destroy_event + map_event + unmap_event + no_expose_event + + + GdkEventExpose + + expose_event + + + GdkEventNoExpose + + GdkEventVisibility + + GdkEventMotion + + motion_notify_event + + + GdkEventButton + + button_press_event + button_release_event + + + GdkEventKey + + key_press_event + key_release_event + + + GdkEventCrossing + + enter_notify_event + leave_notify_event + + + GdkEventFocus + + focus_in_event + focus_out_event + + + GdkEventConfigure + + configure_event + + + GdkEventProperty + + property_notify_event + + + GdkEventSelection + + selection_clear_event + selection_request_event + selection_notify_event + + + GdkEventProximity + + proximity_in_event + proximity_out_event + + + GdkEventDragBegin + + drag_begin_event + + + GdkEventDragRequest + + drag_request_event + + + GdkEventDropEnter + + drop_enter_event + + + GdkEventDropLeave + + drop_leave_event + + + GdkEventDropDataAvailable + + drop_data_available_event + + + GdkEventClient + + client_event + + + GdkEventOther + + other_event + + + +The data type +typedef enum +{ + GDK_NOTHING = -1, + GDK_DELETE = 0, + GDK_DESTROY = 1, + GDK_EXPOSE = 2, + GDK_MOTION_NOTIFY = 3, + GDK_BUTTON_PRESS = 4, + GDK_2BUTTON_PRESS = 5, + GDK_3BUTTON_PRESS = 6, + GDK_BUTTON_RELEASE = 7, + GDK_KEY_PRESS = 8, + GDK_KEY_RELEASE = 9, + GDK_ENTER_NOTIFY = 10, + GDK_LEAVE_NOTIFY = 11, + GDK_FOCUS_CHANGE = 12, + GDK_CONFIGURE = 13, + GDK_MAP = 14, + GDK_UNMAP = 15, + GDK_PROPERTY_NOTIFY = 16, + GDK_SELECTION_CLEAR = 17, + GDK_SELECTION_REQUEST = 18, + GDK_SELECTION_NOTIFY = 19, + GDK_PROXIMITY_IN = 20, + GDK_PROXIMITY_OUT = 21, + GDK_DRAG_BEGIN = 22, + GDK_DRAG_REQUEST = 23, + GDK_DROP_ENTER = 24, + GDK_DROP_LEAVE = 25, + GDK_DROP_DATA_AVAIL = 26, + GDK_CLIENT_EVENT = 27, + GDK_VISIBILITY_NOTIFY = 28, + GDK_NO_EXPOSE = 29, + GDK_OTHER_EVENT = 9999 /* Deprecated, use filters instead */ +} GdkEventType; + + +The other event type that is different from the others is + +So, the event data types are defined as follows: + + +struct _GdkEventAny +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; +}; + +struct _GdkEventExpose +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkRectangle area; + gint count; /* If non-zero, how many more events follow. */ +}; + +struct _GdkEventNoExpose +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + /* XXX: does anyone need the X major_code or minor_code fields? */ +}; + +struct _GdkEventVisibility +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkVisibilityState state; +}; + +struct _GdkEventMotion +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + gdouble x; + gdouble y; + gdouble pressure; + gdouble xtilt; + gdouble ytilt; + guint state; + gint16 is_hint; + GdkInputSource source; + guint32 deviceid; + gdouble x_root, y_root; +}; + +struct _GdkEventButton +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + gdouble x; + gdouble y; + gdouble pressure; + gdouble xtilt; + gdouble ytilt; + guint state; + guint button; + GdkInputSource source; + guint32 deviceid; + gdouble x_root, y_root; +}; + +struct _GdkEventKey +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + guint state; + guint keyval; + gint length; + gchar *string; +}; + +struct _GdkEventCrossing +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkWindow *subwindow; + GdkNotifyType detail; +}; + +struct _GdkEventFocus +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + gint16 in; +}; + +struct _GdkEventConfigure +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + gint16 x, y; + gint16 width; + gint16 height; +}; + +struct _GdkEventProperty +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkAtom atom; + guint32 time; + guint state; +}; + +struct _GdkEventSelection +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkAtom selection; + GdkAtom target; + GdkAtom property; + guint32 requestor; + guint32 time; +}; + +/* This event type will be used pretty rarely. It only is important + for XInput aware programs that are drawing their own cursor */ + +struct _GdkEventProximity +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + GdkInputSource source; + guint32 deviceid; +}; + +struct _GdkEventDragRequest +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint sendreply:1; + guint willaccept:1; + guint delete_data:1; /* Do *not* delete if link is sent, only + if data is sent */ + guint senddata:1; + guint reserved:22; + } flags; + glong allflags; + } u; + guint8 isdrop; /* This gdk event can be generated by a couple of + X events - this lets the app know whether the + drop really occurred or we just set the data */ + + GdkPoint drop_coords; + gchar *data_type; + guint32 timestamp; +}; + +struct _GdkEventDragBegin +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + union { + struct { + guint protocol_version:4; + guint reserved:28; + } flags; + glong allflags; + } u; +}; + +struct _GdkEventDropEnter +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint sendreply:1; + guint extended_typelist:1; + guint reserved:26; + } flags; + glong allflags; + } u; +}; + +struct _GdkEventDropLeave +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint reserved:28; + } flags; + glong allflags; + } u; +}; + +struct _GdkEventDropDataAvailable +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint isdrop:1; + guint reserved:25; + } flags; + glong allflags; + } u; + gchar *data_type; /* MIME type */ + gulong data_numbytes; + gpointer data; + guint32 timestamp; + GdkPoint coords; +}; + +struct _GdkEventClient +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkAtom message_type; + gushort data_format; + union { + char b[20]; + short s[10]; + long l[5]; + } data; +}; + +struct _GdkEventOther +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkXEvent *xevent; +}; + + Code Examples @@ -11682,10 +12952,12 @@ Below are the code examples that are used in the above text which are not included in complete form elsewhere. - Scribble +Tictactoe + +tictactoe.h

-/* example-start scribble-simple scribble-simple.c */ +/* example-start tictactoe tictactoe.h */ /* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald @@ -11705,165 +12977,267 @@ which are not included in complete form elsewhere. * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ +#ifndef __TICTACTOE_H__ +#define __TICTACTOE_H__ -#include -/* Backing pixmap for drawing area */ -static GdkPixmap *pixmap = NULL; +#include +#include -/* Create a new backing pixmap of the appropriate size */ -static gint -configure_event (GtkWidget *widget, GdkEventConfigure *event) -{ - if (pixmap) - gdk_pixmap_unref(pixmap); - pixmap = gdk_pixmap_new(widget->window, - widget->allocation.width, - widget->allocation.height, - -1); - gdk_draw_rectangle (pixmap, - widget->style->white_gc, - TRUE, - 0, 0, - widget->allocation.width, - widget->allocation.height); +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ - return TRUE; -} +#define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe) +#define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass) +#define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ()) -/* Redraw the screen from the backing pixmap */ -static gint -expose_event (GtkWidget *widget, GdkEventExpose *event) + +typedef struct _Tictactoe Tictactoe; +typedef struct _TictactoeClass TictactoeClass; + +struct _Tictactoe { - gdk_draw_pixmap(widget->window, - widget->style->fg_gc[GTK_WIDGET_STATE (widget)], - pixmap, - event->area.x, event->area.y, - event->area.x, event->area.y, - event->area.width, event->area.height); - - return FALSE; -} + GtkVBox vbox; + + GtkWidget *buttons[3][3]; +}; -/* Draw a rectangle on the screen */ -static void -draw_brush (GtkWidget *widget, gdouble x, gdouble y) +struct _TictactoeClass { - GdkRectangle update_rect; + GtkVBoxClass parent_class; - update_rect.x = x - 5; - update_rect.y = y - 5; - update_rect.width = 10; - update_rect.height = 10; - gdk_draw_rectangle (pixmap, - widget->style->black_gc, - TRUE, - update_rect.x, update_rect.y, - update_rect.width, update_rect.height); - gtk_widget_draw (widget, &update_rect); -} + void (* tictactoe) (Tictactoe *ttt); +}; -static gint -button_press_event (GtkWidget *widget, GdkEventButton *event) -{ - if (event->button == 1 && pixmap != NULL) - draw_brush (widget, event->x, event->y); +guint tictactoe_get_type (void); +GtkWidget* tictactoe_new (void); +void tictactoe_clear (Tictactoe *ttt); - return TRUE; +#ifdef __cplusplus } +#endif /* __cplusplus */ -static gint -motion_notify_event (GtkWidget *widget, GdkEventMotion *event) +#endif /* __TICTACTOE_H__ */ + +/* example-end */ + + + +tictactoe.c +

+ +/* example-start tictactoe tictactoe.c */ + +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include "gtk/gtksignal.h" +#include "gtk/gtktable.h" +#include "gtk/gtktogglebutton.h" +#include "tictactoe.h" + +enum { + TICTACTOE_SIGNAL, + LAST_SIGNAL +}; + +static void tictactoe_class_init (TictactoeClass *klass); +static void tictactoe_init (Tictactoe *ttt); +static void tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt); + +static gint tictactoe_signals[LAST_SIGNAL] = { 0 }; + +guint +tictactoe_get_type () { - int x, y; - GdkModifierType state; + static guint ttt_type = 0; - if (event->is_hint) - gdk_window_get_pointer (event->window, &x, &y, &state); - else + if (!ttt_type) { - x = event->x; - y = event->y; - state = event->state; + GtkTypeInfo ttt_info = + { + "Tictactoe", + sizeof (Tictactoe), + sizeof (TictactoeClass), + (GtkClassInitFunc) tictactoe_class_init, + (GtkObjectInitFunc) tictactoe_init, + (GtkArgSetFunc) NULL, + (GtkArgGetFunc) NULL + }; + + ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info); } - - if (state & GDK_BUTTON1_MASK && pixmap != NULL) - draw_brush (widget, x, y); + + return ttt_type; +} + +static void +tictactoe_class_init (TictactoeClass *class) +{ + GtkObjectClass *object_class; + + object_class = (GtkObjectClass*) class; - return TRUE; + tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe), + gtk_signal_default_marshaller, GTK_TYPE_NONE, 0); + + + gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL); + + class->tictactoe = NULL; } -void -quit () +static void +tictactoe_init (Tictactoe *ttt) { - gtk_exit (0); + GtkWidget *table; + gint i,j; + + table = gtk_table_new (3, 3, TRUE); + gtk_container_add (GTK_CONTAINER(ttt), table); + gtk_widget_show (table); + + for (i=0;i<3; i++) + for (j=0;j<3; j++) + { + ttt->buttons[i][j] = gtk_toggle_button_new (); + gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j], + i, i+1, j, j+1); + gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled", + GTK_SIGNAL_FUNC (tictactoe_toggle), ttt); + gtk_widget_set_usize (ttt->buttons[i][j], 20, 20); + gtk_widget_show (ttt->buttons[i][j]); + } } -int -main (int argc, char *argv[]) +GtkWidget* +tictactoe_new () { - GtkWidget *window; - GtkWidget *drawing_area; - GtkWidget *vbox; + return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ())); +} - GtkWidget *button; +void +tictactoe_clear (Tictactoe *ttt) +{ + int i,j; - gtk_init (&argc, &argv); + for (i=0;i<3;i++) + for (j=0;j<3;j++) + { + gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]), + FALSE); + gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt); + } +} - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_widget_set_name (window, "Test Input"); +static void +tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt) +{ + int i,k; - vbox = gtk_vbox_new (FALSE, 0); - gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_widget_show (vbox); + static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 }, + { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 }, + { 0, 1, 2 }, { 0, 1, 2 } }; + static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 }, + { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 }, + { 0, 1, 2 }, { 2, 1, 0 } }; - gtk_signal_connect (GTK_OBJECT (window), "destroy", - GTK_SIGNAL_FUNC (quit), NULL); + int success, found; - /* Create the drawing area */ + for (k=0; k<8; k++) + { + success = TRUE; + found = FALSE; - drawing_area = gtk_drawing_area_new (); - gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200); - gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0); + for (i=0;i<3;i++) + { + success = success && + GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active; + found = found || + ttt->buttons[rwins[k][i]][cwins[k][i]] == widget; + } + + if (success && found) + { + gtk_signal_emit (GTK_OBJECT (ttt), + tictactoe_signals[TICTACTOE_SIGNAL]); + break; + } + } +} - gtk_widget_show (drawing_area); +/* example-end */ + - /* Signals used to handle backing pixmap */ + +ttt_test.c +

+ +/* example-start tictactoe ttt_test.c */ - gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event", - (GtkSignalFunc) expose_event, NULL); - gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event", - (GtkSignalFunc) configure_event, NULL); +#include +#include "tictactoe.h" - /* Event signals */ +void +win (GtkWidget *widget, gpointer data) +{ + g_print ("Yay!\n"); + tictactoe_clear (TICTACTOE (widget)); +} - gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event", - (GtkSignalFunc) motion_notify_event, NULL); - gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event", - (GtkSignalFunc) button_press_event, NULL); +int +main (int argc, char *argv[]) +{ + GtkWidget *window; + GtkWidget *ttt; + + gtk_init (&argc, &argv); - gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK - | GDK_LEAVE_NOTIFY_MASK - | GDK_BUTTON_PRESS_MASK - | GDK_POINTER_MOTION_MASK - | GDK_POINTER_MOTION_HINT_MASK); + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame"); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (gtk_exit), NULL); + + gtk_container_border_width (GTK_CONTAINER (window), 10); - /* .. And a quit button */ - button = gtk_button_new_with_label ("Quit"); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + ttt = tictactoe_new (); + + gtk_container_add (GTK_CONTAINER (window), ttt); + gtk_widget_show (ttt); - gtk_signal_connect_object (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (gtk_widget_destroy), - GTK_OBJECT (window)); - gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe", + GTK_SIGNAL_FUNC (win), NULL); gtk_widget_show (window); - + gtk_main (); - + return 0; } + /* example-end */ @@ -12565,4 +13939,191 @@ gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment, } /* example-end */ + + + Scribble +

+ +/* example-start scribble-simple scribble-simple.c */ + +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +/* Backing pixmap for drawing area */ +static GdkPixmap *pixmap = NULL; + +/* Create a new backing pixmap of the appropriate size */ +static gint +configure_event (GtkWidget *widget, GdkEventConfigure *event) +{ + if (pixmap) + gdk_pixmap_unref(pixmap); + + pixmap = gdk_pixmap_new(widget->window, + widget->allocation.width, + widget->allocation.height, + -1); + gdk_draw_rectangle (pixmap, + widget->style->white_gc, + TRUE, + 0, 0, + widget->allocation.width, + widget->allocation.height); + + return TRUE; +} + +/* Redraw the screen from the backing pixmap */ +static gint +expose_event (GtkWidget *widget, GdkEventExpose *event) +{ + gdk_draw_pixmap(widget->window, + widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + pixmap, + event->area.x, event->area.y, + event->area.x, event->area.y, + event->area.width, event->area.height); + + return FALSE; +} + +/* Draw a rectangle on the screen */ +static void +draw_brush (GtkWidget *widget, gdouble x, gdouble y) +{ + GdkRectangle update_rect; + + update_rect.x = x - 5; + update_rect.y = y - 5; + update_rect.width = 10; + update_rect.height = 10; + gdk_draw_rectangle (pixmap, + widget->style->black_gc, + TRUE, + update_rect.x, update_rect.y, + update_rect.width, update_rect.height); + gtk_widget_draw (widget, &update_rect); +} + +static gint +button_press_event (GtkWidget *widget, GdkEventButton *event) +{ + if (event->button == 1 && pixmap != NULL) + draw_brush (widget, event->x, event->y); + + return TRUE; +} + +static gint +motion_notify_event (GtkWidget *widget, GdkEventMotion *event) +{ + int x, y; + GdkModifierType state; + + if (event->is_hint) + gdk_window_get_pointer (event->window, &x, &y, &state); + else + { + x = event->x; + y = event->y; + state = event->state; + } + + if (state & GDK_BUTTON1_MASK && pixmap != NULL) + draw_brush (widget, x, y); + + return TRUE; +} + +void +quit () +{ + gtk_exit (0); +} + +int +main (int argc, char *argv[]) +{ + GtkWidget *window; + GtkWidget *drawing_area; + GtkWidget *vbox; + + GtkWidget *button; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_name (window, "Test Input"); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (quit), NULL); + + /* Create the drawing area */ + + drawing_area = gtk_drawing_area_new (); + gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200); + gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0); + + gtk_widget_show (drawing_area); + + /* Signals used to handle backing pixmap */ + + gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event", + (GtkSignalFunc) expose_event, NULL); + gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event", + (GtkSignalFunc) configure_event, NULL); + + /* Event signals */ + + gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event", + (GtkSignalFunc) motion_notify_event, NULL); + gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event", + (GtkSignalFunc) button_press_event, NULL); + + gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK + | GDK_LEAVE_NOTIFY_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK); + + /* .. And a quit button */ + button = gtk_button_new_with_label ("Quit"); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + GTK_OBJECT (window)); + gtk_widget_show (button); + + gtk_widget_show (window); + + gtk_main (); + + return 0; +} +/* example-end */ + + diff --git a/docs/tutorial/gtk_tut.sgml b/docs/tutorial/gtk_tut.sgml index d519ddbfc6c546a350974722120d2367216179b6..a948db791538068779327bd5a69b6116f742b25d 100644 --- a/docs/tutorial/gtk_tut.sgml +++ b/docs/tutorial/gtk_tut.sgml @@ -10,7 +10,7 @@ name="<imain@gtk.org>">, Tony Gale -July 25th, 1998 +August 13th, 1998 Introduction @@ -482,14 +482,17 @@ static gint button_press_event (GtkWidget *widget, Note that we can declare the second argument as type - - +propagate further. Returning FALSE continues the normal event handling. +See the section on + for more details on this +propagation process. + +For details on the GdkEvent data types, see the appendix entitled +. Stepping Through Hello World @@ -2085,6 +2088,775 @@ removes the need for a variable to hold the list of buttons: + +Range Widgets + +

+The category of range widgets includes the ubiquitous scrollbar +widget and the less common scale widget. Though these two +types of widgets are typically used for vastly different +purposes, they are quite similar in function and implementation. +Range widgets allow the user to visually manipulate a value +within a specified range (hence the name). + +All range widgets share a set of common graphic elements, each +of which has its own X window and receives events. They all +contain a "trough" and a "slider" (what is sometimes called a +"thumbwheel" in other GUI environments). Dragging the slider +with the pointer moves it back and forth within the trough, +while clicking in the trough advances the slider towards the +location of the click, either completely, or by a designated +amount (called a "page"), depending on which button was used. + + +The Scale Widgets +

+Scale widgets are used to set an explicitly numeric parameter +which has a visual correlate, and which the user might be +expected to adjust primarily by sight. For example, the +GtkColorSelection compound widget contains scale widgets which +control the components of the colour being selected. +Typically, the precise value of the number is less important +here than its side-effects, and thus the user should be spared +the effort of reaching for the keyboard. + + +Creating a Scale Widget +

+There are actually two types of scale widget: GtkHScale +widgets, which are horizontal, and GtkVScale widgets, which + +are vertical. (Most programmers seem to favour horizontal +scale widgets). Since they work essentially the same way, +there's no need to treat them separately here. The +following functions, defined in +<gtk/gtkvscale.h> and +<gtk/gtkhscale.h>, create vertical and +horizontal scale widgets, respectively: + + +GtkWidget* gtk_vscale_new( GtkAdjustment *adjustment ); + +GtkWidget* gtk_hscale_new( GtkAdjustment *adjustment ); + + + +below for an explanation of what exactly the +Functions, Signals, and Macros +

+Scale widgets can display their current value as a number +beside the trough. The default behaviour is to show the +value, but you can change this with this function: + + +void gtk_scale_set_draw_value( GtkScale *scale, + gint draw_value ); + + +As you might have guessed, +void gtk_scale_set_digits( GtkScale *scale, + gint digits); + + +where +void gtk_scale_set_value_pos( GtkScale *scale, + GtkPositionType pos ); + + +If you've read the section on the notebook widget, then you +know what the possible values of GtkPositionType and can take one +of the following values: + + +GTK_POS_LEFT +GTK_POS_RIGHT +GTK_POS_TOP +GTK_POS_BOTTOM + + +If you position the value on the "side" +of the trough (e.g. on the top or bottom of a horizontal +scale widget), then it will follow the slider up and down +the trough. + +All the preceding functions are defined in +<gtk/gtkscale.h>. The other signals and +functions defined in the header files for the scale widgets +are either not useful for anyone other than writers of scale +widgets, or are the standard GTK+ type-casting macros and +functions. + + +The Scrollbar Widgets +

+These are your standard, run-of-the-mill scrollbars. As with +the scale widgets, there are separate types for horizontal and +vertical scrollbars. There really isn't much to say about +these. You create them with the following functions: + + +GtkWidget* gtk_hscrollbar_new( GtkAdjustment *adjustment ); + +GtkWidget* gtk_vscrollbar_new( GtkAdjustment *adjustment ); + + +and that's about it (if you don't believe me, look in the +header files!). Again, +The Adjustment Object

+As you might have noticed, there really isn't much to the +various range widgets themselves from the programmer's point +of view. Most of your program's interaction with these +widgets will take place by way of the heretofore mysterious + +Creating a GtkAdjustment +

+You create an adjustment using: + + +GtkObject* gtk_adjustment_new( gfloat value, + gfloat lower, + gfloat upper, + gfloat step_increment, + gfloat page_increment, + gfloat page_size ); + + +It may or may not be obvious by now that the values given to + below +describes the default key and mouse bindings for range +widgets, and how they relate to these increments. The + +GtkObject *adj; + +adj = gtk_adjustment_new (0, first_line, last_line, 1, + window_height - 2, window_height); + + +where last_line - +window_height (or, in more general terms, upper - +page_height). This is a little confusing at first, but +it makes sense if you think about it in terms of what the +user expects to see in a scrolled window when the +scrollbar's slider is moved all the way to the end of the +trough. + +Since the size of the slider on scale widgets is invariable, +to avoid excessive confusion, it's a good idea to set the + +Inside the GtkAdjustment object +

+OK, you say, that's nice, but how do I get at all these +values, and, more importantly, how do I know when the user +has moved the slider around? To answer these questions and +more, let's start by taking a look at +struct _GtkAdjustment +{ + GtkData data; + + gfloat lower; + gfloat upper; + gfloat value; + gfloat step_increment; + gfloat page_increment; + gfloat page_size; +}; + +struct _GtkAdjustmentClass +{ + GtkDataClass parent_class; + + void (* changed) (GtkAdjustment *adjustment); + void (* value_changed) (GtkAdjustment *adjustment); +}; + + +The first thing you should know is that there aren't any +handy-dandy macros or accessor functions for getting the +GTK_ADJUSTMENT (Object) macro does +run-time type checking (as do all the GTK+ type-casting +macros, actually). On the other hand, unless you're writing +a new type of range widget, you probably don't want to + +void gtk_adjustment_set_value( GtkAdjustment *adjustment, + gfloat value ); + + +If you need to change the other fields, and you don't intend +to do this very frequently, it's best to create a new +GtkAdjustment and set it with + below. + +You might have noticed that, while adjustments are not +widgets, they are still a "subclass" of GtkObject. +Therefore, they can (and do) emit signals of their own. + +The various widgets that use the GtkAdjustment object will +emit the "value_changed" signal on an adjustment whenever +they change its value (see below for more detail). This +happens both when user input causes the slider to move on a +range widget, as well as when the program explicitly changes +the value with +void cb_rotate_picture (GtkAdjustment *adj, GtkWidget *picture) +{ + set_picture_rotation (picture, adj->value); +... + + +and connect it to the scale widget's adjustment like this: + + +gtk_signal_connect (GTK_OBJECT (adj), "value_changed", + GTK_SIGNAL_FUNC (cb_rotate_picture), picture); + + +The "changed" signal is somewhat more elusive. It is never +emitted directly due to the +Common Functions, Signals, and Macros

+The GtkRange widget class is fairly complicated internally, +but, like all the "base class" widgets, most of its complexity +is only interesting if you want to hack on it. Also, almost +all of the functions and signals it defines are only really +used in writing derived widgets. There are, however, a few +useful functions and concepts that are defined in gtkrange.h +and are common to all range widgets. + + +Update Policies

+The "update policy" of a range widget defines at what points +during user interaction it will change the <gtk/gtkenums.h> as the enum +GtkUpdateType, are: + + +GTK_UPDATE_POLICY_CONTINUOUS - This is the default. +The "value_changed" signal is emitted continuously, +i.e. whenever the slider is moved by even the tiniest +amount. + + +GTK_UPDATE_POLICY_DISCONTINUOUS - The +"value_changed" signal is only emitted once the slider +has stopped moving and the user has released the mouse +button. + + +GTK_UPDATE_POLICY_DELAYED - The "value_change" +signal is emitted when the user releases the mouse button, +or if the slider stops moving for a short period of +time. + + + +The update policy of a range widget can be set by casting it +using the GTK_RANGE (Widget) macro and passing it +to this function: + + +void gtk_range_set_update_policy( GtkRange *range, + GtkUpdateType policy ); + + + +Getting and setting adjustments +

+Getting and setting the adjustment for a range widget "on +the fly" is done, predictably, with: + + +GtkAdjustment* gtk_range_get_adjustment( GtkRange *range ); + +void gtk_range_set_adjustment( GtkRange *range, + GtkAdjustment *adjustment ); + + + + +gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed"); + + + +Key and Mouse bindings

+All of the GTK+ range widgets react to mouse clicks in more +or less the same way. Clicking button 1 in the trough will +cause its adjustment's +Vertical Range Widgets +

+All vertical range widgets can be operated with the up and +down arrow keys, as well as with the Control-Page Up and +Control-Page Down. + + +Horizontal Range Widgets +

+The left and right arrow keys work as you might expect in +these widgets, moving the slider back and forth by +Control-Left and +Control-Right, while for GtkHScrollbar, it's done +with Control-Home and Control-End. + + +Example

+This example is a somewhat modified version of the "range +widgets" test from +/* example-start rangewidgets rangewidgets.c */ + +#include + +GtkWidget *hscale, *vscale; + +void cb_pos_menu_select (GtkWidget *item, GtkPositionType pos) +{ + /* set the value position on both scale widgets */ + gtk_scale_set_value_pos (GTK_SCALE (hscale), pos); + gtk_scale_set_value_pos (GTK_SCALE (vscale), pos); +} + +void cb_update_menu_select (GtkWidget *item, GtkUpdateType policy) +{ + /* set the update policy for both scale widgets */ + gtk_range_set_update_policy (GTK_RANGE (hscale), policy); + gtk_range_set_update_policy (GTK_RANGE (vscale), policy); +} + +void cb_digits_scale (GtkAdjustment *adj) +{ + /* set the number of decimal places to which adj->vaule is rounded + */ + gtk_scale_set_digits (GTK_SCALE (hscale), (gint) adj->value); + gtk_scale_set_digits (GTK_SCALE (vscale), (gint) adj->value); +} + +void cb_page_size (GtkAdjustment *get, GtkAdjustment *set) +{ + /* set the page size and page increment size of the sample + adjustment to the value specified by the "Page Size" scale */ + set->page_size = get->value; + set->page_increment = get->value; + /* now emit the "changed" signal to reconfigure all the widgets that + are attached to this adjustment */ + gtk_signal_emit_by_name (GTK_OBJECT (set), "changed"); +} + +void cb_draw_value (GtkToggleButton *button) +{ + /* turn the value display on the scale widgets off or on depending + on the state of the checkbutton */ + gtk_scale_set_draw_value (GTK_SCALE (hscale), button->active); + gtk_scale_set_draw_value (GTK_SCALE (vscale), button->active); +} + +/* convenience functions */ + +GtkWidget *make_menu_item (gchar *name, GtkSignalFunc callback, + gpointer data) +{ + GtkWidget *item; + + item = gtk_menu_item_new_with_label (name); + gtk_signal_connect (GTK_OBJECT (item), "activate", + callback, data); + gtk_widget_show (item); + + return item; +} + +void scale_set_default_values (GtkScale *scale) +{ + gtk_range_set_update_policy (GTK_RANGE (scale), + GTK_UPDATE_CONTINUOUS); + gtk_scale_set_digits (scale, 1); + gtk_scale_set_value_pos (scale, GTK_POS_TOP); + gtk_scale_set_draw_value (scale, TRUE); +} + +/* makes the sample window */ + +void create_range_controls (void) +{ + GtkWidget *window; + GtkWidget *box1, *box2, *box3; + GtkWidget *button; + GtkWidget *scrollbar; + GtkWidget *separator; + GtkWidget *opt, *menu, *item; + GtkWidget *label; + GtkWidget *scale; + GtkObject *adj1, *adj2; + + /* standard window-creating stuff */ + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC(gtk_main_quit), + NULL); + gtk_window_set_title (GTK_WINDOW (window), "range controls"); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + /* value, lower, upper, step_increment, page_increment, page_size */ + /* note that the page_size value only makes a difference for + scrollbar widgets, and the highest value you'll get is actually + (upper - page_size). */ + adj1 = gtk_adjustment_new (0.0, 0.0, 101.0, 0.1, 1.0, 1.0); + + vscale = gtk_vscale_new (GTK_ADJUSTMENT (adj1)); + scale_set_default_values (GTK_SCALE (vscale)); + gtk_box_pack_start (GTK_BOX (box2), vscale, TRUE, TRUE, 0); + gtk_widget_show (vscale); + + box3 = gtk_vbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (box2), box3, TRUE, TRUE, 0); + gtk_widget_show (box3); + + /* reuse the same adjustment */ + hscale = gtk_hscale_new (GTK_ADJUSTMENT (adj1)); + gtk_widget_set_usize (GTK_WIDGET (hscale), 200, 30); + scale_set_default_values (GTK_SCALE (hscale)); + gtk_box_pack_start (GTK_BOX (box3), hscale, TRUE, TRUE, 0); + gtk_widget_show (hscale); + + /* reuse the same adjustment again */ + scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adj1)); + /* notice how this causes the scales to always be updated + continuously when the scrollbar is moved */ + gtk_range_set_update_policy (GTK_RANGE (scrollbar), + GTK_UPDATE_CONTINUOUS); + gtk_box_pack_start (GTK_BOX (box3), scrollbar, TRUE, TRUE, 0); + gtk_widget_show (scrollbar); + + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + /* a checkbutton to control whether the value is displayed or not */ + button = gtk_check_button_new_with_label + ("Display value on scale widgets"); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE); + gtk_signal_connect (GTK_OBJECT (button), "toggled", GTK_SIGNAL_FUNC + (cb_draw_value), NULL); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + + /* an option menu to change the position of the value */ + label = gtk_label_new ("Scale Value Position:"); + gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + opt = gtk_option_menu_new(); + menu = gtk_menu_new(); + + item = make_menu_item ("Top", GTK_SIGNAL_FUNC (cb_pos_menu_select), + GINT_TO_POINTER (GTK_POS_TOP)); + gtk_menu_append (GTK_MENU (menu), item); + + item = make_menu_item ("Bottom", GTK_SIGNAL_FUNC (cb_pos_menu_select), + GINT_TO_POINTER (GTK_POS_BOTTOM)); + gtk_menu_append (GTK_MENU (menu), item); + + item = make_menu_item ("Left", GTK_SIGNAL_FUNC (cb_pos_menu_select), + GINT_TO_POINTER (GTK_POS_LEFT)); + gtk_menu_append (GTK_MENU (menu), item); + + item = make_menu_item ("Right", GTK_SIGNAL_FUNC (cb_pos_menu_select), + GINT_TO_POINTER (GTK_POS_RIGHT)); + gtk_menu_append (GTK_MENU (menu), item); + + gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu); + gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0); + gtk_widget_show (opt); + + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + + /* yet another option menu, this time for the update policy of the + scale widgets */ + label = gtk_label_new ("Scale Update Policy:"); + gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + opt = gtk_option_menu_new(); + menu = gtk_menu_new(); + + item = make_menu_item ("Continuous", + GTK_SIGNAL_FUNC (cb_update_menu_select), + GINT_TO_POINTER (GTK_UPDATE_CONTINUOUS)); + gtk_menu_append (GTK_MENU (menu), item); + + item = make_menu_item ("Discontinuous", + GTK_SIGNAL_FUNC (cb_update_menu_select), + GINT_TO_POINTER (GTK_UPDATE_DISCONTINUOUS)); + gtk_menu_append (GTK_MENU (menu), item); + + item = make_menu_item ("Delayed", + GTK_SIGNAL_FUNC (cb_update_menu_select), + GINT_TO_POINTER (GTK_UPDATE_DELAYED)); + gtk_menu_append (GTK_MENU (menu), item); + + gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu); + gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0); + gtk_widget_show (opt); + + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + + /* a GtkHScale widget for adjusting the number of digits on the + sample scales. */ + label = gtk_label_new ("Scale Digits:"); + gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + adj2 = gtk_adjustment_new (1.0, 0.0, 5.0, 1.0, 1.0, 0.0); + gtk_signal_connect (GTK_OBJECT (adj2), "value_changed", + GTK_SIGNAL_FUNC (cb_digits_scale), NULL); + scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2)); + gtk_scale_set_digits (GTK_SCALE (scale), 0); + gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0); + gtk_widget_show (scale); + + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + + /* And, one last GtkHScale widget for adjusting the page size of the + scrollbar. */ + label = gtk_label_new ("Scrollbar Page Size:"); + gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + adj2 = gtk_adjustment_new (1.0, 1.0, 101.0, 1.0, 1.0, 0.0); + gtk_signal_connect (GTK_OBJECT (adj2), "value_changed", + GTK_SIGNAL_FUNC (cb_page_size), adj1); + scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2)); + gtk_scale_set_digits (GTK_SCALE (scale), 0); + gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0); + gtk_widget_show (scale); + + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + button = gtk_button_new_with_label ("Quit"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC(gtk_main_quit), + NULL); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + gtk_widget_show (window); +} + +int main (int argc, char *argv[]) +{ + gtk_init(&argc, &argv); + + create_range_controls(); + + gtk_main(); + + return 0; +} + +/* example-end */ + + Miscallaneous Widgets @@ -6328,7 +7100,7 @@ tree, and connects all the signals for the relevant objects, so you can see when they are emitted. -/* example-start tree tree.c */ +/* example-start tree tree.h */ #include @@ -6872,14 +7644,14 @@ of the global variables used in the menufactory.c file. extern "C" { #endif /* __cplusplus */ -void get_main_menu (GtkWidget **menubar, GtkAcceleratorTable **table); -void menus_create(GtkMenuEntry *entries, int nmenu_entries); +void get_main_menu (GtkWidget *, GtkWidget **menubar); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __MENUFACTORY_H__ */ + /* example-end */ @@ -6893,11 +7665,7 @@ And here is the menufactory.c file. #include "mfmain.h" - -static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path); -static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path); -void menus_init(void); -void menus_create(GtkMenuEntry * entries, int nmenu_entries); +static void print_hello(GtkWidget *widget, gpointer data); /* this is the GtkMenuEntry structure used to create new menus. The @@ -6910,131 +7678,39 @@ void menus_create(GtkMenuEntry * entries, int nmenu_entries); static GtkMenuEntry menu_items[] = { - {"

/File/New", "N", NULL, NULL}, - {"
/File/Open", "O", NULL, NULL}, - {"
/File/Save", "S", NULL, NULL}, - {"
/File/Save as", NULL, NULL, NULL}, - {"
/File/", NULL, NULL, NULL}, - {"
/File/Quit", "Q", file_quit_cmd_callback, "OK, I'll quit"}, - {"
/Options/Test", NULL, NULL, NULL} + {"
/File/New", "N", print_hello, NULL}, + {"
/File/Open", "O", print_hello, NULL}, + {"
/File/Save", "S", print_hello, NULL}, + {"
/File/Save as", NULL, NULL, NULL}, + {"
/File/", NULL, NULL, NULL}, + {"
/File/Quit", "Q", file_quit_cmd_callback, "OK, I'll quit"}, + {"
/Options/Test", NULL, NULL, NULL} }; -/* calculate the number of menu_item's */ -static int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]); -static int initialize = TRUE; -static GtkMenuFactory *factory = NULL; -static GtkMenuFactory *subfactory[1]; -static GHashTable *entry_ht = NULL; - -void get_main_menu(GtkWidget ** menubar, GtkAcceleratorTable ** table) +static void +print_hello(GtkWidget *widget, gpointer data) { - if (initialize) - menus_init(); - - if (menubar) - *menubar = subfactory[0]->widget; - if (table) - *table = subfactory[0]->table; + printf("hello!\n"); } -void menus_init(void) +void get_main_menu(GtkWidget *window, GtkWidget ** menubar) { - if (initialize) { - initialize = FALSE; - - factory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR); - subfactory[0] = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR); - - gtk_menu_factory_add_subfactory(factory, subfactory[0], "
"); - menus_create(menu_items, nmenu_items); - } -} + int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]); + GtkMenuFactory *factory; + GtkMenuFactory *subfactory; -void menus_create(GtkMenuEntry * entries, int nmenu_entries) -{ - char *accelerator; - int i; - - if (initialize) - menus_init(); - - if (entry_ht) - for (i = 0; i < nmenu_entries; i++) { - accelerator = g_hash_table_lookup(entry_ht, entries[i].path); - if (accelerator) { - if (accelerator[0] == '\0') - entries[i].accelerator = NULL; - else - entries[i].accelerator = accelerator; - } - } - gtk_menu_factory_add_entries(factory, entries, nmenu_entries); - - for (i = 0; i < nmenu_entries; i++) - if (entries[i].widget) { - gtk_signal_connect(GTK_OBJECT(entries[i].widget), "install_accelerator", - (GtkSignalFunc) menus_install_accel, - entries[i].path); - gtk_signal_connect(GTK_OBJECT(entries[i].widget), "remove_accelerator", - (GtkSignalFunc) menus_remove_accel, - entries[i].path); - } -} + factory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR); + subfactory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR); -static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path) -{ - char accel[64]; - char *t1, t2[2]; - - accel[0] = '\0'; - if (modifiers & GDK_CONTROL_MASK) - strcat(accel, ""); - if (modifiers & GDK_SHIFT_MASK) - strcat(accel, ""); - if (modifiers & GDK_MOD1_MASK) - strcat(accel, ""); + gtk_menu_factory_add_subfactory(factory, subfactory, "
"); + gtk_menu_factory_add_entries(factory, menu_items, nmenu_items); + gtk_window_add_accelerator_table(GTK_WINDOW(window), subfactory->table); - t2[0] = key; - t2[1] = '\0'; - strcat(accel, t2); - - if (entry_ht) { - t1 = g_hash_table_lookup(entry_ht, path); - g_free(t1); - } else - entry_ht = g_hash_table_new(g_str_hash, g_str_equal); - - g_hash_table_insert(entry_ht, path, g_strdup(accel)); - - return TRUE; + if (menubar) + *menubar = subfactory->widget; } -static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path) -{ - char *t; - - if (entry_ht) { - t = g_hash_table_lookup(entry_ht, path); - g_free(t); - - g_hash_table_insert(entry_ht, path, g_strdup("")); - } -} - -void menus_set_sensitive(char *path, int sensitive) -{ - GtkMenuPath *menu_path; - - if (initialize) - menus_init(); - - menu_path = gtk_menu_factory_find(factory, path); - if (menu_path) - gtk_widget_set_sensitive(menu_path->widget, sensitive); - else - g_warning("Unable to set sensitivity for menu which doesn't exist: %s", path); -} /* example-end */ @@ -7058,6 +7734,7 @@ void file_quit_cmd_callback(GtkWidget *widget, gpointer data); #endif /* __cplusplus */ #endif /* __MFMAIN_H__ */ + /* example-end */ @@ -7071,15 +7748,12 @@ And mfmain.c #include "mfmain.h" #include "menufactory.h" - int main(int argc, char *argv[]) { GtkWidget *window; GtkWidget *main_vbox; GtkWidget *menubar; - GtkAcceleratorTable *accel; - gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); @@ -7094,8 +7768,7 @@ int main(int argc, char *argv[]) gtk_container_add(GTK_CONTAINER(window), main_vbox); gtk_widget_show(main_vbox); - get_main_menu(&menubar, &accel); - gtk_window_add_accelerator_table(GTK_WINDOW(window), accel); + get_main_menu(window, &menubar); gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0); gtk_widget_show(menubar); @@ -7114,6 +7787,7 @@ void file_quit_cmd_callback (GtkWidget *widget, gpointer data) g_print ("%s\n", (char *) data); gtk_exit(0); } + /* example-end */ @@ -7571,9 +8245,6 @@ When you do come to understand all the functions of a new undocumented widget, please consider writing a tutorial on it so others may benifit from your time. - - Adjustments -

Toolbar

@@ -7581,9 +8252,6 @@ from your time. Fixed Container

- Range Controls -

- Curves

@@ -8282,6 +8950,169 @@ the ones above. The function pointed to by the first argument to gtk_idle_add will be called whenever the opportunity arises. As with the others, returning FALSE will stop the idle function from being called. + +Advanced Event and Signal Handling

+ + +guint gtk_signal_connect( GtkObject *object, + const gchar *name, + GtkSignalFunc func, + gpointer func_data ); + +guint gtk_signal_connect_after( GtkObject *object, + const gchar *name, + GtkSignalFunc func, + gpointer func_data ); + +guint gtk_signal_connect_object( GtkObject *object, + const gchar *name, + GtkSignalFunc func, + GtkObject *slot_object ); + +guint gtk_signal_connect_object_after( GtkObject *object, + const gchar *name, + GtkSignalFunc func, + GtkObject *slot_object ); + +guint gtk_signal_connect_full( GtkObject *object, + const gchar *name, + GtkSignalFunc func, + GtkCallbackMarshal marshal, + gpointer data, + GtkDestroyNotify destroy_func, + gint object_signal, + gint after ); + +guint gtk_signal_connect_interp( GtkObject *object, + const gchar *name, + GtkCallbackMarshal func, + gpointer data, + GtkDestroyNotify destroy_func, + gint after ); + +void gtk_signal_connect_object_while_alive( GtkObject *object, + const gchar *signal, + GtkSignalFunc func, + GtkObject *alive_object ); + +void gtk_signal_connect_while_alive( GtkObject *object, + const gchar *signal, + GtkSignalFunc func, + gpointer func_data, + GtkObject *alive_object ); + +void gtk_signal_disconnect( GtkObject *object, + guint handler_id ); + +void gtk_signal_disconnect_by_func( GtkObject *object, + GtkSignalFunc func, + gpointer data ); + + + +Blocking and Unblocking Signal Handlers +

+ +void gtk_signal_handler_block( GtkObject *object, + guint handler_id); + +void gtk_signal_handler_block_by_func( GtkObject *object, + GtkSignalFunc func, + gpointer data ); + +void gtk_signal_handler_block_by_data( GtkObject *object, + gpointer data ); + +void gtk_signal_handler_unblock( GtkObject *object, + guint handler_id ); + +void gtk_signal_handler_unblock_by_func( GtkObject *object, + GtkSignalFunc func, + gpointer data ); + +void gtk_signal_handler_unblock_by_data( GtkObject *object, + gpointer data ); + + + +Emitting and Stopping Signals +

+ +void gtk_signal_emit( GtkObject *object, + guint signal_id, + ... ); + +void gtk_signal_emit_by_name( GtkObject *object, + const gchar *name, + ... ); + +void gtk_signal_emitv( GtkObject *object, + guint signal_id, + GtkArg *params ); + +void gtk_signal_emitv_by_name( GtkObject *object, + const gchar *name, + GtkArg *params ); + +guint gtk_signal_n_emissions( GtkObject *object, + guint signal_id ); + +guint gtk_signal_n_emissions_by_name( GtkObject *object, + const gchar *name ); + +void gtk_signal_emit_stop( GtkObject *object, + guint signal_id ); + +void gtk_signal_emit_stop_by_name( GtkObject *object, + const gchar *name ); + + + +Signal Emission and Propagation +

+Signal emission is the process wherby GTK+ runs all handlers for a +specific object and signal. + +First, note that the return value from a signal emission is the +return value of the last handler executed. Since event signals +are all of type GTK_RUN_LAST, this will be the default (GTK+ supplied) +default handler, unless you connect with gtk_signal_connect_after(). + +The way an event (say GTK_BUTTON_PRESS) is handled, is: + +Start with the widget where the event occured. + +Emit the generic "event" signal. If that signal handler returns +a value of TRUE, stop all processing. + +Otherwise, emit a specific, "button_press_event" signal. If that +returns TRUE, stop all processing. + +Otherwise, go to the widget's parent, and repeat the above steps. + +Contimue until some signal handler returns TRUE, or until the +top-level widget is reached. + + +Some consequences of the above are: + +Your handler's return value will have no effect if there is a +default handler, unless you connect with gtk_signal_connect_after(). + +To prevent the default handler from being run, you need to connect +with gtk_signal_connect() and use gtk_signal_emit_stop_by_name() - the +return value only affects whether the signal is propagated, not the +current emission. + + Managing Selections @@ -11636,6 +12467,12 @@ name="rajat@ix.netcom.com" for the excellent job on the Pixmap tutorial. Michael K. Johnson for info and code for popup menus. +David Huggins-Daines for the Range Widgets and Tree Widget +sections. + +Stefan Mars for the GtkCList section

And to all of you who commented and helped refine this document. @@ -11674,6 +12511,439 @@ not make any guarentee that the information is even accurate. + + GDK Event Types

+The follwing data types are passed into event handlers by GTK+. For +each data type listed, the signals that use this data type are listed. + + + GdkEvent + + drag_end_event + + + GdkEventType + + GdkEventAny + + delete_event + destroy_event + map_event + unmap_event + no_expose_event + + + GdkEventExpose + + expose_event + + + GdkEventNoExpose + + GdkEventVisibility + + GdkEventMotion + + motion_notify_event + + + GdkEventButton + + button_press_event + button_release_event + + + GdkEventKey + + key_press_event + key_release_event + + + GdkEventCrossing + + enter_notify_event + leave_notify_event + + + GdkEventFocus + + focus_in_event + focus_out_event + + + GdkEventConfigure + + configure_event + + + GdkEventProperty + + property_notify_event + + + GdkEventSelection + + selection_clear_event + selection_request_event + selection_notify_event + + + GdkEventProximity + + proximity_in_event + proximity_out_event + + + GdkEventDragBegin + + drag_begin_event + + + GdkEventDragRequest + + drag_request_event + + + GdkEventDropEnter + + drop_enter_event + + + GdkEventDropLeave + + drop_leave_event + + + GdkEventDropDataAvailable + + drop_data_available_event + + + GdkEventClient + + client_event + + + GdkEventOther + + other_event + + + +The data type +typedef enum +{ + GDK_NOTHING = -1, + GDK_DELETE = 0, + GDK_DESTROY = 1, + GDK_EXPOSE = 2, + GDK_MOTION_NOTIFY = 3, + GDK_BUTTON_PRESS = 4, + GDK_2BUTTON_PRESS = 5, + GDK_3BUTTON_PRESS = 6, + GDK_BUTTON_RELEASE = 7, + GDK_KEY_PRESS = 8, + GDK_KEY_RELEASE = 9, + GDK_ENTER_NOTIFY = 10, + GDK_LEAVE_NOTIFY = 11, + GDK_FOCUS_CHANGE = 12, + GDK_CONFIGURE = 13, + GDK_MAP = 14, + GDK_UNMAP = 15, + GDK_PROPERTY_NOTIFY = 16, + GDK_SELECTION_CLEAR = 17, + GDK_SELECTION_REQUEST = 18, + GDK_SELECTION_NOTIFY = 19, + GDK_PROXIMITY_IN = 20, + GDK_PROXIMITY_OUT = 21, + GDK_DRAG_BEGIN = 22, + GDK_DRAG_REQUEST = 23, + GDK_DROP_ENTER = 24, + GDK_DROP_LEAVE = 25, + GDK_DROP_DATA_AVAIL = 26, + GDK_CLIENT_EVENT = 27, + GDK_VISIBILITY_NOTIFY = 28, + GDK_NO_EXPOSE = 29, + GDK_OTHER_EVENT = 9999 /* Deprecated, use filters instead */ +} GdkEventType; + + +The other event type that is different from the others is + +So, the event data types are defined as follows: + + +struct _GdkEventAny +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; +}; + +struct _GdkEventExpose +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkRectangle area; + gint count; /* If non-zero, how many more events follow. */ +}; + +struct _GdkEventNoExpose +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + /* XXX: does anyone need the X major_code or minor_code fields? */ +}; + +struct _GdkEventVisibility +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkVisibilityState state; +}; + +struct _GdkEventMotion +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + gdouble x; + gdouble y; + gdouble pressure; + gdouble xtilt; + gdouble ytilt; + guint state; + gint16 is_hint; + GdkInputSource source; + guint32 deviceid; + gdouble x_root, y_root; +}; + +struct _GdkEventButton +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + gdouble x; + gdouble y; + gdouble pressure; + gdouble xtilt; + gdouble ytilt; + guint state; + guint button; + GdkInputSource source; + guint32 deviceid; + gdouble x_root, y_root; +}; + +struct _GdkEventKey +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + guint state; + guint keyval; + gint length; + gchar *string; +}; + +struct _GdkEventCrossing +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkWindow *subwindow; + GdkNotifyType detail; +}; + +struct _GdkEventFocus +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + gint16 in; +}; + +struct _GdkEventConfigure +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + gint16 x, y; + gint16 width; + gint16 height; +}; + +struct _GdkEventProperty +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkAtom atom; + guint32 time; + guint state; +}; + +struct _GdkEventSelection +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkAtom selection; + GdkAtom target; + GdkAtom property; + guint32 requestor; + guint32 time; +}; + +/* This event type will be used pretty rarely. It only is important + for XInput aware programs that are drawing their own cursor */ + +struct _GdkEventProximity +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + GdkInputSource source; + guint32 deviceid; +}; + +struct _GdkEventDragRequest +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint sendreply:1; + guint willaccept:1; + guint delete_data:1; /* Do *not* delete if link is sent, only + if data is sent */ + guint senddata:1; + guint reserved:22; + } flags; + glong allflags; + } u; + guint8 isdrop; /* This gdk event can be generated by a couple of + X events - this lets the app know whether the + drop really occurred or we just set the data */ + + GdkPoint drop_coords; + gchar *data_type; + guint32 timestamp; +}; + +struct _GdkEventDragBegin +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + union { + struct { + guint protocol_version:4; + guint reserved:28; + } flags; + glong allflags; + } u; +}; + +struct _GdkEventDropEnter +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint sendreply:1; + guint extended_typelist:1; + guint reserved:26; + } flags; + glong allflags; + } u; +}; + +struct _GdkEventDropLeave +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint reserved:28; + } flags; + glong allflags; + } u; +}; + +struct _GdkEventDropDataAvailable +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint isdrop:1; + guint reserved:25; + } flags; + glong allflags; + } u; + gchar *data_type; /* MIME type */ + gulong data_numbytes; + gpointer data; + guint32 timestamp; + GdkPoint coords; +}; + +struct _GdkEventClient +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkAtom message_type; + gushort data_format; + union { + char b[20]; + short s[10]; + long l[5]; + } data; +}; + +struct _GdkEventOther +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkXEvent *xevent; +}; + + Code Examples @@ -11682,10 +12952,12 @@ Below are the code examples that are used in the above text which are not included in complete form elsewhere. - Scribble +Tictactoe + +tictactoe.h

-/* example-start scribble-simple scribble-simple.c */ +/* example-start tictactoe tictactoe.h */ /* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald @@ -11705,165 +12977,267 @@ which are not included in complete form elsewhere. * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ +#ifndef __TICTACTOE_H__ +#define __TICTACTOE_H__ -#include -/* Backing pixmap for drawing area */ -static GdkPixmap *pixmap = NULL; +#include +#include -/* Create a new backing pixmap of the appropriate size */ -static gint -configure_event (GtkWidget *widget, GdkEventConfigure *event) -{ - if (pixmap) - gdk_pixmap_unref(pixmap); - pixmap = gdk_pixmap_new(widget->window, - widget->allocation.width, - widget->allocation.height, - -1); - gdk_draw_rectangle (pixmap, - widget->style->white_gc, - TRUE, - 0, 0, - widget->allocation.width, - widget->allocation.height); +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ - return TRUE; -} +#define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe) +#define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass) +#define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ()) -/* Redraw the screen from the backing pixmap */ -static gint -expose_event (GtkWidget *widget, GdkEventExpose *event) + +typedef struct _Tictactoe Tictactoe; +typedef struct _TictactoeClass TictactoeClass; + +struct _Tictactoe { - gdk_draw_pixmap(widget->window, - widget->style->fg_gc[GTK_WIDGET_STATE (widget)], - pixmap, - event->area.x, event->area.y, - event->area.x, event->area.y, - event->area.width, event->area.height); - - return FALSE; -} + GtkVBox vbox; + + GtkWidget *buttons[3][3]; +}; -/* Draw a rectangle on the screen */ -static void -draw_brush (GtkWidget *widget, gdouble x, gdouble y) +struct _TictactoeClass { - GdkRectangle update_rect; + GtkVBoxClass parent_class; - update_rect.x = x - 5; - update_rect.y = y - 5; - update_rect.width = 10; - update_rect.height = 10; - gdk_draw_rectangle (pixmap, - widget->style->black_gc, - TRUE, - update_rect.x, update_rect.y, - update_rect.width, update_rect.height); - gtk_widget_draw (widget, &update_rect); -} + void (* tictactoe) (Tictactoe *ttt); +}; -static gint -button_press_event (GtkWidget *widget, GdkEventButton *event) -{ - if (event->button == 1 && pixmap != NULL) - draw_brush (widget, event->x, event->y); +guint tictactoe_get_type (void); +GtkWidget* tictactoe_new (void); +void tictactoe_clear (Tictactoe *ttt); - return TRUE; +#ifdef __cplusplus } +#endif /* __cplusplus */ -static gint -motion_notify_event (GtkWidget *widget, GdkEventMotion *event) +#endif /* __TICTACTOE_H__ */ + +/* example-end */ + + + +tictactoe.c +

+ +/* example-start tictactoe tictactoe.c */ + +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include "gtk/gtksignal.h" +#include "gtk/gtktable.h" +#include "gtk/gtktogglebutton.h" +#include "tictactoe.h" + +enum { + TICTACTOE_SIGNAL, + LAST_SIGNAL +}; + +static void tictactoe_class_init (TictactoeClass *klass); +static void tictactoe_init (Tictactoe *ttt); +static void tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt); + +static gint tictactoe_signals[LAST_SIGNAL] = { 0 }; + +guint +tictactoe_get_type () { - int x, y; - GdkModifierType state; + static guint ttt_type = 0; - if (event->is_hint) - gdk_window_get_pointer (event->window, &x, &y, &state); - else + if (!ttt_type) { - x = event->x; - y = event->y; - state = event->state; + GtkTypeInfo ttt_info = + { + "Tictactoe", + sizeof (Tictactoe), + sizeof (TictactoeClass), + (GtkClassInitFunc) tictactoe_class_init, + (GtkObjectInitFunc) tictactoe_init, + (GtkArgSetFunc) NULL, + (GtkArgGetFunc) NULL + }; + + ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info); } - - if (state & GDK_BUTTON1_MASK && pixmap != NULL) - draw_brush (widget, x, y); + + return ttt_type; +} + +static void +tictactoe_class_init (TictactoeClass *class) +{ + GtkObjectClass *object_class; + + object_class = (GtkObjectClass*) class; - return TRUE; + tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe), + gtk_signal_default_marshaller, GTK_TYPE_NONE, 0); + + + gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL); + + class->tictactoe = NULL; } -void -quit () +static void +tictactoe_init (Tictactoe *ttt) { - gtk_exit (0); + GtkWidget *table; + gint i,j; + + table = gtk_table_new (3, 3, TRUE); + gtk_container_add (GTK_CONTAINER(ttt), table); + gtk_widget_show (table); + + for (i=0;i<3; i++) + for (j=0;j<3; j++) + { + ttt->buttons[i][j] = gtk_toggle_button_new (); + gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j], + i, i+1, j, j+1); + gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled", + GTK_SIGNAL_FUNC (tictactoe_toggle), ttt); + gtk_widget_set_usize (ttt->buttons[i][j], 20, 20); + gtk_widget_show (ttt->buttons[i][j]); + } } -int -main (int argc, char *argv[]) +GtkWidget* +tictactoe_new () { - GtkWidget *window; - GtkWidget *drawing_area; - GtkWidget *vbox; + return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ())); +} - GtkWidget *button; +void +tictactoe_clear (Tictactoe *ttt) +{ + int i,j; - gtk_init (&argc, &argv); + for (i=0;i<3;i++) + for (j=0;j<3;j++) + { + gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]), + FALSE); + gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt); + } +} - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_widget_set_name (window, "Test Input"); +static void +tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt) +{ + int i,k; - vbox = gtk_vbox_new (FALSE, 0); - gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_widget_show (vbox); + static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 }, + { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 }, + { 0, 1, 2 }, { 0, 1, 2 } }; + static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 }, + { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 }, + { 0, 1, 2 }, { 2, 1, 0 } }; - gtk_signal_connect (GTK_OBJECT (window), "destroy", - GTK_SIGNAL_FUNC (quit), NULL); + int success, found; - /* Create the drawing area */ + for (k=0; k<8; k++) + { + success = TRUE; + found = FALSE; - drawing_area = gtk_drawing_area_new (); - gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200); - gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0); + for (i=0;i<3;i++) + { + success = success && + GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active; + found = found || + ttt->buttons[rwins[k][i]][cwins[k][i]] == widget; + } + + if (success && found) + { + gtk_signal_emit (GTK_OBJECT (ttt), + tictactoe_signals[TICTACTOE_SIGNAL]); + break; + } + } +} - gtk_widget_show (drawing_area); +/* example-end */ + - /* Signals used to handle backing pixmap */ + +ttt_test.c +

+ +/* example-start tictactoe ttt_test.c */ - gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event", - (GtkSignalFunc) expose_event, NULL); - gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event", - (GtkSignalFunc) configure_event, NULL); +#include +#include "tictactoe.h" - /* Event signals */ +void +win (GtkWidget *widget, gpointer data) +{ + g_print ("Yay!\n"); + tictactoe_clear (TICTACTOE (widget)); +} - gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event", - (GtkSignalFunc) motion_notify_event, NULL); - gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event", - (GtkSignalFunc) button_press_event, NULL); +int +main (int argc, char *argv[]) +{ + GtkWidget *window; + GtkWidget *ttt; + + gtk_init (&argc, &argv); - gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK - | GDK_LEAVE_NOTIFY_MASK - | GDK_BUTTON_PRESS_MASK - | GDK_POINTER_MOTION_MASK - | GDK_POINTER_MOTION_HINT_MASK); + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame"); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (gtk_exit), NULL); + + gtk_container_border_width (GTK_CONTAINER (window), 10); - /* .. And a quit button */ - button = gtk_button_new_with_label ("Quit"); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + ttt = tictactoe_new (); + + gtk_container_add (GTK_CONTAINER (window), ttt); + gtk_widget_show (ttt); - gtk_signal_connect_object (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (gtk_widget_destroy), - GTK_OBJECT (window)); - gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe", + GTK_SIGNAL_FUNC (win), NULL); gtk_widget_show (window); - + gtk_main (); - + return 0; } + /* example-end */ @@ -12565,4 +13939,191 @@ gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment, } /* example-end */ + + + Scribble +

+ +/* example-start scribble-simple scribble-simple.c */ + +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +/* Backing pixmap for drawing area */ +static GdkPixmap *pixmap = NULL; + +/* Create a new backing pixmap of the appropriate size */ +static gint +configure_event (GtkWidget *widget, GdkEventConfigure *event) +{ + if (pixmap) + gdk_pixmap_unref(pixmap); + + pixmap = gdk_pixmap_new(widget->window, + widget->allocation.width, + widget->allocation.height, + -1); + gdk_draw_rectangle (pixmap, + widget->style->white_gc, + TRUE, + 0, 0, + widget->allocation.width, + widget->allocation.height); + + return TRUE; +} + +/* Redraw the screen from the backing pixmap */ +static gint +expose_event (GtkWidget *widget, GdkEventExpose *event) +{ + gdk_draw_pixmap(widget->window, + widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + pixmap, + event->area.x, event->area.y, + event->area.x, event->area.y, + event->area.width, event->area.height); + + return FALSE; +} + +/* Draw a rectangle on the screen */ +static void +draw_brush (GtkWidget *widget, gdouble x, gdouble y) +{ + GdkRectangle update_rect; + + update_rect.x = x - 5; + update_rect.y = y - 5; + update_rect.width = 10; + update_rect.height = 10; + gdk_draw_rectangle (pixmap, + widget->style->black_gc, + TRUE, + update_rect.x, update_rect.y, + update_rect.width, update_rect.height); + gtk_widget_draw (widget, &update_rect); +} + +static gint +button_press_event (GtkWidget *widget, GdkEventButton *event) +{ + if (event->button == 1 && pixmap != NULL) + draw_brush (widget, event->x, event->y); + + return TRUE; +} + +static gint +motion_notify_event (GtkWidget *widget, GdkEventMotion *event) +{ + int x, y; + GdkModifierType state; + + if (event->is_hint) + gdk_window_get_pointer (event->window, &x, &y, &state); + else + { + x = event->x; + y = event->y; + state = event->state; + } + + if (state & GDK_BUTTON1_MASK && pixmap != NULL) + draw_brush (widget, x, y); + + return TRUE; +} + +void +quit () +{ + gtk_exit (0); +} + +int +main (int argc, char *argv[]) +{ + GtkWidget *window; + GtkWidget *drawing_area; + GtkWidget *vbox; + + GtkWidget *button; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_name (window, "Test Input"); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (quit), NULL); + + /* Create the drawing area */ + + drawing_area = gtk_drawing_area_new (); + gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200); + gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0); + + gtk_widget_show (drawing_area); + + /* Signals used to handle backing pixmap */ + + gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event", + (GtkSignalFunc) expose_event, NULL); + gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event", + (GtkSignalFunc) configure_event, NULL); + + /* Event signals */ + + gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event", + (GtkSignalFunc) motion_notify_event, NULL); + gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event", + (GtkSignalFunc) button_press_event, NULL); + + gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK + | GDK_LEAVE_NOTIFY_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK); + + /* .. And a quit button */ + button = gtk_button_new_with_label ("Quit"); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + GTK_OBJECT (window)); + gtk_widget_show (button); + + gtk_widget_show (window); + + gtk_main (); + + return 0; +} +/* example-end */ + + diff --git a/examples/menu/menufactory.c b/examples/menu/menufactory.c index 9f72e1e9250af4d260a21cd4e104982dc5756d9b..a7f781959419f0a5d82582c392c20c509f4230e2 100644 --- a/examples/menu/menufactory.c +++ b/examples/menu/menufactory.c @@ -1,17 +1,11 @@ -/* This file extracted from the GTK tutorial. */ - -/* menufactory.c */ +/* example-start menu menufactory.c */ #include #include #include "mfmain.h" - -static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path); -static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path); -void menus_init(void); -void menus_create(GtkMenuEntry * entries, int nmenu_entries); +static void print_hello(GtkWidget *widget, gpointer data); /* this is the GtkMenuEntry structure used to create new menus. The @@ -24,128 +18,37 @@ void menus_create(GtkMenuEntry * entries, int nmenu_entries); static GtkMenuEntry menu_items[] = { - {"

/File/New", "N", NULL, NULL}, - {"
/File/Open", "O", NULL, NULL}, - {"
/File/Save", "S", NULL, NULL}, - {"
/File/Save as", NULL, NULL, NULL}, - {"
/File/", NULL, NULL, NULL}, - {"
/File/Quit", "Q", file_quit_cmd_callback, "OK, I'll quit"}, - {"
/Options/Test", NULL, NULL, NULL} + {"
/File/New", "N", print_hello, NULL}, + {"
/File/Open", "O", print_hello, NULL}, + {"
/File/Save", "S", print_hello, NULL}, + {"
/File/Save as", NULL, NULL, NULL}, + {"
/File/", NULL, NULL, NULL}, + {"
/File/Quit", "Q", file_quit_cmd_callback, "OK, I'll quit"}, + {"
/Options/Test", NULL, NULL, NULL} }; -/* calculate the number of menu_item's */ -static int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]); -static int initialize = TRUE; -static GtkMenuFactory *factory = NULL; -static GtkMenuFactory *subfactory[1]; -static GHashTable *entry_ht = NULL; - -void get_main_menu(GtkWidget ** menubar, GtkAcceleratorTable ** table) +static void +print_hello(GtkWidget *widget, gpointer data) { - if (initialize) - menus_init(); - - if (menubar) - *menubar = subfactory[0]->widget; - if (table) - *table = subfactory[0]->table; + printf("hello!\n"); } -void menus_init(void) +void get_main_menu(GtkWidget *window, GtkWidget ** menubar) { - if (initialize) { - initialize = FALSE; - - factory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR); - subfactory[0] = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR); - - gtk_menu_factory_add_subfactory(factory, subfactory[0], "
"); - menus_create(menu_items, nmenu_items); - } -} + int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]); + GtkMenuFactory *factory; + GtkMenuFactory *subfactory; -void menus_create(GtkMenuEntry * entries, int nmenu_entries) -{ - char *accelerator; - int i; - - if (initialize) - menus_init(); - - if (entry_ht) - for (i = 0; i < nmenu_entries; i++) { - accelerator = g_hash_table_lookup(entry_ht, entries[i].path); - if (accelerator) { - if (accelerator[0] == '\0') - entries[i].accelerator = NULL; - else - entries[i].accelerator = accelerator; - } - } - gtk_menu_factory_add_entries(factory, entries, nmenu_entries); - - for (i = 0; i < nmenu_entries; i++) - if (entries[i].widget) { - gtk_signal_connect(GTK_OBJECT(entries[i].widget), "install_accelerator", - (GtkSignalFunc) menus_install_accel, - entries[i].path); - gtk_signal_connect(GTK_OBJECT(entries[i].widget), "remove_accelerator", - (GtkSignalFunc) menus_remove_accel, - entries[i].path); - } -} + factory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR); + subfactory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR); -static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path) -{ - char accel[64]; - char *t1, t2[2]; - - accel[0] = '\0'; - if (modifiers & GDK_CONTROL_MASK) - strcat(accel, ""); - if (modifiers & GDK_SHIFT_MASK) - strcat(accel, ""); - if (modifiers & GDK_MOD1_MASK) - strcat(accel, ""); + gtk_menu_factory_add_subfactory(factory, subfactory, "
"); + gtk_menu_factory_add_entries(factory, menu_items, nmenu_items); + gtk_window_add_accelerator_table(GTK_WINDOW(window), subfactory->table); - t2[0] = key; - t2[1] = '\0'; - strcat(accel, t2); - - if (entry_ht) { - t1 = g_hash_table_lookup(entry_ht, path); - g_free(t1); - } else - entry_ht = g_hash_table_new(g_str_hash, g_str_equal); - - g_hash_table_insert(entry_ht, path, g_strdup(accel)); - - return TRUE; -} - -static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path) -{ - char *t; - - if (entry_ht) { - t = g_hash_table_lookup(entry_ht, path); - g_free(t); - - g_hash_table_insert(entry_ht, path, g_strdup("")); - } + if (menubar) + *menubar = subfactory->widget; } -void menus_set_sensitive(char *path, int sensitive) -{ - GtkMenuPath *menu_path; - - if (initialize) - menus_init(); - - menu_path = gtk_menu_factory_find(factory, path); - if (menu_path) - gtk_widget_set_sensitive(menu_path->widget, sensitive); - else - g_warning("Unable to set sensitivity for menu which doesn't exist: %s", path); -} +/* example-end */ diff --git a/examples/menu/menufactory.h b/examples/menu/menufactory.h index e1569dae4c7de3751fa158bb2dab6d3eb04ed45a..acd04684e896dee47fc1a885598b38ee5c934b5e 100644 --- a/examples/menu/menufactory.h +++ b/examples/menu/menufactory.h @@ -1,6 +1,4 @@ -/* This file extracted from the GTK tutorial. */ - -/* menufactory.h */ +/* example-start menu menufactory.h */ #ifndef __MENUFACTORY_H__ #define __MENUFACTORY_H__ @@ -9,11 +7,12 @@ extern "C" { #endif /* __cplusplus */ -void get_main_menu (GtkWidget **menubar, GtkAcceleratorTable **table); -void menus_create(GtkMenuEntry *entries, int nmenu_entries); +void get_main_menu (GtkWidget *, GtkWidget **menubar); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __MENUFACTORY_H__ */ + +/* example-end */ diff --git a/examples/menu/mfmain.c b/examples/menu/mfmain.c index cbe0c58408e65e949a453236ec8974276ecedb20..5777632ee98db5e0c120972076984be4c610a6b4 100644 --- a/examples/menu/mfmain.c +++ b/examples/menu/mfmain.c @@ -1,21 +1,16 @@ -/* This file extracted from the GTK tutorial. */ - -/* mfmain.c */ +/* example-start menu mfmain.c */ #include #include "mfmain.h" #include "menufactory.h" - int main(int argc, char *argv[]) { GtkWidget *window; GtkWidget *main_vbox; GtkWidget *menubar; - GtkAcceleratorTable *accel; - gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); @@ -30,8 +25,7 @@ int main(int argc, char *argv[]) gtk_container_add(GTK_CONTAINER(window), main_vbox); gtk_widget_show(main_vbox); - get_main_menu(&menubar, &accel); - gtk_window_add_accelerator_table(GTK_WINDOW(window), accel); + get_main_menu(window, &menubar); gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0); gtk_widget_show(menubar); @@ -50,3 +44,5 @@ void file_quit_cmd_callback (GtkWidget *widget, gpointer data) g_print ("%s\n", (char *) data); gtk_exit(0); } + +/* example-end */ diff --git a/examples/menu/mfmain.h b/examples/menu/mfmain.h index fe481b0c1fd657d0fc110602111d3928e6fc0bf1..83fc0e3a480d877acbbd5583f1e355ff4e1c5142 100644 --- a/examples/menu/mfmain.h +++ b/examples/menu/mfmain.h @@ -1,6 +1,4 @@ -/* This file extracted from the GTK tutorial. */ - -/* mfmain.h */ +/* example-start menu mfmain.h */ #ifndef __MFMAIN_H__ #define __MFMAIN_H__ @@ -17,3 +15,5 @@ void file_quit_cmd_callback(GtkWidget *widget, gpointer data); #endif /* __cplusplus */ #endif /* __MFMAIN_H__ */ + +/* example-end */ diff --git a/examples/rangewidgets/Makefile b/examples/rangewidgets/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1259faef4587bf52ba8081b50da0b3908c9260c9 --- /dev/null +++ b/examples/rangewidgets/Makefile @@ -0,0 +1,8 @@ + +CC = gcc + +rangewidgets: rangewidgets.c + $(CC) `gtk-config --cflags` `gtk-config --libs` rangewidgets.c -o rangewidgets + +clean: + rm -f *.o rangewidgets diff --git a/examples/rangewidgets/rangewidgets.c b/examples/rangewidgets/rangewidgets.c new file mode 100644 index 0000000000000000000000000000000000000000..d59c8b27371c7d9c57717b0017aeb18c265b2405 --- /dev/null +++ b/examples/rangewidgets/rangewidgets.c @@ -0,0 +1,287 @@ +/* example-start rangewidgets rangewidgets.c */ + +#include + +GtkWidget *hscale, *vscale; + +void cb_pos_menu_select (GtkWidget *item, GtkPositionType pos) +{ + /* set the value position on both scale widgets */ + gtk_scale_set_value_pos (GTK_SCALE (hscale), pos); + gtk_scale_set_value_pos (GTK_SCALE (vscale), pos); +} + +void cb_update_menu_select (GtkWidget *item, GtkUpdateType policy) +{ + /* set the update policy for both scale widgets */ + gtk_range_set_update_policy (GTK_RANGE (hscale), policy); + gtk_range_set_update_policy (GTK_RANGE (vscale), policy); +} + +void cb_digits_scale (GtkAdjustment *adj) +{ + /* set the number of decimal places to which adj->vaule is rounded + */ + gtk_scale_set_digits (GTK_SCALE (hscale), (gint) adj->value); + gtk_scale_set_digits (GTK_SCALE (vscale), (gint) adj->value); +} + +void cb_page_size (GtkAdjustment *get, GtkAdjustment *set) +{ + /* set the page size and page increment size of the sample + adjustment to the value specified by the "Page Size" scale */ + set->page_size = get->value; + set->page_increment = get->value; + /* now emit the "changed" signal to reconfigure all the widgets that + are attached to this adjustment */ + gtk_signal_emit_by_name (GTK_OBJECT (set), "changed"); +} + +void cb_draw_value (GtkToggleButton *button) +{ + /* turn the value display on the scale widgets off or on depending + on the state of the checkbutton */ + gtk_scale_set_draw_value (GTK_SCALE (hscale), button->active); + gtk_scale_set_draw_value (GTK_SCALE (vscale), button->active); +} + +/* convenience functions */ + +GtkWidget *make_menu_item (gchar *name, GtkSignalFunc callback, + gpointer data) +{ + GtkWidget *item; + + item = gtk_menu_item_new_with_label (name); + gtk_signal_connect (GTK_OBJECT (item), "activate", + callback, data); + gtk_widget_show (item); + + return item; +} + +void scale_set_default_values (GtkScale *scale) +{ + gtk_range_set_update_policy (GTK_RANGE (scale), + GTK_UPDATE_CONTINUOUS); + gtk_scale_set_digits (scale, 1); + gtk_scale_set_value_pos (scale, GTK_POS_TOP); + gtk_scale_set_draw_value (scale, TRUE); +} + +/* makes the sample window */ + +void create_range_controls (void) +{ + GtkWidget *window; + GtkWidget *box1, *box2, *box3; + GtkWidget *button; + GtkWidget *scrollbar; + GtkWidget *separator; + GtkWidget *opt, *menu, *item; + GtkWidget *label; + GtkWidget *scale; + GtkObject *adj1, *adj2; + + /* standard window-creating stuff */ + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC(gtk_main_quit), + NULL); + gtk_window_set_title (GTK_WINDOW (window), "range controls"); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + /* value, lower, upper, step_increment, page_increment, page_size */ + /* note that the page_size value only makes a difference for + scrollbar widgets, and the highest value you'll get is actually + (upper - page_size). */ + adj1 = gtk_adjustment_new (0.0, 0.0, 101.0, 0.1, 1.0, 1.0); + + vscale = gtk_vscale_new (GTK_ADJUSTMENT (adj1)); + scale_set_default_values (GTK_SCALE (vscale)); + gtk_box_pack_start (GTK_BOX (box2), vscale, TRUE, TRUE, 0); + gtk_widget_show (vscale); + + box3 = gtk_vbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (box2), box3, TRUE, TRUE, 0); + gtk_widget_show (box3); + + /* reuse the same adjustment */ + hscale = gtk_hscale_new (GTK_ADJUSTMENT (adj1)); + gtk_widget_set_usize (GTK_WIDGET (hscale), 200, 30); + scale_set_default_values (GTK_SCALE (hscale)); + gtk_box_pack_start (GTK_BOX (box3), hscale, TRUE, TRUE, 0); + gtk_widget_show (hscale); + + /* reuse the same adjustment again */ + scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adj1)); + /* notice how this causes the scales to always be updated + continuously when the scrollbar is moved */ + gtk_range_set_update_policy (GTK_RANGE (scrollbar), + GTK_UPDATE_CONTINUOUS); + gtk_box_pack_start (GTK_BOX (box3), scrollbar, TRUE, TRUE, 0); + gtk_widget_show (scrollbar); + + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + /* a checkbutton to control whether the value is displayed or not */ + button = gtk_check_button_new_with_label + ("Display value on scale widgets"); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE); + gtk_signal_connect (GTK_OBJECT (button), "toggled", GTK_SIGNAL_FUNC + (cb_draw_value), NULL); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + + /* an option menu to change the position of the value */ + label = gtk_label_new ("Scale Value Position:"); + gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + opt = gtk_option_menu_new(); + menu = gtk_menu_new(); + + item = make_menu_item ("Top", GTK_SIGNAL_FUNC (cb_pos_menu_select), + GINT_TO_POINTER (GTK_POS_TOP)); + gtk_menu_append (GTK_MENU (menu), item); + + item = make_menu_item ("Bottom", GTK_SIGNAL_FUNC (cb_pos_menu_select), + GINT_TO_POINTER (GTK_POS_BOTTOM)); + gtk_menu_append (GTK_MENU (menu), item); + + item = make_menu_item ("Left", GTK_SIGNAL_FUNC (cb_pos_menu_select), + GINT_TO_POINTER (GTK_POS_LEFT)); + gtk_menu_append (GTK_MENU (menu), item); + + item = make_menu_item ("Right", GTK_SIGNAL_FUNC (cb_pos_menu_select), + GINT_TO_POINTER (GTK_POS_RIGHT)); + gtk_menu_append (GTK_MENU (menu), item); + + gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu); + gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0); + gtk_widget_show (opt); + + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + + /* yet another option menu, this time for the update policy of the + scale widgets */ + label = gtk_label_new ("Scale Update Policy:"); + gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + opt = gtk_option_menu_new(); + menu = gtk_menu_new(); + + item = make_menu_item ("Continuous", + GTK_SIGNAL_FUNC (cb_update_menu_select), + GINT_TO_POINTER (GTK_UPDATE_CONTINUOUS)); + gtk_menu_append (GTK_MENU (menu), item); + + item = make_menu_item ("Discontinuous", + GTK_SIGNAL_FUNC (cb_update_menu_select), + GINT_TO_POINTER (GTK_UPDATE_DISCONTINUOUS)); + gtk_menu_append (GTK_MENU (menu), item); + + item = make_menu_item ("Delayed", + GTK_SIGNAL_FUNC (cb_update_menu_select), + GINT_TO_POINTER (GTK_UPDATE_DELAYED)); + gtk_menu_append (GTK_MENU (menu), item); + + gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu); + gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0); + gtk_widget_show (opt); + + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + + /* a GtkHScale widget for adjusting the number of digits on the + sample scales. */ + label = gtk_label_new ("Scale Digits:"); + gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + adj2 = gtk_adjustment_new (1.0, 0.0, 5.0, 1.0, 1.0, 0.0); + gtk_signal_connect (GTK_OBJECT (adj2), "value_changed", + GTK_SIGNAL_FUNC (cb_digits_scale), NULL); + scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2)); + gtk_scale_set_digits (GTK_SCALE (scale), 0); + gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0); + gtk_widget_show (scale); + + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + + /* And, one last GtkHScale widget for adjusting the page size of the + scrollbar. */ + label = gtk_label_new ("Scrollbar Page Size:"); + gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + adj2 = gtk_adjustment_new (1.0, 1.0, 101.0, 1.0, 1.0, 0.0); + gtk_signal_connect (GTK_OBJECT (adj2), "value_changed", + GTK_SIGNAL_FUNC (cb_page_size), adj1); + scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2)); + gtk_scale_set_digits (GTK_SCALE (scale), 0); + gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0); + gtk_widget_show (scale); + + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + button = gtk_button_new_with_label ("Quit"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC(gtk_main_quit), + NULL); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + gtk_widget_show (window); +} + +int main (int argc, char *argv[]) +{ + gtk_init(&argc, &argv); + + create_range_controls(); + + gtk_main(); + + return 0; +} + +/* example-end */