diff options
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | ChangeLog.pre-2-0 | 11 | ||||
-rw-r--r-- | ChangeLog.pre-2-10 | 11 | ||||
-rw-r--r-- | ChangeLog.pre-2-2 | 11 | ||||
-rw-r--r-- | ChangeLog.pre-2-4 | 11 | ||||
-rw-r--r-- | ChangeLog.pre-2-6 | 11 | ||||
-rw-r--r-- | ChangeLog.pre-2-8 | 11 | ||||
-rw-r--r-- | Makefile.am | 34 | ||||
-rw-r--r-- | docs/gtk_tut.sgml | 752 | ||||
-rw-r--r-- | docs/tutorial/gtk_tut.sgml | 752 |
10 files changed, 1204 insertions, 411 deletions
@@ -1,3 +1,14 @@ +Mon Feb 8 12:50:06 GMT 1999 Tony Gale <gale@gtk.org> + + * docs/gtk_tut.sgml: + - Heavily edited GtkCombo section initially from + Christopher T. Lansdown <lansdoct@screech.cs.alfred.edu>. + + - Cleanups and some glib stuff from + David Wheeler <wheeler@ida.org> + + * Makefile.am: update to include the latest Tutorial examples. + Sat Feb 6 11:20:16 1999 Owen Taylor <otaylor@redhat.com> * gtk/gtkwidget.c (gtk_widget_idle_draw): Add the diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index a501d41b8..ecea45557 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,14 @@ +Mon Feb 8 12:50:06 GMT 1999 Tony Gale <gale@gtk.org> + + * docs/gtk_tut.sgml: + - Heavily edited GtkCombo section initially from + Christopher T. Lansdown <lansdoct@screech.cs.alfred.edu>. + + - Cleanups and some glib stuff from + David Wheeler <wheeler@ida.org> + + * Makefile.am: update to include the latest Tutorial examples. + Sat Feb 6 11:20:16 1999 Owen Taylor <otaylor@redhat.com> * gtk/gtkwidget.c (gtk_widget_idle_draw): Add the diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index a501d41b8..ecea45557 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,14 @@ +Mon Feb 8 12:50:06 GMT 1999 Tony Gale <gale@gtk.org> + + * docs/gtk_tut.sgml: + - Heavily edited GtkCombo section initially from + Christopher T. Lansdown <lansdoct@screech.cs.alfred.edu>. + + - Cleanups and some glib stuff from + David Wheeler <wheeler@ida.org> + + * Makefile.am: update to include the latest Tutorial examples. + Sat Feb 6 11:20:16 1999 Owen Taylor <otaylor@redhat.com> * gtk/gtkwidget.c (gtk_widget_idle_draw): Add the diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index a501d41b8..ecea45557 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,14 @@ +Mon Feb 8 12:50:06 GMT 1999 Tony Gale <gale@gtk.org> + + * docs/gtk_tut.sgml: + - Heavily edited GtkCombo section initially from + Christopher T. Lansdown <lansdoct@screech.cs.alfred.edu>. + + - Cleanups and some glib stuff from + David Wheeler <wheeler@ida.org> + + * Makefile.am: update to include the latest Tutorial examples. + Sat Feb 6 11:20:16 1999 Owen Taylor <otaylor@redhat.com> * gtk/gtkwidget.c (gtk_widget_idle_draw): Add the diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index a501d41b8..ecea45557 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,14 @@ +Mon Feb 8 12:50:06 GMT 1999 Tony Gale <gale@gtk.org> + + * docs/gtk_tut.sgml: + - Heavily edited GtkCombo section initially from + Christopher T. Lansdown <lansdoct@screech.cs.alfred.edu>. + + - Cleanups and some glib stuff from + David Wheeler <wheeler@ida.org> + + * Makefile.am: update to include the latest Tutorial examples. + Sat Feb 6 11:20:16 1999 Owen Taylor <otaylor@redhat.com> * gtk/gtkwidget.c (gtk_widget_idle_draw): Add the diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index a501d41b8..ecea45557 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,14 @@ +Mon Feb 8 12:50:06 GMT 1999 Tony Gale <gale@gtk.org> + + * docs/gtk_tut.sgml: + - Heavily edited GtkCombo section initially from + Christopher T. Lansdown <lansdoct@screech.cs.alfred.edu>. + + - Cleanups and some glib stuff from + David Wheeler <wheeler@ida.org> + + * Makefile.am: update to include the latest Tutorial examples. + Sat Feb 6 11:20:16 1999 Owen Taylor <otaylor@redhat.com> * gtk/gtkwidget.c (gtk_widget_idle_draw): Add the diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index a501d41b8..ecea45557 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,14 @@ +Mon Feb 8 12:50:06 GMT 1999 Tony Gale <gale@gtk.org> + + * docs/gtk_tut.sgml: + - Heavily edited GtkCombo section initially from + Christopher T. Lansdown <lansdoct@screech.cs.alfred.edu>. + + - Cleanups and some glib stuff from + David Wheeler <wheeler@ida.org> + + * Makefile.am: update to include the latest Tutorial examples. + Sat Feb 6 11:20:16 1999 Owen Taylor <otaylor@redhat.com> * gtk/gtkwidget.c (gtk_widget_idle_draw): Add the diff --git a/Makefile.am b/Makefile.am index 5e3bb3cee..af444c54e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,18 +16,21 @@ EXTRA_DIST = \ README.cvs-commits \ intl/libgettext.h \ intl/po2tbl.sed.in \ - examples/Makefile \ - examples/README.1ST \ - examples/extract.awk \ - examples/extract.sh \ examples/aspectframe/Makefile \ examples/aspectframe/aspectframe.c \ - examples/base/Makefile \ - examples/base/base.c \ + examples/Makefile \ + examples/README.1ST \ + examples/extract.awk \ + examples/extract.sh \ + examples/base/Makefile \ + examples/base/base.c \ examples/buttons/Makefile \ examples/buttons/buttons.c \ examples/buttons/info.xpm \ - examples/clist/clist.c \ + examples/calendar/Makefile \ + examples/calendar/gcalendar.c \ + examples/clist/Makefile \ + examples/clist/clist.c \ examples/entry/Makefile \ examples/entry/entry.c \ examples/eventbox/Makefile \ @@ -49,10 +52,10 @@ EXTRA_DIST = \ examples/menu/itemfactory.c \ examples/notebook/Makefile \ examples/notebook/notebook.c \ - examples/packer/Makefile \ - examples/packer/pack.c \ examples/packbox/Makefile \ examples/packbox/packbox.c \ + examples/packer/Makefile \ + examples/packer/pack.c \ examples/paned/Makefile \ examples/paned/paned.c \ examples/pixmap/Makefile \ @@ -61,6 +64,8 @@ EXTRA_DIST = \ examples/progressbar/progressbar.c \ examples/radiobuttons/Makefile \ examples/radiobuttons/radiobuttons.c \ + examples/rangewidgets/Makefile \ + examples/rangewidgets/rangewidgets.c \ examples/rulers/Makefile \ examples/rulers/rulers.c \ examples/scribble-simple/Makefile \ @@ -74,12 +79,23 @@ EXTRA_DIST = \ examples/statusbar/statusbar.c \ examples/table/Makefile \ examples/table/table.c \ + examples/text/Makefile \ + examples/text/text.c \ examples/tictactoe/Makefile \ examples/tictactoe/tictactoe.c \ examples/tictactoe/tictactoe.h \ examples/tictactoe/ttt_test.c \ + examples/tree/Makefile \ + examples/tree/tree.c \ examples/wheelbarrow/Makefile \ examples/wheelbarrow/wheelbarrow.c \ + examples/colorsel/colorsel.c \ + examples/fixed/fixed.c \ + examples/fixed/Makefile \ + examples/frame/frame.c \ + examples/frame/Makefile \ + examples/spinbutton/spinbutton.c \ + examples/spinbutton/Makefile \ examples/find-examples.sh diff --git a/docs/gtk_tut.sgml b/docs/gtk_tut.sgml index efad9eb39..656334f65 100644 --- a/docs/gtk_tut.sgml +++ b/docs/gtk_tut.sgml @@ -5,24 +5,41 @@ --> <article> -<title>GTK v1.1 Tutorial +<title>GTK v1.2 Tutorial <author> Tony Gale <tt><htmlurl url="mailto:gale@gtk.org" name="<gale@gtk.org>"></tt> Ian Main <tt><htmlurl url="mailto:imain@gtk.org" name="<imain@gtk.org>"></tt>, -<date>February 1st, 1999 +<date>February 7th, 1999 +<abstract> +This is a tutorial on how to use GTK (the GIMP Toolkit) through its C +interface. +</abstract> + +<!-- Table of contents --> +<!-- Older versions of this tutorial did not have a table of contents, + but the tutorial is now so large that having one is very useful. --> +<toc> + <!-- ***************************************************************** --> <sect>Introduction <!-- ***************************************************************** --> <p> -GTK (GIMP Toolkit) was originally developed as a toolkit for the GIMP -(General Image Manipulation Program). GTK is built on top of GDK -(GIMP Drawing Kit) which is basically a wrapper around the Xlib -functions. It's called the GIMP toolkit because it was originally -written for developing the GIMP, but has now been used in several free -software projects. The authors are: +GTK (GIMP Toolkit) is a library for creating graphical user +interfaces. It is licensed using the LGPL license, so you can develop +open software, free software, or even commercial non-free software +using GTK without having to spend anything for licenses or royalties. + +It's called the GIMP toolkit because it was originally written for +developing the General Image Manipulation Program (GIMP), but GTK has +now been used in a large number of software projects, including the +GNU Network Object Model Environment (GNOME) project. GTK is built on +top of GDK (GIMP Drawing Kit) which is basically a wrapper around the +low-level functions for accessing the underlying windowing functions +(Xlib in the case of X windows). The primary authors of GTK are: + <itemize> <item> Peter Mattis <tt><htmlurl url="mailto:petm@xcf.berkeley.edu" name="petm@xcf.berkeley.edu"></tt> @@ -45,18 +62,44 @@ implemented here are not available or are nonstandard on other unixes such as g_strerror(). Some also contain enhancements to the libc versions, such as g_malloc that has enhanced debugging utilities. -This tutorial is an attempt to document as much as possible of GTK, it -is by no means complete. This tutorial assumes a good understanding of -C, and how to create C programs. It would be a great benefit for the -reader to have previous X programming experience, but it shouldn't be -necessary. If you are learning GTK as your first widget set, please -comment on how you found this tutorial, and what you had trouble -with. Note that there is also a C++ API for GTK (GTK--) in the works, -so if you prefer to use C++, you should look into this -instead. There are also Objective C, ADA, Guile and other language -bindings available, but I don't follow these. - -This document is a 'work in progress'. Please look for updates on +This tutorial describes the C interface to GTK. There are GTK +bindings for many other languages including C++, Guile, Perl, Python, +TOM, Ada95, Objective C, Free Pascal, and Eiffel. If you intend to +use another language's bindings to GTK, look at that binding's +documentation first. In some cases that documentation may describe +some important conventions (which you should know first) and then +refer you back to this tutorial. There are also some cross-platform +APIs (such as wxWindows and V) which use GTK as one of their target +platforms; again, consult their documentation first. + +If you're developing your GTK application in C++, a few extra notes +are in order. There's a C++ binding to GTK called GTK--, which +provides a more C++-like interface to GTK; you should probably look +into this instead. If you don't like that approach for whatever +reason, there are two alternatives for using GTK. First, you can use +only the C subset of C++ when interfacing with GTK and then use the C +interface as described in this tutorial. Second, you can use GTK and +C++ together by declaring all callbacks as static functions in C++ +classes, and again calling GTK using its C interface. If you choose +this last approach, you can include as the callback's data value a +pointer to the object to be manipulated (the so-called "this" value). +Selecting between these options is simply a matter of preference, +since in all three approaches you get C++ and GTK. None of these +approaches requires the use of a specialized preprocessor, so no +matter what you choose you can use standard C++ with GTK. + +This tutorial is an attempt to document as much as possible of GTK, +but it is by no means complete. This tutorial assumes a good +understanding of C, and how to create C programs. It would be a great +benefit for the reader to have previous X programming experience, but +it shouldn't be necessary. If you are learning GTK as your first +widget set, please comment on how you found this tutorial, and what +you had trouble with. Note that there is also a C++ API for GTK +(GTK--) in the works, so if you prefer to use C++, you should look +into this instead. There are also Objective C, ADA, Guile and other +language bindings available, but I don't follow these. + +This document is a 'work in progress'. Please look for updates on http://www.gtk.org/ <htmlurl url="http://www.gtk.org/" name="http://www.gtk.org/">. @@ -1131,7 +1174,7 @@ int main( int argc, if (argc != 2) { fprintf (stderr, "usage: packbox num, where num is 1, 2, or 3.\n"); - /* this just does cleanup in GTK, and exits with an exit status of 1. */ + /* This just does cleanup in GTK and exits with an exit status of 1. */ gtk_exit (1); } @@ -1215,7 +1258,8 @@ int main( int argc, /* Another new separator. */ separator = gtk_hseparator_new (); - /* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */ + /* The last 3 arguments to gtk_box_pack_start are: + * expand, fill, padding. */ gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5); gtk_widget_show (separator); @@ -1241,7 +1285,8 @@ int main( int argc, gtk_widget_show (box2); separator = gtk_hseparator_new (); - /* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */ + /* The last 3 arguments to gtk_box_pack_start are: + * expand, fill, padding. */ gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5); gtk_widget_show (separator); @@ -1311,7 +1356,8 @@ int main( int argc, GTK_SIGNAL_FUNC (gtk_main_quit), GTK_OBJECT (window)); /* Pack the button into the quitbox. - * The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */ + * The last 3 arguments to gtk_box_pack_start are: + * expand, fill, padding. */ gtk_box_pack_start (GTK_BOX (quitbox), button, TRUE, FALSE, 0); /* pack the quitbox into the vbox (box1) */ gtk_box_pack_start (GTK_BOX (box1), quitbox, FALSE, FALSE, 0); @@ -2411,7 +2457,7 @@ which mouse button is used. As mentioned in <ref id="sec_Adjustment" name="Adjustments"> above, all range widgets are associated with an adjustment object, from which -they calculate the length of the slider and it's position within the +they calculate the length of the slider and its position within the trough. When the user manipulates the slider, the range widget will change the value of the adjustment. @@ -3392,9 +3438,9 @@ Progress bars are used to show the status of an operation. They are pretty easy to use, as you will see with the code below. But first lets start out with the calls to create a new progress bar. -There are two ways to create a progress bar, one simple one takes +There are two ways to create a progress bar, one simple that takes no arguments, and one that takes a GtkAdjustment object as an -argument. If the former is used, the progress bar creates it's own +argument. If the former is used, the progress bar creates its own adjustment object. <tscreen><verb> @@ -3418,8 +3464,8 @@ second argument is the amount 'completed', meaning the amount the progress bar has been filled from 0-100%. This is passed to the function as a real number ranging from 0 to 1. -GTK v1.1 has added new functionality to the progress bar that enables -it to display it's value in different ways, and to inform the user of +GTK v1.2 has added new functionality to the progress bar that enables +it to display its value in different ways, and to inform the user of its current value and its range. A progress bar may be set to one of a number of orientations using the @@ -3441,7 +3487,7 @@ values to indicate the direction in which the progress bar moves: </itemize> When used as a measure of how far a process has progressed, the -GtkProgressBar can be set to display it's value in either a continuous +GtkProgressBar can be set to display its value in either a continuous or discrete mode. In continuous mode, the progress bar is updated for each value. In discrete mode, the progress bar is updated in a number of discrete blocks. The number of blocks is also configurable. @@ -3491,7 +3537,7 @@ void gtk_progress_bar_set_activity_blocks( GtkProgressBar *pbar, </verb></tscreen> When in continuous mode, the progress bar can also display a -configurable text string within it's trough, using the following +configurable text string within its trough, using the following function. <tscreen><verb> @@ -3812,7 +3858,25 @@ vertical box. <p> Pixmaps are data structures that contain pictures. These pictures can be used in various places, but most visibly as icons on the X-Windows -desktop, or as cursors. A bitmap is a 2-color pixmap. +desktop, or as cursors. + +A pixmap which only has 2 colors is called a bitmap, and there are a +few additional routines for handling this common special case. + +To understand pixmaps, it would help to understand how X-windows +works. Under X-windows, applications do not need to be running on the +same computer that is interacting with the user. Instead, the various +applications, called "clients", all communicate with a program which +displays the graphics and handles the keyboard and mouse. This +program which interacts directly with the user is called a "display +server" or "X server." Since the communication might take place over +a network, it's important to keep some information with the X server. +Pixmaps, for example, are stored in the memory of the X server. This +means that once pixmap values are set, they don't need to keep getting +transmitted over the network; instead a command is sent to "display +pixmap number XYZ here." Even if you aren't using X-windows with GTK +currently, using constructs such as Pixmaps will make your programs +work acceptably under X-windows. To use pixmaps in GTK, we must first build a GdkPixmap structure using routines from the GDK layer. Pixmaps can either be created from @@ -3869,8 +3933,8 @@ GdkPixmap *gdk_pixmap_create_from_xpm_d( GdkWindow *window, </verb></tscreen> Small images can be incorporated into a program as data in the XPM -format. A pixmap is created using this data, instead of reading it -from a file. An example of such data is +format. A pixmap is created using this data, instead of reading it +from a file. An example of such data is <tscreen><verb> /* XPM */ @@ -4349,28 +4413,33 @@ int main( int argc, char *argv[] ) { gtk_drawing_area_size( (GtkDrawingArea *)area, XSIZE, YSIZE ); gtk_table_attach( GTK_TABLE(table), area, 1, 2, 1, 2, GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0 ); - gtk_widget_set_events( area, GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK ); + gtk_widget_set_events( area, GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK ); - /* The horizontal ruler goes on top. As the mouse moves across the drawing area, - * a motion_notify_event is passed to the appropriate event handler for the ruler. */ + /* The horizontal ruler goes on top. As the mouse moves across the + * drawing area, a motion_notify_event is passed to the + * appropriate event handler for the ruler. */ hrule = gtk_hruler_new(); gtk_ruler_set_metric( GTK_RULER(hrule), GTK_PIXELS ); gtk_ruler_set_range( GTK_RULER(hrule), 7, 13, 0, 20 ); gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event", - (GtkSignalFunc)EVENT_METHOD(hrule, motion_notify_event), + (GtkSignalFunc)EVENT_METHOD(hrule, + motion_notify_event), GTK_OBJECT(hrule) ); /* GTK_WIDGET_CLASS(GTK_OBJECT(hrule)->klass)->motion_notify_event, */ gtk_table_attach( GTK_TABLE(table), hrule, 1, 2, 0, 1, GTK_EXPAND|GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0 ); - /* The vertical ruler goes on the left. As the mouse moves across the drawing area, - * a motion_notify_event is passed to the appropriate event handler for the ruler. */ + /* The vertical ruler goes on the left. As the mouse moves across + * the drawing area, a motion_notify_event is passed to the + * appropriate event handler for the ruler. */ vrule = gtk_vruler_new(); gtk_ruler_set_metric( GTK_RULER(vrule), GTK_PIXELS ); gtk_ruler_set_range( GTK_RULER(vrule), 0, YSIZE, 10, YSIZE ); gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event", (GtkSignalFunc) - GTK_WIDGET_CLASS(GTK_OBJECT(vrule)->klass)->motion_notify_event, + GTK_WIDGET_CLASS(GTK_OBJECT(vrule)->klass)-> + motion_notify_event, GTK_OBJECT(vrule) ); gtk_table_attach( GTK_TABLE(table), vrule, 0, 1, 1, 2, GTK_FILL, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0 ); @@ -4494,7 +4563,8 @@ int main (int argc, char *argv[]) gtk_box_pack_start (GTK_BOX (vbox), status_bar, TRUE, TRUE, 0); gtk_widget_show (status_bar); - context_id = gtk_statusbar_get_context_id( GTK_STATUSBAR(status_bar), "Statusbar example"); + context_id = gtk_statusbar_get_context_id( + GTK_STATUSBAR(status_bar), "Statusbar example"); button = gtk_button_new_with_label("push item"); gtk_signal_connect(GTK_OBJECT(button), "clicked", @@ -4570,6 +4640,9 @@ following function. This is useful in the callback functions described below. gchar *gtk_entry_get_text( GtkEntry *entry ); </verb></tscreen> +The value returned by this function is used internally, and must not +be freed using either free() or g_free() + If we don't want the contents of the Entry to be changed by someone typing into it, we can change its editable state. @@ -4898,6 +4971,18 @@ void gtk_spin_button_set_update_policy( GtkSpinButton *spin_button, The possible values of <tt/policy/ are either GTK_UPDATE_ALWAYS or GTK_UPDATE_IF_VALID. +These policies affect the behavior of a Spin Button when parsing +inserted text and syncing it's value with the values of the +Adjustment. + +In the case of GTK_UPDATE_IF_VALID the Spin Button only value gets +changed if the text input is a numeric value that +is within the range specified by the Adjustment. Otherwise +the text is reset to the current value. + +In case of GTK_UPDATE_ALWAYS we ignore errors while converting text +into a numeric value. + The appearance of the buttons used in a Spin Button can be changed using the following function: @@ -5153,6 +5238,171 @@ int main( int argc, </verb></tscreen> <!-- ----------------------------------------------------------------- --> +<sect1>Combo Box +<p> +The combo box is another fairly simple widget that is really just a +collection of other widgets. From the users point of view, the widget +consists of a text entry box and a pull down menu from which the user +can select one of a set of predefined entries. Alternatively, the user +can type a different option directly into the text box. + +The following extract from the structure that defines a Combo Box +identifies several of the components: + +<tscreen><verb> +struct _GtkCombo { + GtkHBox hbox; + GtkWidget *entry; + GtkWidget *button; + GtkWidget *popup; + GtkWidget *popwin; + GtkWidget *list; + ... }; +</verb></tscreen> + +As you can see, the Combo Box has two principle parts that you really +care about: an entry and a list. + +First off, to create a combo box, use: + +<tscreen><verb> +GtkWidget *gtk_combo_new( void ); +</verb></tscreen> + +Now, if you want to set the string in the entry section of the combo +box, this is done by manipulating the <tt/entry/ widget directly: + +<tscreen><verb> + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), "My String."); +</verb></tscreen> + +To set the values in the popdown list, one uses the function: + +<tscreen><verb> +void gtk_combo_set_popdown_strings( GtkCombo *combo, + GList *strings ); +</verb></tscreen> + +Before you can do this, you have to assemble a GList of the strings +that you want. GList is a linked list implementation that is part of +<ref id="sec_glib" name="glib">, a library supporing GTK. For the +moment, the quick and dirty explanation is that you need to set up a +GList pointer, set it equal to NULL, then append strings to it with + +<tscreen><verb> +GList *g_list_append( GList *glist, + gpointer data ); +</verb></tscreen> + +It is important that you set the initial GList pointer to NULL. The +value returned from the g_list_append function must be used as the new +pointer to the GList. + +Here's a typical code segment for creating a set of options: + +<tscreen><verb> + GList *glist=NULL; + + glist = g_list_append(glist, "String 1"); + glist = g_list_append(glist, "String 2"); + glist = g_list_append(glist, "String 3"); + glist = g_list_append(glist, "String 4"); + + gtk_combo_set_popdown_strings( GTK_COMBO(combo), glist) ; +</verb></tscreen> + +At this point you have a working combo box that has been set up. +There are a few aspects of its behavior that you can change. These +are accomplished with the functions: + +<tscreen><verb> +void gtk_combo_set_use_arrows( GtkCombo *combo, + gint val ); + +void gtk_combo_set_use_arrows_always( GtkCombo *combo, + gint val ); + +void gtk_combo_set_case_sensitive( GtkCombo *combo, + gint val ); +</verb></tscreen> + +<tt/gtk_combo_set_use_arrows()/ lets the user change the value in the +entry using the up/down arrow keys. This doesn't bring up the list, but +rather replaces the current text in the entry with the next list entry +(up or down, as your key choice indicates). It does this by searching +in the list for the item corresponding to the current value in the +entry and selecting the previous/next item accordingly. Usually in an +entry the arrow keys are used to change focus (you can do that anyway +using TAB). Note that when the current item is the last of the list +and you press arrow-down it changes the focus (the same applies with +the first item and arrow-up). + +If the current value in the entry is not in the list, then the +function of <tt/gtk_combo_set_use_arrows()/ is disabled. + +<tt/gtk_combo_set_use_arrows_always()/ similarly allows the use the +the up/down arrow keys to cycle through the choices in the dropdown +list, except that it wraps around the values in the list, completely +disabling the use of the up and down arrow keys for changing focus. + +<tt/gtk_combo_set_case_sensitive()/ toggles whether or not GTK +searches for entries in a case sensitive manner. This is used when +the Combo widget is asked to find a value from the list using the +current entry in the text box. This completion can be performed in +eother a case sensitive or insensitive manner, depending upon the use +of this function. The Combo widget can also simply complete the +current entry if the user presses the key combination MOD-1 and +'Tab'. MOD-1 is often mapped to the 'Alt' key. Note, however that some +Window managers also use this key combination, which will override +it's use within GTK. + +Now that we have a combo box, tailored to look and act how we want it, +all that remains is being able to get data from the combo box. This is +relatively straight forward. The majority of the time, all you are +going to care about getting data from is the entry. The entry is +accessed simply by GTK_ENTRY(GTK_COMBO(combo)->entry). The two +principle things that you are going to want to do with it are attach +to the activate signal, which indicates that the user has pressed the +Return or Enter key,and read the text. The first is accomplished +using something like: + +<tscreen><verb> + gtk_signal_connect(GTK_OBJECT(GTK_COMB(combo)->entry), "activate", + GTK_SIGNAL_FUNC (my_callback_function), my_data); +</verb></tscreen> + +Getting the text at any arbitrary time is accomplished by simply using +the entry function: + +<tscreen><verb> +gchar *gtk_entry_get_text(GtkEntry *entry); +</verb></tscreen> + +Such as: + +<tscreen><verb> + char *string; + + string = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry)); +</verb></tscreen> + +That's about all there is to it. There is a function + +<tscreen><verb> +void gtk_combo_disable_activate(GtkCombo *combo); +</verb></tscreen> + +that will disable the activate signal on the entry widget in the combo +box. Personally, I can't think of why you'd want to use it, but it +does exist. + +<!-- There are also a function to set the string on a particular item, void +gtk_combo_set_item_string(GtkCombo *combo, GtkItem *item, const gchar +*item_value), but this requires that you have a pointer to the +appropriate GtkItem. Frankly, I have no idea how to do that. +--> + +<!-- ----------------------------------------------------------------- --> <sect1> Color Selection <p> The color selection widget is, not surprisingly, a widget for @@ -5284,7 +5534,8 @@ void color_changed_cb (GtkWidget *widget, GtkColorSelection *colorsel) gtk_color_selection_get_color (colorsel,color); - /* Fit to a unsigned 16 bit integer (0..65535) and insert into the GdkColor structure */ + /* Fit to a unsigned 16 bit integer (0..65535) and + * insert into the GdkColor structure */ gdk_color.red = (guint16)(color[0]*65535.0); gdk_color.green = (guint16)(color[1]*65535.0); @@ -5326,7 +5577,8 @@ gint area_event (GtkWidget *widget, GdkEvent *event, gpointer client_data) colorsel = GTK_COLOR_SELECTION_DIALOG(colorseldlg)->colorsel; - /* Connect to the "color_changed" signal, set the client-data to the colorsel widget */ + /* Connect to the "color_changed" signal, set the client-data + * to the colorsel widget */ gtk_signal_connect(GTK_OBJECT(colorsel), "color_changed", (GtkSignalFunc)color_changed_cb, (gpointer)colorsel); @@ -5481,7 +5733,8 @@ int main (int argc, char *argv[]) "clicked", (GtkSignalFunc) file_ok_sel, filew ); /* Connect the cancel_button to destroy the widget */ - gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button), + gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION + (filew)->cancel_button), "clicked", (GtkSignalFunc) gtk_widget_destroy, GTK_OBJECT (filew)); @@ -6104,8 +6357,8 @@ create_list (void) /* Create a new list and put it in the scrolled window */ list = gtk_list_new (); - gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), - list); + gtk_scrolled_window_add_with_viewport ( + GTK_SCROLLED_WINDOW (scrolled_window), list); gtk_widget_show (list); /* Add some messages to the window */ @@ -6382,8 +6635,8 @@ int main (int argc, char *argv[]) gtk_table_set_col_spacings (GTK_TABLE (table), 10); /* pack the table into the scrolled window */ - gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), - table); + gtk_scrolled_window_add_with_viewport ( + GTK_SCROLLED_WINDOW (scrolled_window), table); gtk_widget_show (table); /* this simply creates a grid of toggle buttons on the table @@ -6755,12 +7008,14 @@ GTK program. There is one additional thing though, we include a nice XPM picture to serve as an icon for all of the buttons. <tscreen><verb> -GtkWidget* close_button; // this button will emit signal to close application -GtkWidget* tooltips_button; // to enable/disable tooltips +GtkWidget* close_button; /* This button will emit signal to close + * application */ +GtkWidget* tooltips_button; /* to enable/disable tooltips */ GtkWidget* text_button, * icon_button, - * both_button; // radio buttons for toolbar style -GtkWidget* entry; // a text entry to show packing any widget into toolbar + * both_button; /* radio buttons for toolbar style */ +GtkWidget* entry; /* a text entry to show packing any widget into + * toolbar */ </verb></tscreen> In fact not all of the above widgets are needed here, but to make things @@ -6869,16 +7124,16 @@ earlier in this tutorial. <tscreen><verb> /* our first item is <close> button */ - iconw = gtk_pixmap_new ( icon, mask ); // icon widget + iconw = gtk_pixmap_new ( icon, mask ); /* icon widget */ close_button = - gtk_toolbar_append_item ( GTK_TOOLBAR (toolbar), // our toolbar - "Close", // button label - "Closes this app", // tooltip for this button - "Private", // tooltip private string - iconw, // icon widget - GTK_SIGNAL_FUNC (delete_event), // a signal - NULL ); - gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) ); // space after item + gtk_toolbar_append_item ( GTK_TOOLBAR (toolbar), /* our toolbar */ + "Close", /* button label */ + "Closes this app", /* this button's tooltip */ + "Private", /* tooltip private info */ + iconw, /* icon widget */ + GTK_SIGNAL_FUNC (delete_event), /* a signal */ + NULL ); + gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) ); /* space after item */ </verb></tscreen> In the above code you see the simplest case: adding a button to @@ -6892,16 +7147,16 @@ widget, so that we can work with it in the normal way. <tscreen><verb> /* now, let's make our radio buttons group... */ iconw = gtk_pixmap_new ( icon, mask ); - icon_button = - gtk_toolbar_append_element(GTK_TOOLBAR(toolbar), - GTK_TOOLBAR_CHILD_RADIOBUTTON, // a type of element - NULL, // pointer to widget - "Icon", // label - "Only icons in toolbar", // tooltip - "Private", // tooltip private string - iconw, // icon - GTK_SIGNAL_FUNC (radio_event), // signal - toolbar); // data for signal + icon_button = gtk_toolbar_append_element( + GTK_TOOLBAR(toolbar), + GTK_TOOLBAR_CHILD_RADIOBUTTON, /* a type of element */ + NULL, /* pointer to widget */ + "Icon", /* label */ + "Only icons in toolbar", /* tooltip */ + "Private", /* tooltip private string */ + iconw, /* icon */ + GTK_SIGNAL_FUNC (radio_event), /* signal */ + toolbar); /* data for signal */ gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) ); </verb></tscreen> @@ -7079,7 +7334,8 @@ void gtk_notebook_set_tab_pos( GtkNotebook *notebook, GtkPositionType pos ); </verb></tscreen> -GtkPostionType will be one of the following, and they are pretty self explanatory: +GtkPostionType will be one of the following, which are pretty self +explanatory: <itemize> <item> GTK_POS_LEFT <item> GTK_POS_RIGHT @@ -7339,7 +7595,8 @@ int main (int argc, char *argv[]) button = gtk_button_new_with_label ("tab position"); gtk_signal_connect (GTK_OBJECT (button), "clicked", - (GtkSignalFunc) rotate_book, GTK_OBJECT(notebook)); + (GtkSignalFunc) rotate_book, + GTK_OBJECT(notebook)); gtk_table_attach_defaults(GTK_TABLE(table), button, 3,4,1,2); gtk_widget_show(button); @@ -7411,7 +7668,7 @@ and the number of pointers should equal the number of columns specified. Of course we can always use the first form, and manually add titles later. -Note: the GtkCList widget does not have it's own scrollbars and should +Note: the GtkCList widget does not have its own scrollbars and should be placed within a GtkScrolledWindow widget if your require this functionality. This is a change from the GTK 1.0 implementation. @@ -7426,23 +7683,24 @@ void gtk_clist_set_selection_mode( GtkCList *clist, GtkSelectionMode mode ); </verb></tscreen> -which, as the name implies, sets the selection mode of the GtkCList. The first -argument is the GtkCList widget, and the second specifies the cell selection -mode (they are defined in gtkenums.h). At the time of this writing, the following -modes are available to us: +which, as the name implies, sets the selection mode of the +GtkCList. The first argument is the GtkCList widget, and the second +specifies the cell selection mode (they are defined in gtkenums.h). At +the time of this writing, the following modes are available to us: <itemize> -<item> GTK_SELECTION_SINGLE - The selection is either NULL or contains a GList -pointer for a single selected item. +<item> GTK_SELECTION_SINGLE - The selection is either NULL or contains +a GList pointer for a single selected item. -<item> GTK_SELECTION_BROWSE - The selection is NULL if the list contains no -widgets or insensitive ones only, otherwise it contains a GList pointer for -one GList structure, and therefore exactly one list item. +<item> GTK_SELECTION_BROWSE - The selection is NULL if the list +contains no widgets or insensitive ones only, otherwise it contains a +GList pointer for one GList structure, and therefore exactly one list +item. -<item> GTK_SELECTION_MULTIPLE - The selection is NULL if no list items are -selected or a GList pointer for the first selected item. That in turn points -to a GList structure for the second selected item and so on. This is currently -the <bf>default</bf> for the GtkCList widget. +<item> GTK_SELECTION_MULTIPLE - The selection is NULL if no list items +are selected or a GList pointer for the first selected item. That in +turn points to a GList structure for the second selected item and so +on. This is currently the <bf>default</bf> for the GtkCList widget. <item> GTK_SELECTION_EXTENDED - The selection is always NULL. </itemize> @@ -8896,7 +9154,7 @@ disadvantages to each approach. The itemfactory is much easier to use, and to add new menus to, although writing a few wrapper functions to create menus using the manual method could go a long way towards usability. With the -itemfactory, it is not possible to add images or the character '/' to +menufactory, it is not possible to add images or the character '/' to the menus. <!-- ----------------------------------------------------------------- --> @@ -9699,7 +9957,8 @@ int main (int argc, char *argv[]) /* Load a fixed font */ fixed_font = gdk_font_load ("-misc-fixed-medium-r-*-*-*-140-*-*-*-*-*-*"); - /* Realizing a widget creates a window for it, ready for us to insert some text */ + /* Realizing a widget creates a window for it, + * ready for us to insert some text */ gtk_widget_realize (text); /* Freeze the text widget, ready for multiple updates */ @@ -9807,9 +10066,6 @@ from your time. <sect1> Calendar <p> <!-- ----------------------------------------------------------------- --> -<sect1> Combo box -<p> -<!-- ----------------------------------------------------------------- --> <sect1> CTree <p> <!-- ----------------------------------------------------------------- --> @@ -10127,8 +10383,10 @@ ReducedImage *Reduce_The_Image(GDrawable *drawable, tempRGB = (guchar *) malloc(RW*RH*bytes); tempmask = (guchar *) malloc(RW*RH); - gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height, FALSE, FALSE); - gimp_pixel_rgn_init (&srcMask, mask, x1, y1, width, height, FALSE, FALSE); + gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height, + FALSE, FALSE); + gimp_pixel_rgn_init (&srcMask, mask, x1, y1, width, height, + FALSE, FALSE); /* Grab enough to save a row of image and a row of mask. */ src_row = (guchar *) malloc (width*bytes); @@ -10988,11 +11246,32 @@ main (int argc, char *argv[]) <sect>glib<label id="sec_glib"> <!-- ***************************************************************** --> <p> -glib provides many useful functions and definitions available for use -when creating GDK and GTK applications. I will list them all here with -a brief explanation. Many are duplicates of standard libc functions so -I won't go into detail on those. This is mostly to be used as a reference, -so you know what is available for use. +glib is a lower-level library that provides many useful definitions +and functions available for use when creating GDK and GTK +applications. These include definitions for basic types and their +limits, standard macros, type conversions, byte order, memory +allocation, warnings and assertions, message logging, timers, string +utilities, hook functions, a lexical scanner, dynamic loading of +modules, and automatic string completion. A number of data structures +(and their related operations) are also defined, including memory +chunks, doubly-linked lists, singly-linked lists, hash tables, strings +(which can grow dynamically), string chunks (groups of strings), +arrays (which can grow in size as elements are added), balanced binary +trees, N-ary trees, quarks (a two-way association of a string and a +unique integer identifier), keyed data lists (lists of data elements +accessible by a string or integer id), relations and tuples (tables of +data which can be indexed on any number of fields), and caches. + +A summary of some of glib's capabilities follows; not every function, +data structure, or operation is covered here. For more complete +information about the glib routines, see the glib documentation. One +source of glib documentation is http://www.gtk.org/ <htmlurl +url="http://www.gtk.org/" name="http://www.gtk.org/">. + +If you are using a language other than C, you should consult your +language's binding documentation. In some cases your language may +have equivalent functionality built-in, while in other cases it may +not. <!-- ----------------------------------------------------------------- --> <sect1>Definitions @@ -11014,8 +11293,8 @@ G_MAXLONG Also, the following typedefs. The ones left unspecified are dynamically set depending on the architecture. Remember to avoid counting on the size of a -pointer if you want to be portable! E.g., a pointer on an Alpha is 8 bytes, but 4 -on Intel. +pointer if you want to be portable! E.g., a pointer on an Alpha is 8 +bytes, but 4 on Intel 80x86 family CPUs. <tscreen><verb> char gchar; @@ -11046,31 +11325,75 @@ guint32 <!-- ----------------------------------------------------------------- --> <sect1>Doubly Linked Lists <p> -The following functions are used to create, manage, and destroy doubly -linked lists. I assume you know what linked lists are, as it is beyond the scope -of this document to explain them. Of course, it's not required that you -know these for general use of GTK, but they are nice to know. - -<tscreen><verb> -GList *g_list_alloc( void ); - -void g_list_free( GList *list ); - -void g_list_free_1( GList *list ); +The following functions are used to create, manage, and destroy +standard doubly linked lists. Each element in the list contains a +piece of data, together with pointers which link to the previous and +next elements in the list. This enables easy movement in either +direction through the list. The data item is of type "gpointer", +which means the data can be a pointer to your real data or (through +casting) a numeric value (but do not assume that int and gpointer have +the same size!). These routines internally allocate list elements in +blocks, which is more efficient than allocating elements individually. + +There is no function to specifically create a list. Instead, simply +create a variable of type GList* and set its value to NULL; NULL is +considered to be the empty list. + +To add elements to a list, use the g_list_append(), g_list_prepend(), +g_list_insert(), or g_list_insert_sorted() routines. In all cases +they accept a pointer to the beginning of the list, and return the +(possibly changed) pointer to the beginning of the list. Thus, for +all of the operations that add or remove elements, be sure to save the +returned value! + +<tscreen><verb> +GList *g_list_append( GList *list, + gpointer data ); +</verb></tscreen> -GList *g_list_append( GList *list, - gpointer data ); - +This adds a new element (with value <tt/data/) onto the end of the +list. + +<tscreen><verb> GList *g_list_prepend( GList *list, gpointer data ); - +</verb></tscreen> + +This adds a new element (with value <tt/data/) to the beginning of the +list. + +<tscreen><verb> GList *g_list_insert( GList *list, gpointer data, - gint position ); + gint position ); + +</verb></tscreen> + +This inserts a new element (with value data) into the list at the +given position. If position is 0, this is just like g_list_prepend(); +if position is less than 0, this is just like g_list_append(). +<tscreen><verb> GList *g_list_remove( GList *list, gpointer data ); - +</verb></tscreen> + +This removes the element in the list with the value <tt/data/; +if the element isn't there, the list is unchanged. + +<tscreen><verb> +void g_list_free( GList *list ); +</verb></tscreen> + +This frees all of the memory used by a GList. If the list elements +refer to dynamically-allocated memory, then they should be freed +first. + +There are many other glib functions that support doubly linked lists; +see the glib documentation for more information. Here are a few of +the more useful functions' signatures: + +<tscreen><verb> GList *g_list_remove_link( GList *list, GList *link ); @@ -11097,14 +11420,9 @@ void g_list_foreach( GList *list, <sect1>Singly Linked Lists <p> Many of the above functions for singly linked lists are identical to the -above. Here is a complete list: -<tscreen><verb> -GSList *g_slist_alloc( void ); - -void g_slist_free( GSList *list ); - -void g_slist_free_1( GSList *list ); +above. Here is a list of some of their operations: +<tscreen><verb> GSList *g_slist_append( GSList *list, gpointer data ); @@ -11113,7 +11431,7 @@ GSList *g_slist_prepend( GSList *list, GSList *g_slist_insert( GSList *list, gpointer data, - gint position ); + gint position ); GSList *g_slist_remove( GSList *list, gpointer data ); @@ -11135,7 +11453,7 @@ gint g_slist_length( GSList *list ); void g_slist_foreach( GSList *list, GFunc func, - gpointer user_data ); + gpointer user_data ); </verb></tscreen> @@ -11147,7 +11465,8 @@ gpointer g_malloc( gulong size ); </verb></tscreen> This is a replacement for malloc(). You do not need to check the return -value as it is done for you in this function. +value as it is done for you in this function. If the memory allocation +fails for whatever reasons, your applications will be terminated. <tscreen><verb> gpointer g_malloc0( gulong size ); @@ -11167,7 +11486,7 @@ memory should have been previously allocated. void g_free( gpointer mem ); </verb></tscreen> -Frees memory. Easy one. +Frees memory. Easy one. If <tt/mem/ is NULL it simply returns. <tscreen><verb> void g_mem_profile( void ); @@ -11186,7 +11505,11 @@ MEM_CHECK to the top of gmem.c and re-make and make install. <!-- ----------------------------------------------------------------- --> <sect1>Timers <p> -Timer functions.. +Timer functions can be used to time operations (e.g. to see how much +time has elapsed). First, you create a new timer with g_timer_new(). +You can then use g_timer_start() to start timing an operation, +g_timer_stop() to stop timing an operation, and g_timer_elapsed() to +determine the elapsed time. <tscreen><verb> GTimer *g_timer_new( void ); @@ -11206,19 +11529,56 @@ gdouble g_timer_elapsed( GTimer *timer, <!-- ----------------------------------------------------------------- --> <sect1>String Handling <p> -A whole mess of string handling functions. They all look very interesting, and -probably better for many purposes than the standard C string functions, but -require documentation. +glib defines a new type called a GString, which is similar to a +standard C string but one that grows automatically. Its string data +is null-terminated. What this gives you is protection from buffer +overflow programming errors within your program. This is a very +important feature, and hence I recommend that you make use of +GStrings. GString itself has a simple public definition: + +<tscreen><verb> +struct GString +{ + gchar *str; /* Points to the string's current \0-terminated value. */ + gint len; /* Current length */ +}; +</verb></tscreen> + +As you might expect, there are a number of operations you can do with +a GString. <tscreen><verb> GString *g_string_new( gchar *init ); +</verb></tscreen> + +This constructs a GString, copying the string value of <tt/init/ +into the GString and returning a pointer to it. NULL may be given as +the argument for an initially empty GString. + +<tscreen><verb> void g_string_free( GString *string, gint free_segment ); +</verb></tscreen> + +This frees the memory for the given GString. If <tt/free_segment/ is +TRUE, then this also frees its character data. + +<tscreen><verb> -GString *g_string_assign( GString *lval, - gchar *rval ); - +GString *g_string_assign( GString *lval, + const gchar *rval ); +</verb></tscreen> + +This copies the characters from rval into lval, destroying the +previous contents of lval. Note that lval will be lengthened as +necessary to hold the string's contents, unlike the standard strcpy() +function. + +The rest of these functions should be relatively obvious (the _c +versions accept a character instead of a string): + +<tscreen><verb> GString *g_string_truncate( GString *string, gint len ); @@ -12707,9 +13067,7 @@ gtk_dial_expose (GtkWidget *widget, <!-- ----------------------------------------------------------------- --> <sect2> Event handling - <p> - The rest of the widget's code handles various types of events, and isn't too different from what would be found in many GTK applications. Two types of events can occur - either the user can @@ -12717,7 +13075,6 @@ click on the widget with the mouse and drag to move the pointer, or the value of the Adjustment object can change due to some external circumstance. -<p> When the user clicks on the widget, we check to see if the click was appropriately near the pointer, and if so, store then button that the user clicked with in the <tt/button/ field of the widget @@ -12912,7 +13269,6 @@ gtk_dial_update_mouse (GtkDial *dial, gint x, gint y) } </verb></tscreen> -<p> Changes to the Adjustment by external means are communicated to our widget by the `changed' and `value_changed' signals. The handlers for these functions call <tt/gtk_dial_update()/ to validate the @@ -12994,7 +13350,6 @@ gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment, <!-- ----------------------------------------------------------------- --> <sect2> Possible Enhancements <p> - The Dial widget as we've described it so far runs about 670 lines of code. Although that might sound like a fair bit, we've really accomplished quite a bit with that much code, especially since much of @@ -13044,7 +13399,6 @@ Good luck! <!-- ----------------------------------------------------------------- --> <sect1> Overview - <p> In this section, we will build a simple drawing program. In the process, we will examine how to handle mouse events, how to draw in a @@ -13056,7 +13410,6 @@ pressure and tilt, from such devices quite easy. <!-- ----------------------------------------------------------------- --> <sect1> Event Handling - <p> The GTK signals we have already discussed are for high-level actions, such as a menu item being selected. However, sometimes it is useful to @@ -13105,7 +13458,6 @@ GDK_BUTTON4_MASK GDK_BUTTON5_MASK </verb></tscreen> -<p> As for other signals, to determine what happens when an event occurs we call <tt>gtk_signal_connect()</tt>. But we also need let GTK know which events we want to be notified about. To do this, we call @@ -13173,7 +13525,6 @@ To capture events for these widgets, you need to use an EventBox widget. See the section on the <ref id="sec_EventBox" name="EventBox"> widget for details. -<p> For our drawing program, we want to know when the mouse button is pressed and when the mouse is moved, so we specify <tt/GDK_POINTER_MOTION_MASK/ and <tt/GDK_BUTTON_PRESS_MASK/. We also @@ -13183,7 +13534,6 @@ Configure event when our window size changes, we don't have to specify the corresponding <tt/GDK_STRUCTURE_MASK/ flag, because it is automatically specified for all windows. -<p> It turns out, however, that there is a problem with just specifying <tt/GDK_POINTER_MOTION_MASK/. This will cause the server to add a new motion event to the event queue every time the user moves the mouse. @@ -13195,7 +13545,6 @@ the mouse button! What we would like is to only get one motion event for each event we process. The way to do this is to specify <tt/GDK_POINTER_MOTION_HINT_MASK/. -<p> When we specify <tt/GDK_POINTER_MOTION_HINT_MASK/, the server sends us a motion event the first time the pointer moves after entering our window, or after a button press or release event. Subsequent @@ -13214,7 +13563,6 @@ has a simpler interface, but turns out not to be very useful, since it only retrieves the position of the mouse, not whether the buttons are pressed.) -<p> The code to set the events for our window then looks like: <tscreen><verb> @@ -13272,7 +13620,6 @@ motion_notify_event (GtkWidget *widget, GdkEventMotion *event) <!-- ----------------------------------------------------------------- --> <sect1> The DrawingArea Widget, And Drawing - <p> We know turn to the process of drawing on the screen. The widget we use for this is the DrawingArea widget. A drawing area @@ -13297,13 +13644,11 @@ by calling <tt>gtk_widget_set_usize()</tt>, and that, in turn, can be overridden if the user manually resizes the the window containing the drawing area. -<p> It should be noted that when we create a DrawingArea widget, we are, <em>completely</em> responsible for drawing the contents. If our window is obscured then uncovered, we get an exposure event and must redraw what was previously hidden. -<p> Having to remember everything that was drawn on the screen so we can properly redraw it can, to say the least, be a nuisance. In addition, it can be visually distracting if portions of the @@ -13314,7 +13659,6 @@ stored in server memory but not displayed, then when the image changes or new portions of the image are displayed, we copy the relevant portions onto the screen. -<p> To create an offscreen pixmap, we call the function: <tscreen><verb> @@ -13331,7 +13675,6 @@ depth</em>, that is the number of bits per pixel, for the new window. If the depth is specified as <tt>-1</tt>, it will match the depth of <tt>window</tt>. -<p> We create the pixmap in our "configure_event" handler. This event is generated whenever the window changes size, including when it is originally created. @@ -13365,7 +13708,6 @@ configure_event (GtkWidget *widget, GdkEventConfigure *event) The call to <tt>gdk_draw_rectangle()</tt> clears the pixmap initially to white. We'll say more about that in a moment. -<p> Our exposure event handler then simply copies the relevant portion of the pixmap onto the screen (we determine the area we need to redraw by using the event->area field of the exposure event): @@ -13415,7 +13757,6 @@ These functions all share the same first two arguments. The first argument is the drawable to draw upon, the second argument is a <em>graphics context</em> (GC). -<p> A graphics context encapsulates information about things such as foreground and background color and line width. GDK has a full set of functions for creating and modifying graphics contexts, but to keep @@ -13447,7 +13788,6 @@ GTK_STATE_INSENSITIVE For instance, the for <tt/GTK_STATE_SELECTED/ the default foreground color is white and the default background color, dark blue. -<p> Our function <tt>draw_brush()</tt>, which does the actual drawing on the screen, is then: @@ -13485,7 +13825,6 @@ needs to be updated. X will eventually generate an expose event <tt>gtk_widget_draw()</tt>) which will cause our expose event handler to copy the relevant portions to the screen. -<p> We have now covered the entire drawing program except for a few mundane details like creating the main window. The complete source code is available from the location from which you got @@ -13497,9 +13836,7 @@ name="http://www.gtk.org/~otaylor/gtk/tutorial/"> <!-- ----------------------------------------------------------------- --> <sect1> Adding XInput support - <p> - It is now possible to buy quite inexpensive input devices such as drawing tablets, which allow drawing with a much greater ease of artistic expression than does a mouse. The simplest way @@ -13518,7 +13855,6 @@ For information about the XInput extension, see the <htmlurl url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html" name="XInput-HOWTO">. -<p> If we examine the full definition of, for example, the GdkEventMotion structure, we see that it has fields to support extended device information. @@ -13563,7 +13899,6 @@ be used to find out further information about the device using the the mouse.) <sect2> Enabling extended device information - <p> To let GTK know about our interest in the extended device information, we merely have to add a single line to our program: @@ -13581,7 +13916,6 @@ give the values <tt/GDK_EXTENSION_EVENTS_ALL/ if we were willing to draw our own cursor, or <tt/GDK_EXTENSION_EVENTS_NONE/ to revert back to the default condition. -<p> This is not completely the end of the story however. By default, no extension devices are enabled. We need a mechanism to allow users to enable and configure their extension devices. GTK provides @@ -13630,14 +13964,12 @@ connecting to the "destroy" signal, we make sure that we don't keep a pointer to dialog around after it is destroyed - that could lead to a segfault.) -<p> The InputDialog has two buttons "Close" and "Save", which by default have no actions assigned to them. In the above function we make "Close" hide the dialog, hide the "Save" button, since we don't implement saving of XInput options in this program. <sect2> Using extended device information - <p> Once we've enabled the device, we can just use the extended device information in the extra fields of the event structures. @@ -13645,7 +13977,6 @@ In fact, it is always safe to use this information since these fields will have reasonable default values even when extended events are not enabled. -<p> Once change we do have to make is to call <tt/gdk_input_window_get_pointer()/ instead of <tt/gdk_window_get_pointer/. This is necessary because @@ -13653,14 +13984,14 @@ Once change we do have to make is to call information. <tscreen><verb> -void gdk_input_window_get_pointer (GdkWindow *window, - guint32 deviceid, - gdouble *x, - gdouble *y, - gdouble *pressure, - gdouble *xtilt, - gdouble *ytilt, - GdkModifierType *mask); +void gdk_input_window_get_pointer( GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); </verb></tscreen> When calling this function, we need to specify the device ID as @@ -13753,7 +14084,6 @@ draw_brush (GtkWidget *widget, GdkInputSource source, </verb></tscreen> <sect2> Finding out more about a device - <p> As an example of how to find out more about a device, our program will print the name of the device that generates each button @@ -13791,7 +14121,6 @@ that isn't configuration information is <tt/has_cursor/. If cursor. But since we've specified <tt/GDK_EXTENSION_EVENTS_CURSOR/, we don't have to worry about this. -<p> Our <tt/print_button_press()/ function simply iterates through the returned list until it finds a match, then prints out the name of the device. @@ -13830,7 +14159,6 @@ name="http://www.gtk.org/~otaylor/gtk/tutorial/"> <sect2> Further sophistications <label id="sec_Further_Sophistications"> - <p> Although our program now supports XInput quite well, it lacks some features we would want in a full-featured application. First, the user @@ -13840,7 +14168,6 @@ configuration. This is done by iterating through the return of <tt/gdk_input_list_devices()/ and writing out the configuration to a file. -<p> To restore the state next time the program is run, GDK provides functions to change device configuration: @@ -13861,7 +14188,6 @@ would be nice to have a standard way of doing this for all applications. This probably belongs at a slightly higher level than GTK, perhaps in the GNOME library. -<p> Another major omission that we have mentioned above is the lack of cursor drawing. Platforms other than XFree86 currently do not allow simultaneously using a device as both the core pointer and directly by @@ -13871,7 +14197,6 @@ name="XInput-HOWTO"> for more information about this. This means that applications that want to support the widest audience need to draw their own cursor. -<p> An application that draws its own cursor needs to do two things: determine if the current device needs a cursor drawn or not, and determine if the current device is in proximity. (If the current @@ -13886,32 +14211,41 @@ found in the 'testinput' program found in the GTK distribution. <!-- ***************************************************************** --> <sect>Tips For Writing GTK Applications <!-- ***************************************************************** --> - <p> This section is simply a gathering of wisdom, general style guidelines -and hints to creating good GTK applications. It is totally useless -right now cause its only a topic sentence :) - -Use GNU autoconf and automake! They are your friends :) I am planning -to make a quick intro on them here. +and hints to creating good GTK applications. Currently this section +is very short, but hopefully it will get longer in future editions of +this tutorial. + +Use GNU autoconf and automake! They are your friends :) Automake +examines C files, determines how they depend on each other, and +generates a Makefile so the files can be compiled in the correct +order. Autoconf permits automatic configuration of software +installation, handling a large number of system quirks to increase +portability. I am planning to make a quick intro on them here. + +When writing C code, use only C comments (beginning with "/*" and +ending with "*/"), and don't use C++-style comments ("//"). Although +many C compilers understand C++ comments, others don't, and the ANSI C +standard does not require that C++-style comments be processed as +comments. <!-- ***************************************************************** --> <sect>Contributing <label id="sec_Contributing"> <!-- ***************************************************************** --> - <p> This document, like so much other great software out there, was created for free by volunteers. If you are at all knowledgeable about any aspect of GTK that does not already have documentation, please consider contributing to this document. -<p> + If you do decide to contribute, please mail your text to Tony Gale, <tt><htmlurl url="mailto:gale@gtk.org" name="gale@gtk.org"></tt>. Also, be aware that the entirety of this document is free, and any addition by you provide must also be free. That is, people may use any portion of your examples in their programs, and copies of this document may be distributed at will etc. -<p> + Thank you. <!-- ***************************************************************** --> @@ -13971,7 +14305,13 @@ name="bn711@freenet.carleton.ca"></tt> for the Range Widgets and Tree Widget sections. <item>Stefan Mars <tt><htmlurl url="mailto:mars@lysator.liu.se" -name="mars@lysator.liu.se"></tt> for the GtkCList section +name="mars@lysator.liu.se"></tt> for the GtkCList section. + +<item>David A. Wheeler <tt><htmlurl url="mailto:dwheeler@ida.org" +name="dwheeler@ida.org"></tt> for portions of the text on glib +and various tutorial fixups and improvements. +The glib text was in turn based on material developed by Damon Chaplin +<tt><htmlurl url="mailto:DAChaplin@msn.com" name="DAChaplin@msn.com"></tt> </itemize> And to all of you who commented and helped refine this document. @@ -15270,8 +15610,10 @@ tictactoe_class_init (TictactoeClass *class) 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_SIGNAL_OFFSET (TictactoeClass, + tictactoe), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL); @@ -15648,7 +15990,8 @@ gtk_dial_new (GtkAdjustment *adjustment) dial = gtk_type_new (gtk_dial_get_type ()); if (!adjustment) - adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, + 0.0, 0.0, 0.0); gtk_dial_set_adjustment (dial, adjustment); @@ -15700,7 +16043,8 @@ gtk_dial_set_adjustment (GtkDial *dial, if (dial->adjustment) { - gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial); + gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), + (gpointer) dial); gtk_object_unref (GTK_OBJECT (dial->adjustment)); } @@ -15748,7 +16092,9 @@ gtk_dial_realize (GtkWidget *widget) attributes.colormap = gtk_widget_get_colormap (widget); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + widget->window = gdk_window_new (widget->parent->window, + &attributes, + attributes_mask); widget->style = gtk_style_attach (widget->style, widget->window); @@ -15927,7 +16273,8 @@ gtk_dial_button_release (GtkWidget *widget, if ((dial->policy != GTK_UPDATE_CONTINUOUS) && (dial->old_value != dial->adjustment->value)) - gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed"); + gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), + "value_changed"); } return FALSE; @@ -15985,7 +16332,8 @@ gtk_dial_timer (GtkDial *dial) g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE); if (dial->policy == GTK_UPDATE_DELAYED) - gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed"); + gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), + "value_changed"); return FALSE; } @@ -16021,7 +16369,8 @@ gtk_dial_update_mouse (GtkDial *dial, gint x, gint y) { if (dial->policy == GTK_UPDATE_CONTINUOUS) { - gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed"); + gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), + "value_changed"); } else { @@ -16062,7 +16411,8 @@ gtk_dial_update (GtkDial *dial) gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed"); } - dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. / + dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * + 4.*M_PI/3. / (dial->adjustment->upper - dial->adjustment->lower); gtk_widget_draw (GTK_WIDGET(dial), NULL); @@ -16645,7 +16995,7 @@ gint main (int argc, gtk_container_add(GTK_CONTAINER(vbox), separator); gtk_widget_show(separator); - /* Finally create a button and connect it's "clicked" signal + /* Finally create a button and connect its "clicked" signal * to the destruction of the window */ button=gtk_button_new_with_label("Close"); gtk_container_add(GTK_CONTAINER(vbox), button); @@ -16656,7 +17006,7 @@ gint main (int argc, GTK_OBJECT(window)); - /* Now we create 5 list items, each having it's own + /* Now we create 5 list items, each having its own * label and add them to the GtkList using gtk_container_add() * Also we query the text string from the label and * associate it with the list_item_data_key for each list item diff --git a/docs/tutorial/gtk_tut.sgml b/docs/tutorial/gtk_tut.sgml index efad9eb39..656334f65 100644 --- a/docs/tutorial/gtk_tut.sgml +++ b/docs/tutorial/gtk_tut.sgml @@ -5,24 +5,41 @@ --> <article> -<title>GTK v1.1 Tutorial +<title>GTK v1.2 Tutorial <author> Tony Gale <tt><htmlurl url="mailto:gale@gtk.org" name="<gale@gtk.org>"></tt> Ian Main <tt><htmlurl url="mailto:imain@gtk.org" name="<imain@gtk.org>"></tt>, -<date>February 1st, 1999 +<date>February 7th, 1999 +<abstract> +This is a tutorial on how to use GTK (the GIMP Toolkit) through its C +interface. +</abstract> + +<!-- Table of contents --> +<!-- Older versions of this tutorial did not have a table of contents, + but the tutorial is now so large that having one is very useful. --> +<toc> + <!-- ***************************************************************** --> <sect>Introduction <!-- ***************************************************************** --> <p> -GTK (GIMP Toolkit) was originally developed as a toolkit for the GIMP -(General Image Manipulation Program). GTK is built on top of GDK -(GIMP Drawing Kit) which is basically a wrapper around the Xlib -functions. It's called the GIMP toolkit because it was originally -written for developing the GIMP, but has now been used in several free -software projects. The authors are: +GTK (GIMP Toolkit) is a library for creating graphical user +interfaces. It is licensed using the LGPL license, so you can develop +open software, free software, or even commercial non-free software +using GTK without having to spend anything for licenses or royalties. + +It's called the GIMP toolkit because it was originally written for +developing the General Image Manipulation Program (GIMP), but GTK has +now been used in a large number of software projects, including the +GNU Network Object Model Environment (GNOME) project. GTK is built on +top of GDK (GIMP Drawing Kit) which is basically a wrapper around the +low-level functions for accessing the underlying windowing functions +(Xlib in the case of X windows). The primary authors of GTK are: + <itemize> <item> Peter Mattis <tt><htmlurl url="mailto:petm@xcf.berkeley.edu" name="petm@xcf.berkeley.edu"></tt> @@ -45,18 +62,44 @@ implemented here are not available or are nonstandard on other unixes such as g_strerror(). Some also contain enhancements to the libc versions, such as g_malloc that has enhanced debugging utilities. -This tutorial is an attempt to document as much as possible of GTK, it -is by no means complete. This tutorial assumes a good understanding of -C, and how to create C programs. It would be a great benefit for the -reader to have previous X programming experience, but it shouldn't be -necessary. If you are learning GTK as your first widget set, please -comment on how you found this tutorial, and what you had trouble -with. Note that there is also a C++ API for GTK (GTK--) in the works, -so if you prefer to use C++, you should look into this -instead. There are also Objective C, ADA, Guile and other language -bindings available, but I don't follow these. - -This document is a 'work in progress'. Please look for updates on +This tutorial describes the C interface to GTK. There are GTK +bindings for many other languages including C++, Guile, Perl, Python, +TOM, Ada95, Objective C, Free Pascal, and Eiffel. If you intend to +use another language's bindings to GTK, look at that binding's +documentation first. In some cases that documentation may describe +some important conventions (which you should know first) and then +refer you back to this tutorial. There are also some cross-platform +APIs (such as wxWindows and V) which use GTK as one of their target +platforms; again, consult their documentation first. + +If you're developing your GTK application in C++, a few extra notes +are in order. There's a C++ binding to GTK called GTK--, which +provides a more C++-like interface to GTK; you should probably look +into this instead. If you don't like that approach for whatever +reason, there are two alternatives for using GTK. First, you can use +only the C subset of C++ when interfacing with GTK and then use the C +interface as described in this tutorial. Second, you can use GTK and +C++ together by declaring all callbacks as static functions in C++ +classes, and again calling GTK using its C interface. If you choose +this last approach, you can include as the callback's data value a +pointer to the object to be manipulated (the so-called "this" value). +Selecting between these options is simply a matter of preference, +since in all three approaches you get C++ and GTK. None of these +approaches requires the use of a specialized preprocessor, so no +matter what you choose you can use standard C++ with GTK. + +This tutorial is an attempt to document as much as possible of GTK, +but it is by no means complete. This tutorial assumes a good +understanding of C, and how to create C programs. It would be a great +benefit for the reader to have previous X programming experience, but +it shouldn't be necessary. If you are learning GTK as your first +widget set, please comment on how you found this tutorial, and what +you had trouble with. Note that there is also a C++ API for GTK +(GTK--) in the works, so if you prefer to use C++, you should look +into this instead. There are also Objective C, ADA, Guile and other +language bindings available, but I don't follow these. + +This document is a 'work in progress'. Please look for updates on http://www.gtk.org/ <htmlurl url="http://www.gtk.org/" name="http://www.gtk.org/">. @@ -1131,7 +1174,7 @@ int main( int argc, if (argc != 2) { fprintf (stderr, "usage: packbox num, where num is 1, 2, or 3.\n"); - /* this just does cleanup in GTK, and exits with an exit status of 1. */ + /* This just does cleanup in GTK and exits with an exit status of 1. */ gtk_exit (1); } @@ -1215,7 +1258,8 @@ int main( int argc, /* Another new separator. */ separator = gtk_hseparator_new (); - /* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */ + /* The last 3 arguments to gtk_box_pack_start are: + * expand, fill, padding. */ gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5); gtk_widget_show (separator); @@ -1241,7 +1285,8 @@ int main( int argc, gtk_widget_show (box2); separator = gtk_hseparator_new (); - /* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */ + /* The last 3 arguments to gtk_box_pack_start are: + * expand, fill, padding. */ gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5); gtk_widget_show (separator); @@ -1311,7 +1356,8 @@ int main( int argc, GTK_SIGNAL_FUNC (gtk_main_quit), GTK_OBJECT (window)); /* Pack the button into the quitbox. - * The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */ + * The last 3 arguments to gtk_box_pack_start are: + * expand, fill, padding. */ gtk_box_pack_start (GTK_BOX (quitbox), button, TRUE, FALSE, 0); /* pack the quitbox into the vbox (box1) */ gtk_box_pack_start (GTK_BOX (box1), quitbox, FALSE, FALSE, 0); @@ -2411,7 +2457,7 @@ which mouse button is used. As mentioned in <ref id="sec_Adjustment" name="Adjustments"> above, all range widgets are associated with an adjustment object, from which -they calculate the length of the slider and it's position within the +they calculate the length of the slider and its position within the trough. When the user manipulates the slider, the range widget will change the value of the adjustment. @@ -3392,9 +3438,9 @@ Progress bars are used to show the status of an operation. They are pretty easy to use, as you will see with the code below. But first lets start out with the calls to create a new progress bar. -There are two ways to create a progress bar, one simple one takes +There are two ways to create a progress bar, one simple that takes no arguments, and one that takes a GtkAdjustment object as an -argument. If the former is used, the progress bar creates it's own +argument. If the former is used, the progress bar creates its own adjustment object. <tscreen><verb> @@ -3418,8 +3464,8 @@ second argument is the amount 'completed', meaning the amount the progress bar has been filled from 0-100%. This is passed to the function as a real number ranging from 0 to 1. -GTK v1.1 has added new functionality to the progress bar that enables -it to display it's value in different ways, and to inform the user of +GTK v1.2 has added new functionality to the progress bar that enables +it to display its value in different ways, and to inform the user of its current value and its range. A progress bar may be set to one of a number of orientations using the @@ -3441,7 +3487,7 @@ values to indicate the direction in which the progress bar moves: </itemize> When used as a measure of how far a process has progressed, the -GtkProgressBar can be set to display it's value in either a continuous +GtkProgressBar can be set to display its value in either a continuous or discrete mode. In continuous mode, the progress bar is updated for each value. In discrete mode, the progress bar is updated in a number of discrete blocks. The number of blocks is also configurable. @@ -3491,7 +3537,7 @@ void gtk_progress_bar_set_activity_blocks( GtkProgressBar *pbar, </verb></tscreen> When in continuous mode, the progress bar can also display a -configurable text string within it's trough, using the following +configurable text string within its trough, using the following function. <tscreen><verb> @@ -3812,7 +3858,25 @@ vertical box. <p> Pixmaps are data structures that contain pictures. These pictures can be used in various places, but most visibly as icons on the X-Windows -desktop, or as cursors. A bitmap is a 2-color pixmap. +desktop, or as cursors. + +A pixmap which only has 2 colors is called a bitmap, and there are a +few additional routines for handling this common special case. + +To understand pixmaps, it would help to understand how X-windows +works. Under X-windows, applications do not need to be running on the +same computer that is interacting with the user. Instead, the various +applications, called "clients", all communicate with a program which +displays the graphics and handles the keyboard and mouse. This +program which interacts directly with the user is called a "display +server" or "X server." Since the communication might take place over +a network, it's important to keep some information with the X server. +Pixmaps, for example, are stored in the memory of the X server. This +means that once pixmap values are set, they don't need to keep getting +transmitted over the network; instead a command is sent to "display +pixmap number XYZ here." Even if you aren't using X-windows with GTK +currently, using constructs such as Pixmaps will make your programs +work acceptably under X-windows. To use pixmaps in GTK, we must first build a GdkPixmap structure using routines from the GDK layer. Pixmaps can either be created from @@ -3869,8 +3933,8 @@ GdkPixmap *gdk_pixmap_create_from_xpm_d( GdkWindow *window, </verb></tscreen> Small images can be incorporated into a program as data in the XPM -format. A pixmap is created using this data, instead of reading it -from a file. An example of such data is +format. A pixmap is created using this data, instead of reading it +from a file. An example of such data is <tscreen><verb> /* XPM */ @@ -4349,28 +4413,33 @@ int main( int argc, char *argv[] ) { gtk_drawing_area_size( (GtkDrawingArea *)area, XSIZE, YSIZE ); gtk_table_attach( GTK_TABLE(table), area, 1, 2, 1, 2, GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0 ); - gtk_widget_set_events( area, GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK ); + gtk_widget_set_events( area, GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK ); - /* The horizontal ruler goes on top. As the mouse moves across the drawing area, - * a motion_notify_event is passed to the appropriate event handler for the ruler. */ + /* The horizontal ruler goes on top. As the mouse moves across the + * drawing area, a motion_notify_event is passed to the + * appropriate event handler for the ruler. */ hrule = gtk_hruler_new(); gtk_ruler_set_metric( GTK_RULER(hrule), GTK_PIXELS ); gtk_ruler_set_range( GTK_RULER(hrule), 7, 13, 0, 20 ); gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event", - (GtkSignalFunc)EVENT_METHOD(hrule, motion_notify_event), + (GtkSignalFunc)EVENT_METHOD(hrule, + motion_notify_event), GTK_OBJECT(hrule) ); /* GTK_WIDGET_CLASS(GTK_OBJECT(hrule)->klass)->motion_notify_event, */ gtk_table_attach( GTK_TABLE(table), hrule, 1, 2, 0, 1, GTK_EXPAND|GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0 ); - /* The vertical ruler goes on the left. As the mouse moves across the drawing area, - * a motion_notify_event is passed to the appropriate event handler for the ruler. */ + /* The vertical ruler goes on the left. As the mouse moves across + * the drawing area, a motion_notify_event is passed to the + * appropriate event handler for the ruler. */ vrule = gtk_vruler_new(); gtk_ruler_set_metric( GTK_RULER(vrule), GTK_PIXELS ); gtk_ruler_set_range( GTK_RULER(vrule), 0, YSIZE, 10, YSIZE ); gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event", (GtkSignalFunc) - GTK_WIDGET_CLASS(GTK_OBJECT(vrule)->klass)->motion_notify_event, + GTK_WIDGET_CLASS(GTK_OBJECT(vrule)->klass)-> + motion_notify_event, GTK_OBJECT(vrule) ); gtk_table_attach( GTK_TABLE(table), vrule, 0, 1, 1, 2, GTK_FILL, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0 ); @@ -4494,7 +4563,8 @@ int main (int argc, char *argv[]) gtk_box_pack_start (GTK_BOX (vbox), status_bar, TRUE, TRUE, 0); gtk_widget_show (status_bar); - context_id = gtk_statusbar_get_context_id( GTK_STATUSBAR(status_bar), "Statusbar example"); + context_id = gtk_statusbar_get_context_id( + GTK_STATUSBAR(status_bar), "Statusbar example"); button = gtk_button_new_with_label("push item"); gtk_signal_connect(GTK_OBJECT(button), "clicked", @@ -4570,6 +4640,9 @@ following function. This is useful in the callback functions described below. gchar *gtk_entry_get_text( GtkEntry *entry ); </verb></tscreen> +The value returned by this function is used internally, and must not +be freed using either free() or g_free() + If we don't want the contents of the Entry to be changed by someone typing into it, we can change its editable state. @@ -4898,6 +4971,18 @@ void gtk_spin_button_set_update_policy( GtkSpinButton *spin_button, The possible values of <tt/policy/ are either GTK_UPDATE_ALWAYS or GTK_UPDATE_IF_VALID. +These policies affect the behavior of a Spin Button when parsing +inserted text and syncing it's value with the values of the +Adjustment. + +In the case of GTK_UPDATE_IF_VALID the Spin Button only value gets +changed if the text input is a numeric value that +is within the range specified by the Adjustment. Otherwise +the text is reset to the current value. + +In case of GTK_UPDATE_ALWAYS we ignore errors while converting text +into a numeric value. + The appearance of the buttons used in a Spin Button can be changed using the following function: @@ -5153,6 +5238,171 @@ int main( int argc, </verb></tscreen> <!-- ----------------------------------------------------------------- --> +<sect1>Combo Box +<p> +The combo box is another fairly simple widget that is really just a +collection of other widgets. From the users point of view, the widget +consists of a text entry box and a pull down menu from which the user +can select one of a set of predefined entries. Alternatively, the user +can type a different option directly into the text box. + +The following extract from the structure that defines a Combo Box +identifies several of the components: + +<tscreen><verb> +struct _GtkCombo { + GtkHBox hbox; + GtkWidget *entry; + GtkWidget *button; + GtkWidget *popup; + GtkWidget *popwin; + GtkWidget *list; + ... }; +</verb></tscreen> + +As you can see, the Combo Box has two principle parts that you really +care about: an entry and a list. + +First off, to create a combo box, use: + +<tscreen><verb> +GtkWidget *gtk_combo_new( void ); +</verb></tscreen> + +Now, if you want to set the string in the entry section of the combo +box, this is done by manipulating the <tt/entry/ widget directly: + +<tscreen><verb> + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), "My String."); +</verb></tscreen> + +To set the values in the popdown list, one uses the function: + +<tscreen><verb> +void gtk_combo_set_popdown_strings( GtkCombo *combo, + GList *strings ); +</verb></tscreen> + +Before you can do this, you have to assemble a GList of the strings +that you want. GList is a linked list implementation that is part of +<ref id="sec_glib" name="glib">, a library supporing GTK. For the +moment, the quick and dirty explanation is that you need to set up a +GList pointer, set it equal to NULL, then append strings to it with + +<tscreen><verb> +GList *g_list_append( GList *glist, + gpointer data ); +</verb></tscreen> + +It is important that you set the initial GList pointer to NULL. The +value returned from the g_list_append function must be used as the new +pointer to the GList. + +Here's a typical code segment for creating a set of options: + +<tscreen><verb> + GList *glist=NULL; + + glist = g_list_append(glist, "String 1"); + glist = g_list_append(glist, "String 2"); + glist = g_list_append(glist, "String 3"); + glist = g_list_append(glist, "String 4"); + + gtk_combo_set_popdown_strings( GTK_COMBO(combo), glist) ; +</verb></tscreen> + +At this point you have a working combo box that has been set up. +There are a few aspects of its behavior that you can change. These +are accomplished with the functions: + +<tscreen><verb> +void gtk_combo_set_use_arrows( GtkCombo *combo, + gint val ); + +void gtk_combo_set_use_arrows_always( GtkCombo *combo, + gint val ); + +void gtk_combo_set_case_sensitive( GtkCombo *combo, + gint val ); +</verb></tscreen> + +<tt/gtk_combo_set_use_arrows()/ lets the user change the value in the +entry using the up/down arrow keys. This doesn't bring up the list, but +rather replaces the current text in the entry with the next list entry +(up or down, as your key choice indicates). It does this by searching +in the list for the item corresponding to the current value in the +entry and selecting the previous/next item accordingly. Usually in an +entry the arrow keys are used to change focus (you can do that anyway +using TAB). Note that when the current item is the last of the list +and you press arrow-down it changes the focus (the same applies with +the first item and arrow-up). + +If the current value in the entry is not in the list, then the +function of <tt/gtk_combo_set_use_arrows()/ is disabled. + +<tt/gtk_combo_set_use_arrows_always()/ similarly allows the use the +the up/down arrow keys to cycle through the choices in the dropdown +list, except that it wraps around the values in the list, completely +disabling the use of the up and down arrow keys for changing focus. + +<tt/gtk_combo_set_case_sensitive()/ toggles whether or not GTK +searches for entries in a case sensitive manner. This is used when +the Combo widget is asked to find a value from the list using the +current entry in the text box. This completion can be performed in +eother a case sensitive or insensitive manner, depending upon the use +of this function. The Combo widget can also simply complete the +current entry if the user presses the key combination MOD-1 and +'Tab'. MOD-1 is often mapped to the 'Alt' key. Note, however that some +Window managers also use this key combination, which will override +it's use within GTK. + +Now that we have a combo box, tailored to look and act how we want it, +all that remains is being able to get data from the combo box. This is +relatively straight forward. The majority of the time, all you are +going to care about getting data from is the entry. The entry is +accessed simply by GTK_ENTRY(GTK_COMBO(combo)->entry). The two +principle things that you are going to want to do with it are attach +to the activate signal, which indicates that the user has pressed the +Return or Enter key,and read the text. The first is accomplished +using something like: + +<tscreen><verb> + gtk_signal_connect(GTK_OBJECT(GTK_COMB(combo)->entry), "activate", + GTK_SIGNAL_FUNC (my_callback_function), my_data); +</verb></tscreen> + +Getting the text at any arbitrary time is accomplished by simply using +the entry function: + +<tscreen><verb> +gchar *gtk_entry_get_text(GtkEntry *entry); +</verb></tscreen> + +Such as: + +<tscreen><verb> + char *string; + + string = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry)); +</verb></tscreen> + +That's about all there is to it. There is a function + +<tscreen><verb> +void gtk_combo_disable_activate(GtkCombo *combo); +</verb></tscreen> + +that will disable the activate signal on the entry widget in the combo +box. Personally, I can't think of why you'd want to use it, but it +does exist. + +<!-- There are also a function to set the string on a particular item, void +gtk_combo_set_item_string(GtkCombo *combo, GtkItem *item, const gchar +*item_value), but this requires that you have a pointer to the +appropriate GtkItem. Frankly, I have no idea how to do that. +--> + +<!-- ----------------------------------------------------------------- --> <sect1> Color Selection <p> The color selection widget is, not surprisingly, a widget for @@ -5284,7 +5534,8 @@ void color_changed_cb (GtkWidget *widget, GtkColorSelection *colorsel) gtk_color_selection_get_color (colorsel,color); - /* Fit to a unsigned 16 bit integer (0..65535) and insert into the GdkColor structure */ + /* Fit to a unsigned 16 bit integer (0..65535) and + * insert into the GdkColor structure */ gdk_color.red = (guint16)(color[0]*65535.0); gdk_color.green = (guint16)(color[1]*65535.0); @@ -5326,7 +5577,8 @@ gint area_event (GtkWidget *widget, GdkEvent *event, gpointer client_data) colorsel = GTK_COLOR_SELECTION_DIALOG(colorseldlg)->colorsel; - /* Connect to the "color_changed" signal, set the client-data to the colorsel widget */ + /* Connect to the "color_changed" signal, set the client-data + * to the colorsel widget */ gtk_signal_connect(GTK_OBJECT(colorsel), "color_changed", (GtkSignalFunc)color_changed_cb, (gpointer)colorsel); @@ -5481,7 +5733,8 @@ int main (int argc, char *argv[]) "clicked", (GtkSignalFunc) file_ok_sel, filew ); /* Connect the cancel_button to destroy the widget */ - gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button), + gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION + (filew)->cancel_button), "clicked", (GtkSignalFunc) gtk_widget_destroy, GTK_OBJECT (filew)); @@ -6104,8 +6357,8 @@ create_list (void) /* Create a new list and put it in the scrolled window */ list = gtk_list_new (); - gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), - list); + gtk_scrolled_window_add_with_viewport ( + GTK_SCROLLED_WINDOW (scrolled_window), list); gtk_widget_show (list); /* Add some messages to the window */ @@ -6382,8 +6635,8 @@ int main (int argc, char *argv[]) gtk_table_set_col_spacings (GTK_TABLE (table), 10); /* pack the table into the scrolled window */ - gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), - table); + gtk_scrolled_window_add_with_viewport ( + GTK_SCROLLED_WINDOW (scrolled_window), table); gtk_widget_show (table); /* this simply creates a grid of toggle buttons on the table @@ -6755,12 +7008,14 @@ GTK program. There is one additional thing though, we include a nice XPM picture to serve as an icon for all of the buttons. <tscreen><verb> -GtkWidget* close_button; // this button will emit signal to close application -GtkWidget* tooltips_button; // to enable/disable tooltips +GtkWidget* close_button; /* This button will emit signal to close + * application */ +GtkWidget* tooltips_button; /* to enable/disable tooltips */ GtkWidget* text_button, * icon_button, - * both_button; // radio buttons for toolbar style -GtkWidget* entry; // a text entry to show packing any widget into toolbar + * both_button; /* radio buttons for toolbar style */ +GtkWidget* entry; /* a text entry to show packing any widget into + * toolbar */ </verb></tscreen> In fact not all of the above widgets are needed here, but to make things @@ -6869,16 +7124,16 @@ earlier in this tutorial. <tscreen><verb> /* our first item is <close> button */ - iconw = gtk_pixmap_new ( icon, mask ); // icon widget + iconw = gtk_pixmap_new ( icon, mask ); /* icon widget */ close_button = - gtk_toolbar_append_item ( GTK_TOOLBAR (toolbar), // our toolbar - "Close", // button label - "Closes this app", // tooltip for this button - "Private", // tooltip private string - iconw, // icon widget - GTK_SIGNAL_FUNC (delete_event), // a signal - NULL ); - gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) ); // space after item + gtk_toolbar_append_item ( GTK_TOOLBAR (toolbar), /* our toolbar */ + "Close", /* button label */ + "Closes this app", /* this button's tooltip */ + "Private", /* tooltip private info */ + iconw, /* icon widget */ + GTK_SIGNAL_FUNC (delete_event), /* a signal */ + NULL ); + gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) ); /* space after item */ </verb></tscreen> In the above code you see the simplest case: adding a button to @@ -6892,16 +7147,16 @@ widget, so that we can work with it in the normal way. <tscreen><verb> /* now, let's make our radio buttons group... */ iconw = gtk_pixmap_new ( icon, mask ); - icon_button = - gtk_toolbar_append_element(GTK_TOOLBAR(toolbar), - GTK_TOOLBAR_CHILD_RADIOBUTTON, // a type of element - NULL, // pointer to widget - "Icon", // label - "Only icons in toolbar", // tooltip - "Private", // tooltip private string - iconw, // icon - GTK_SIGNAL_FUNC (radio_event), // signal - toolbar); // data for signal + icon_button = gtk_toolbar_append_element( + GTK_TOOLBAR(toolbar), + GTK_TOOLBAR_CHILD_RADIOBUTTON, /* a type of element */ + NULL, /* pointer to widget */ + "Icon", /* label */ + "Only icons in toolbar", /* tooltip */ + "Private", /* tooltip private string */ + iconw, /* icon */ + GTK_SIGNAL_FUNC (radio_event), /* signal */ + toolbar); /* data for signal */ gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) ); </verb></tscreen> @@ -7079,7 +7334,8 @@ void gtk_notebook_set_tab_pos( GtkNotebook *notebook, GtkPositionType pos ); </verb></tscreen> -GtkPostionType will be one of the following, and they are pretty self explanatory: +GtkPostionType will be one of the following, which are pretty self +explanatory: <itemize> <item> GTK_POS_LEFT <item> GTK_POS_RIGHT @@ -7339,7 +7595,8 @@ int main (int argc, char *argv[]) button = gtk_button_new_with_label ("tab position"); gtk_signal_connect (GTK_OBJECT (button), "clicked", - (GtkSignalFunc) rotate_book, GTK_OBJECT(notebook)); + (GtkSignalFunc) rotate_book, + GTK_OBJECT(notebook)); gtk_table_attach_defaults(GTK_TABLE(table), button, 3,4,1,2); gtk_widget_show(button); @@ -7411,7 +7668,7 @@ and the number of pointers should equal the number of columns specified. Of course we can always use the first form, and manually add titles later. -Note: the GtkCList widget does not have it's own scrollbars and should +Note: the GtkCList widget does not have its own scrollbars and should be placed within a GtkScrolledWindow widget if your require this functionality. This is a change from the GTK 1.0 implementation. @@ -7426,23 +7683,24 @@ void gtk_clist_set_selection_mode( GtkCList *clist, GtkSelectionMode mode ); </verb></tscreen> -which, as the name implies, sets the selection mode of the GtkCList. The first -argument is the GtkCList widget, and the second specifies the cell selection -mode (they are defined in gtkenums.h). At the time of this writing, the following -modes are available to us: +which, as the name implies, sets the selection mode of the +GtkCList. The first argument is the GtkCList widget, and the second +specifies the cell selection mode (they are defined in gtkenums.h). At +the time of this writing, the following modes are available to us: <itemize> -<item> GTK_SELECTION_SINGLE - The selection is either NULL or contains a GList -pointer for a single selected item. +<item> GTK_SELECTION_SINGLE - The selection is either NULL or contains +a GList pointer for a single selected item. -<item> GTK_SELECTION_BROWSE - The selection is NULL if the list contains no -widgets or insensitive ones only, otherwise it contains a GList pointer for -one GList structure, and therefore exactly one list item. +<item> GTK_SELECTION_BROWSE - The selection is NULL if the list +contains no widgets or insensitive ones only, otherwise it contains a +GList pointer for one GList structure, and therefore exactly one list +item. -<item> GTK_SELECTION_MULTIPLE - The selection is NULL if no list items are -selected or a GList pointer for the first selected item. That in turn points -to a GList structure for the second selected item and so on. This is currently -the <bf>default</bf> for the GtkCList widget. +<item> GTK_SELECTION_MULTIPLE - The selection is NULL if no list items +are selected or a GList pointer for the first selected item. That in +turn points to a GList structure for the second selected item and so +on. This is currently the <bf>default</bf> for the GtkCList widget. <item> GTK_SELECTION_EXTENDED - The selection is always NULL. </itemize> @@ -8896,7 +9154,7 @@ disadvantages to each approach. The itemfactory is much easier to use, and to add new menus to, although writing a few wrapper functions to create menus using the manual method could go a long way towards usability. With the -itemfactory, it is not possible to add images or the character '/' to +menufactory, it is not possible to add images or the character '/' to the menus. <!-- ----------------------------------------------------------------- --> @@ -9699,7 +9957,8 @@ int main (int argc, char *argv[]) /* Load a fixed font */ fixed_font = gdk_font_load ("-misc-fixed-medium-r-*-*-*-140-*-*-*-*-*-*"); - /* Realizing a widget creates a window for it, ready for us to insert some text */ + /* Realizing a widget creates a window for it, + * ready for us to insert some text */ gtk_widget_realize (text); /* Freeze the text widget, ready for multiple updates */ @@ -9807,9 +10066,6 @@ from your time. <sect1> Calendar <p> <!-- ----------------------------------------------------------------- --> -<sect1> Combo box -<p> -<!-- ----------------------------------------------------------------- --> <sect1> CTree <p> <!-- ----------------------------------------------------------------- --> @@ -10127,8 +10383,10 @@ ReducedImage *Reduce_The_Image(GDrawable *drawable, tempRGB = (guchar *) malloc(RW*RH*bytes); tempmask = (guchar *) malloc(RW*RH); - gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height, FALSE, FALSE); - gimp_pixel_rgn_init (&srcMask, mask, x1, y1, width, height, FALSE, FALSE); + gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height, + FALSE, FALSE); + gimp_pixel_rgn_init (&srcMask, mask, x1, y1, width, height, + FALSE, FALSE); /* Grab enough to save a row of image and a row of mask. */ src_row = (guchar *) malloc (width*bytes); @@ -10988,11 +11246,32 @@ main (int argc, char *argv[]) <sect>glib<label id="sec_glib"> <!-- ***************************************************************** --> <p> -glib provides many useful functions and definitions available for use -when creating GDK and GTK applications. I will list them all here with -a brief explanation. Many are duplicates of standard libc functions so -I won't go into detail on those. This is mostly to be used as a reference, -so you know what is available for use. +glib is a lower-level library that provides many useful definitions +and functions available for use when creating GDK and GTK +applications. These include definitions for basic types and their +limits, standard macros, type conversions, byte order, memory +allocation, warnings and assertions, message logging, timers, string +utilities, hook functions, a lexical scanner, dynamic loading of +modules, and automatic string completion. A number of data structures +(and their related operations) are also defined, including memory +chunks, doubly-linked lists, singly-linked lists, hash tables, strings +(which can grow dynamically), string chunks (groups of strings), +arrays (which can grow in size as elements are added), balanced binary +trees, N-ary trees, quarks (a two-way association of a string and a +unique integer identifier), keyed data lists (lists of data elements +accessible by a string or integer id), relations and tuples (tables of +data which can be indexed on any number of fields), and caches. + +A summary of some of glib's capabilities follows; not every function, +data structure, or operation is covered here. For more complete +information about the glib routines, see the glib documentation. One +source of glib documentation is http://www.gtk.org/ <htmlurl +url="http://www.gtk.org/" name="http://www.gtk.org/">. + +If you are using a language other than C, you should consult your +language's binding documentation. In some cases your language may +have equivalent functionality built-in, while in other cases it may +not. <!-- ----------------------------------------------------------------- --> <sect1>Definitions @@ -11014,8 +11293,8 @@ G_MAXLONG Also, the following typedefs. The ones left unspecified are dynamically set depending on the architecture. Remember to avoid counting on the size of a -pointer if you want to be portable! E.g., a pointer on an Alpha is 8 bytes, but 4 -on Intel. +pointer if you want to be portable! E.g., a pointer on an Alpha is 8 +bytes, but 4 on Intel 80x86 family CPUs. <tscreen><verb> char gchar; @@ -11046,31 +11325,75 @@ guint32 <!-- ----------------------------------------------------------------- --> <sect1>Doubly Linked Lists <p> -The following functions are used to create, manage, and destroy doubly -linked lists. I assume you know what linked lists are, as it is beyond the scope -of this document to explain them. Of course, it's not required that you -know these for general use of GTK, but they are nice to know. - -<tscreen><verb> -GList *g_list_alloc( void ); - -void g_list_free( GList *list ); - -void g_list_free_1( GList *list ); +The following functions are used to create, manage, and destroy +standard doubly linked lists. Each element in the list contains a +piece of data, together with pointers which link to the previous and +next elements in the list. This enables easy movement in either +direction through the list. The data item is of type "gpointer", +which means the data can be a pointer to your real data or (through +casting) a numeric value (but do not assume that int and gpointer have +the same size!). These routines internally allocate list elements in +blocks, which is more efficient than allocating elements individually. + +There is no function to specifically create a list. Instead, simply +create a variable of type GList* and set its value to NULL; NULL is +considered to be the empty list. + +To add elements to a list, use the g_list_append(), g_list_prepend(), +g_list_insert(), or g_list_insert_sorted() routines. In all cases +they accept a pointer to the beginning of the list, and return the +(possibly changed) pointer to the beginning of the list. Thus, for +all of the operations that add or remove elements, be sure to save the +returned value! + +<tscreen><verb> +GList *g_list_append( GList *list, + gpointer data ); +</verb></tscreen> -GList *g_list_append( GList *list, - gpointer data ); - +This adds a new element (with value <tt/data/) onto the end of the +list. + +<tscreen><verb> GList *g_list_prepend( GList *list, gpointer data ); - +</verb></tscreen> + +This adds a new element (with value <tt/data/) to the beginning of the +list. + +<tscreen><verb> GList *g_list_insert( GList *list, gpointer data, - gint position ); + gint position ); + +</verb></tscreen> + +This inserts a new element (with value data) into the list at the +given position. If position is 0, this is just like g_list_prepend(); +if position is less than 0, this is just like g_list_append(). +<tscreen><verb> GList *g_list_remove( GList *list, gpointer data ); - +</verb></tscreen> + +This removes the element in the list with the value <tt/data/; +if the element isn't there, the list is unchanged. + +<tscreen><verb> +void g_list_free( GList *list ); +</verb></tscreen> + +This frees all of the memory used by a GList. If the list elements +refer to dynamically-allocated memory, then they should be freed +first. + +There are many other glib functions that support doubly linked lists; +see the glib documentation for more information. Here are a few of +the more useful functions' signatures: + +<tscreen><verb> GList *g_list_remove_link( GList *list, GList *link ); @@ -11097,14 +11420,9 @@ void g_list_foreach( GList *list, <sect1>Singly Linked Lists <p> Many of the above functions for singly linked lists are identical to the -above. Here is a complete list: -<tscreen><verb> -GSList *g_slist_alloc( void ); - -void g_slist_free( GSList *list ); - -void g_slist_free_1( GSList *list ); +above. Here is a list of some of their operations: +<tscreen><verb> GSList *g_slist_append( GSList *list, gpointer data ); @@ -11113,7 +11431,7 @@ GSList *g_slist_prepend( GSList *list, GSList *g_slist_insert( GSList *list, gpointer data, - gint position ); + gint position ); GSList *g_slist_remove( GSList *list, gpointer data ); @@ -11135,7 +11453,7 @@ gint g_slist_length( GSList *list ); void g_slist_foreach( GSList *list, GFunc func, - gpointer user_data ); + gpointer user_data ); </verb></tscreen> @@ -11147,7 +11465,8 @@ gpointer g_malloc( gulong size ); </verb></tscreen> This is a replacement for malloc(). You do not need to check the return -value as it is done for you in this function. +value as it is done for you in this function. If the memory allocation +fails for whatever reasons, your applications will be terminated. <tscreen><verb> gpointer g_malloc0( gulong size ); @@ -11167,7 +11486,7 @@ memory should have been previously allocated. void g_free( gpointer mem ); </verb></tscreen> -Frees memory. Easy one. +Frees memory. Easy one. If <tt/mem/ is NULL it simply returns. <tscreen><verb> void g_mem_profile( void ); @@ -11186,7 +11505,11 @@ MEM_CHECK to the top of gmem.c and re-make and make install. <!-- ----------------------------------------------------------------- --> <sect1>Timers <p> -Timer functions.. +Timer functions can be used to time operations (e.g. to see how much +time has elapsed). First, you create a new timer with g_timer_new(). +You can then use g_timer_start() to start timing an operation, +g_timer_stop() to stop timing an operation, and g_timer_elapsed() to +determine the elapsed time. <tscreen><verb> GTimer *g_timer_new( void ); @@ -11206,19 +11529,56 @@ gdouble g_timer_elapsed( GTimer *timer, <!-- ----------------------------------------------------------------- --> <sect1>String Handling <p> -A whole mess of string handling functions. They all look very interesting, and -probably better for many purposes than the standard C string functions, but -require documentation. +glib defines a new type called a GString, which is similar to a +standard C string but one that grows automatically. Its string data +is null-terminated. What this gives you is protection from buffer +overflow programming errors within your program. This is a very +important feature, and hence I recommend that you make use of +GStrings. GString itself has a simple public definition: + +<tscreen><verb> +struct GString +{ + gchar *str; /* Points to the string's current \0-terminated value. */ + gint len; /* Current length */ +}; +</verb></tscreen> + +As you might expect, there are a number of operations you can do with +a GString. <tscreen><verb> GString *g_string_new( gchar *init ); +</verb></tscreen> + +This constructs a GString, copying the string value of <tt/init/ +into the GString and returning a pointer to it. NULL may be given as +the argument for an initially empty GString. + +<tscreen><verb> void g_string_free( GString *string, gint free_segment ); +</verb></tscreen> + +This frees the memory for the given GString. If <tt/free_segment/ is +TRUE, then this also frees its character data. + +<tscreen><verb> -GString *g_string_assign( GString *lval, - gchar *rval ); - +GString *g_string_assign( GString *lval, + const gchar *rval ); +</verb></tscreen> + +This copies the characters from rval into lval, destroying the +previous contents of lval. Note that lval will be lengthened as +necessary to hold the string's contents, unlike the standard strcpy() +function. + +The rest of these functions should be relatively obvious (the _c +versions accept a character instead of a string): + +<tscreen><verb> GString *g_string_truncate( GString *string, gint len ); @@ -12707,9 +13067,7 @@ gtk_dial_expose (GtkWidget *widget, <!-- ----------------------------------------------------------------- --> <sect2> Event handling - <p> - The rest of the widget's code handles various types of events, and isn't too different from what would be found in many GTK applications. Two types of events can occur - either the user can @@ -12717,7 +13075,6 @@ click on the widget with the mouse and drag to move the pointer, or the value of the Adjustment object can change due to some external circumstance. -<p> When the user clicks on the widget, we check to see if the click was appropriately near the pointer, and if so, store then button that the user clicked with in the <tt/button/ field of the widget @@ -12912,7 +13269,6 @@ gtk_dial_update_mouse (GtkDial *dial, gint x, gint y) } </verb></tscreen> -<p> Changes to the Adjustment by external means are communicated to our widget by the `changed' and `value_changed' signals. The handlers for these functions call <tt/gtk_dial_update()/ to validate the @@ -12994,7 +13350,6 @@ gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment, <!-- ----------------------------------------------------------------- --> <sect2> Possible Enhancements <p> - The Dial widget as we've described it so far runs about 670 lines of code. Although that might sound like a fair bit, we've really accomplished quite a bit with that much code, especially since much of @@ -13044,7 +13399,6 @@ Good luck! <!-- ----------------------------------------------------------------- --> <sect1> Overview - <p> In this section, we will build a simple drawing program. In the process, we will examine how to handle mouse events, how to draw in a @@ -13056,7 +13410,6 @@ pressure and tilt, from such devices quite easy. <!-- ----------------------------------------------------------------- --> <sect1> Event Handling - <p> The GTK signals we have already discussed are for high-level actions, such as a menu item being selected. However, sometimes it is useful to @@ -13105,7 +13458,6 @@ GDK_BUTTON4_MASK GDK_BUTTON5_MASK </verb></tscreen> -<p> As for other signals, to determine what happens when an event occurs we call <tt>gtk_signal_connect()</tt>. But we also need let GTK know which events we want to be notified about. To do this, we call @@ -13173,7 +13525,6 @@ To capture events for these widgets, you need to use an EventBox widget. See the section on the <ref id="sec_EventBox" name="EventBox"> widget for details. -<p> For our drawing program, we want to know when the mouse button is pressed and when the mouse is moved, so we specify <tt/GDK_POINTER_MOTION_MASK/ and <tt/GDK_BUTTON_PRESS_MASK/. We also @@ -13183,7 +13534,6 @@ Configure event when our window size changes, we don't have to specify the corresponding <tt/GDK_STRUCTURE_MASK/ flag, because it is automatically specified for all windows. -<p> It turns out, however, that there is a problem with just specifying <tt/GDK_POINTER_MOTION_MASK/. This will cause the server to add a new motion event to the event queue every time the user moves the mouse. @@ -13195,7 +13545,6 @@ the mouse button! What we would like is to only get one motion event for each event we process. The way to do this is to specify <tt/GDK_POINTER_MOTION_HINT_MASK/. -<p> When we specify <tt/GDK_POINTER_MOTION_HINT_MASK/, the server sends us a motion event the first time the pointer moves after entering our window, or after a button press or release event. Subsequent @@ -13214,7 +13563,6 @@ has a simpler interface, but turns out not to be very useful, since it only retrieves the position of the mouse, not whether the buttons are pressed.) -<p> The code to set the events for our window then looks like: <tscreen><verb> @@ -13272,7 +13620,6 @@ motion_notify_event (GtkWidget *widget, GdkEventMotion *event) <!-- ----------------------------------------------------------------- --> <sect1> The DrawingArea Widget, And Drawing - <p> We know turn to the process of drawing on the screen. The widget we use for this is the DrawingArea widget. A drawing area @@ -13297,13 +13644,11 @@ by calling <tt>gtk_widget_set_usize()</tt>, and that, in turn, can be overridden if the user manually resizes the the window containing the drawing area. -<p> It should be noted that when we create a DrawingArea widget, we are, <em>completely</em> responsible for drawing the contents. If our window is obscured then uncovered, we get an exposure event and must redraw what was previously hidden. -<p> Having to remember everything that was drawn on the screen so we can properly redraw it can, to say the least, be a nuisance. In addition, it can be visually distracting if portions of the @@ -13314,7 +13659,6 @@ stored in server memory but not displayed, then when the image changes or new portions of the image are displayed, we copy the relevant portions onto the screen. -<p> To create an offscreen pixmap, we call the function: <tscreen><verb> @@ -13331,7 +13675,6 @@ depth</em>, that is the number of bits per pixel, for the new window. If the depth is specified as <tt>-1</tt>, it will match the depth of <tt>window</tt>. -<p> We create the pixmap in our "configure_event" handler. This event is generated whenever the window changes size, including when it is originally created. @@ -13365,7 +13708,6 @@ configure_event (GtkWidget *widget, GdkEventConfigure *event) The call to <tt>gdk_draw_rectangle()</tt> clears the pixmap initially to white. We'll say more about that in a moment. -<p> Our exposure event handler then simply copies the relevant portion of the pixmap onto the screen (we determine the area we need to redraw by using the event->area field of the exposure event): @@ -13415,7 +13757,6 @@ These functions all share the same first two arguments. The first argument is the drawable to draw upon, the second argument is a <em>graphics context</em> (GC). -<p> A graphics context encapsulates information about things such as foreground and background color and line width. GDK has a full set of functions for creating and modifying graphics contexts, but to keep @@ -13447,7 +13788,6 @@ GTK_STATE_INSENSITIVE For instance, the for <tt/GTK_STATE_SELECTED/ the default foreground color is white and the default background color, dark blue. -<p> Our function <tt>draw_brush()</tt>, which does the actual drawing on the screen, is then: @@ -13485,7 +13825,6 @@ needs to be updated. X will eventually generate an expose event <tt>gtk_widget_draw()</tt>) which will cause our expose event handler to copy the relevant portions to the screen. -<p> We have now covered the entire drawing program except for a few mundane details like creating the main window. The complete source code is available from the location from which you got @@ -13497,9 +13836,7 @@ name="http://www.gtk.org/~otaylor/gtk/tutorial/"> <!-- ----------------------------------------------------------------- --> <sect1> Adding XInput support - <p> - It is now possible to buy quite inexpensive input devices such as drawing tablets, which allow drawing with a much greater ease of artistic expression than does a mouse. The simplest way @@ -13518,7 +13855,6 @@ For information about the XInput extension, see the <htmlurl url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html" name="XInput-HOWTO">. -<p> If we examine the full definition of, for example, the GdkEventMotion structure, we see that it has fields to support extended device information. @@ -13563,7 +13899,6 @@ be used to find out further information about the device using the the mouse.) <sect2> Enabling extended device information - <p> To let GTK know about our interest in the extended device information, we merely have to add a single line to our program: @@ -13581,7 +13916,6 @@ give the values <tt/GDK_EXTENSION_EVENTS_ALL/ if we were willing to draw our own cursor, or <tt/GDK_EXTENSION_EVENTS_NONE/ to revert back to the default condition. -<p> This is not completely the end of the story however. By default, no extension devices are enabled. We need a mechanism to allow users to enable and configure their extension devices. GTK provides @@ -13630,14 +13964,12 @@ connecting to the "destroy" signal, we make sure that we don't keep a pointer to dialog around after it is destroyed - that could lead to a segfault.) -<p> The InputDialog has two buttons "Close" and "Save", which by default have no actions assigned to them. In the above function we make "Close" hide the dialog, hide the "Save" button, since we don't implement saving of XInput options in this program. <sect2> Using extended device information - <p> Once we've enabled the device, we can just use the extended device information in the extra fields of the event structures. @@ -13645,7 +13977,6 @@ In fact, it is always safe to use this information since these fields will have reasonable default values even when extended events are not enabled. -<p> Once change we do have to make is to call <tt/gdk_input_window_get_pointer()/ instead of <tt/gdk_window_get_pointer/. This is necessary because @@ -13653,14 +13984,14 @@ Once change we do have to make is to call information. <tscreen><verb> -void gdk_input_window_get_pointer (GdkWindow *window, - guint32 deviceid, - gdouble *x, - gdouble *y, - gdouble *pressure, - gdouble *xtilt, - gdouble *ytilt, - GdkModifierType *mask); +void gdk_input_window_get_pointer( GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); </verb></tscreen> When calling this function, we need to specify the device ID as @@ -13753,7 +14084,6 @@ draw_brush (GtkWidget *widget, GdkInputSource source, </verb></tscreen> <sect2> Finding out more about a device - <p> As an example of how to find out more about a device, our program will print the name of the device that generates each button @@ -13791,7 +14121,6 @@ that isn't configuration information is <tt/has_cursor/. If cursor. But since we've specified <tt/GDK_EXTENSION_EVENTS_CURSOR/, we don't have to worry about this. -<p> Our <tt/print_button_press()/ function simply iterates through the returned list until it finds a match, then prints out the name of the device. @@ -13830,7 +14159,6 @@ name="http://www.gtk.org/~otaylor/gtk/tutorial/"> <sect2> Further sophistications <label id="sec_Further_Sophistications"> - <p> Although our program now supports XInput quite well, it lacks some features we would want in a full-featured application. First, the user @@ -13840,7 +14168,6 @@ configuration. This is done by iterating through the return of <tt/gdk_input_list_devices()/ and writing out the configuration to a file. -<p> To restore the state next time the program is run, GDK provides functions to change device configuration: @@ -13861,7 +14188,6 @@ would be nice to have a standard way of doing this for all applications. This probably belongs at a slightly higher level than GTK, perhaps in the GNOME library. -<p> Another major omission that we have mentioned above is the lack of cursor drawing. Platforms other than XFree86 currently do not allow simultaneously using a device as both the core pointer and directly by @@ -13871,7 +14197,6 @@ name="XInput-HOWTO"> for more information about this. This means that applications that want to support the widest audience need to draw their own cursor. -<p> An application that draws its own cursor needs to do two things: determine if the current device needs a cursor drawn or not, and determine if the current device is in proximity. (If the current @@ -13886,32 +14211,41 @@ found in the 'testinput' program found in the GTK distribution. <!-- ***************************************************************** --> <sect>Tips For Writing GTK Applications <!-- ***************************************************************** --> - <p> This section is simply a gathering of wisdom, general style guidelines -and hints to creating good GTK applications. It is totally useless -right now cause its only a topic sentence :) - -Use GNU autoconf and automake! They are your friends :) I am planning -to make a quick intro on them here. +and hints to creating good GTK applications. Currently this section +is very short, but hopefully it will get longer in future editions of +this tutorial. + +Use GNU autoconf and automake! They are your friends :) Automake +examines C files, determines how they depend on each other, and +generates a Makefile so the files can be compiled in the correct +order. Autoconf permits automatic configuration of software +installation, handling a large number of system quirks to increase +portability. I am planning to make a quick intro on them here. + +When writing C code, use only C comments (beginning with "/*" and +ending with "*/"), and don't use C++-style comments ("//"). Although +many C compilers understand C++ comments, others don't, and the ANSI C +standard does not require that C++-style comments be processed as +comments. <!-- ***************************************************************** --> <sect>Contributing <label id="sec_Contributing"> <!-- ***************************************************************** --> - <p> This document, like so much other great software out there, was created for free by volunteers. If you are at all knowledgeable about any aspect of GTK that does not already have documentation, please consider contributing to this document. -<p> + If you do decide to contribute, please mail your text to Tony Gale, <tt><htmlurl url="mailto:gale@gtk.org" name="gale@gtk.org"></tt>. Also, be aware that the entirety of this document is free, and any addition by you provide must also be free. That is, people may use any portion of your examples in their programs, and copies of this document may be distributed at will etc. -<p> + Thank you. <!-- ***************************************************************** --> @@ -13971,7 +14305,13 @@ name="bn711@freenet.carleton.ca"></tt> for the Range Widgets and Tree Widget sections. <item>Stefan Mars <tt><htmlurl url="mailto:mars@lysator.liu.se" -name="mars@lysator.liu.se"></tt> for the GtkCList section +name="mars@lysator.liu.se"></tt> for the GtkCList section. + +<item>David A. Wheeler <tt><htmlurl url="mailto:dwheeler@ida.org" +name="dwheeler@ida.org"></tt> for portions of the text on glib +and various tutorial fixups and improvements. +The glib text was in turn based on material developed by Damon Chaplin +<tt><htmlurl url="mailto:DAChaplin@msn.com" name="DAChaplin@msn.com"></tt> </itemize> And to all of you who commented and helped refine this document. @@ -15270,8 +15610,10 @@ tictactoe_class_init (TictactoeClass *class) 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_SIGNAL_OFFSET (TictactoeClass, + tictactoe), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL); @@ -15648,7 +15990,8 @@ gtk_dial_new (GtkAdjustment *adjustment) dial = gtk_type_new (gtk_dial_get_type ()); if (!adjustment) - adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, + 0.0, 0.0, 0.0); gtk_dial_set_adjustment (dial, adjustment); @@ -15700,7 +16043,8 @@ gtk_dial_set_adjustment (GtkDial *dial, if (dial->adjustment) { - gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial); + gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), + (gpointer) dial); gtk_object_unref (GTK_OBJECT (dial->adjustment)); } @@ -15748,7 +16092,9 @@ gtk_dial_realize (GtkWidget *widget) attributes.colormap = gtk_widget_get_colormap (widget); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + widget->window = gdk_window_new (widget->parent->window, + &attributes, + attributes_mask); widget->style = gtk_style_attach (widget->style, widget->window); @@ -15927,7 +16273,8 @@ gtk_dial_button_release (GtkWidget *widget, if ((dial->policy != GTK_UPDATE_CONTINUOUS) && (dial->old_value != dial->adjustment->value)) - gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed"); + gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), + "value_changed"); } return FALSE; @@ -15985,7 +16332,8 @@ gtk_dial_timer (GtkDial *dial) g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE); if (dial->policy == GTK_UPDATE_DELAYED) - gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed"); + gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), + "value_changed"); return FALSE; } @@ -16021,7 +16369,8 @@ gtk_dial_update_mouse (GtkDial *dial, gint x, gint y) { if (dial->policy == GTK_UPDATE_CONTINUOUS) { - gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed"); + gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), + "value_changed"); } else { @@ -16062,7 +16411,8 @@ gtk_dial_update (GtkDial *dial) gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed"); } - dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. / + dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * + 4.*M_PI/3. / (dial->adjustment->upper - dial->adjustment->lower); gtk_widget_draw (GTK_WIDGET(dial), NULL); @@ -16645,7 +16995,7 @@ gint main (int argc, gtk_container_add(GTK_CONTAINER(vbox), separator); gtk_widget_show(separator); - /* Finally create a button and connect it's "clicked" signal + /* Finally create a button and connect its "clicked" signal * to the destruction of the window */ button=gtk_button_new_with_label("Close"); gtk_container_add(GTK_CONTAINER(vbox), button); @@ -16656,7 +17006,7 @@ gint main (int argc, GTK_OBJECT(window)); - /* Now we create 5 list items, each having it's own + /* Now we create 5 list items, each having its own * label and add them to the GtkList using gtk_container_add() * Also we query the text string from the label and * associate it with the list_item_data_key for each list item |