1 <!doctype book PUBLIC "-//OASIS//DTD DocBook V3.1//EN" [
2 <!notation PNG system "PNG">
3 <!entity % local.notation.class "| PNG">
8 <date>February 20, 2002</date>
9 <title>GTK+ 2.0 Tutorial</title>
12 <firstname>Tony</firstname>
13 <surname>Gale</surname>
16 <firstname>Ian</firstname>
17 <surname>Main</surname>
20 <firstname>& the GTK team</firstname>
24 <para>This is a tutorial on how to use GTK (the GIMP Toolkit) through its C
31 <!-- ***************************************************************** -->
32 <chapter id="ch-Introduction">
33 <title>Introduction</title>
35 <para>GTK (GIMP Toolkit) is a library for creating graphical user
36 interfaces. It is licensed using the LGPL license, so you can develop
37 open software, free software, or even commercial non-free software
38 using GTK without having to spend anything for licenses or royalties.</para>
40 <para>It's called the GIMP toolkit because it was originally written for
41 developing the GNU Image Manipulation Program (GIMP), but GTK has
42 now been used in a large number of software projects, including the
43 GNU Network Object Model Environment (GNOME) project. GTK is built on
44 top of GDK (GIMP Drawing Kit) which is basically a wrapper around the
45 low-level functions for accessing the underlying windowing functions
46 (Xlib in the case of the X windows system), and gdk-pixbuf, a library for
47 client-side image manipulation.
49 <para>The primary authors of GTK are:</para>
52 <listitem><simpara> Peter Mattis <ulink url="mailto:petm@xcf.berkeley.edu">
53 petm@xcf.berkeley.edu</ulink></simpara>
55 <listitem><simpara> Spencer Kimball <ulink url="mailto:spencer@xcf.berkeley.edu">
56 spencer@xcf.berkeley.edu</ulink></simpara>
58 <listitem><simpara> Josh MacDonald <ulink url="mailto:jmacd@xcf.berkeley.edu">
59 jmacd@xcf.berkeley.edu</ulink></simpara>
63 <para>GTK is currently maintained by:</para>
66 <listitem><simpara> Owen Taylor <ulink url="mailto:otaylor@redhat.com">
67 otaylor@redhat.com</ulink></simpara>
69 <listitem><simpara> Tim Janik <ulink url="mailto:timj@gtk.org">
70 timj@gtk.org</ulink></simpara>
74 <para>GTK is essentially an object oriented application programmers
75 interface (API). Although written completely in C, it is implemented
76 using the idea of classes and callback functions (pointers to
79 <para>There is also a third component called GLib which contains a few
80 replacements for some standard calls, as well as some additional
81 functions for handling linked lists, etc. The replacement functions
82 are used to increase GTK's portability, as some of the functions
83 implemented here are not available or are nonstandard on other Unixes
84 such as g_strerror(). Some also contain enhancements to the libc
85 versions, such as g_malloc() that has enhanced debugging utilities.</para>
87 <para>In version 2.0, GLib has picked up the type system which forms the
88 foundation for GTK's class hierarchy, the signal system which is used
89 throughout GTK, a thread API which abstracts the different native thread APIs
90 of the various platforms and a facility for loading modules.
93 <para>As the last component, GTK uses the Pango library for internationalized
97 <para>This tutorial describes the C interface to GTK. There are GTK
98 bindings for many other languages including C++, Guile, Perl, Python,
99 TOM, Ada95, Objective C, Free Pascal, Eiffel, Java and C#. If you intend to
100 use another language's bindings to GTK, look at that binding's
101 documentation first. In some cases that documentation may describe
102 some important conventions (which you should know first) and then
103 refer you back to this tutorial. There are also some cross-platform
104 APIs (such as wxWindows and V) which use GTK as one of their target
105 platforms; again, consult their documentation first.</para>
107 <para>If you're developing your GTK application in C++, a few extra notes
108 are in order. There's a C++ binding to GTK called GTK--, which
109 provides a more C++-like interface to GTK; you should probably look
110 into this instead. If you don't like that approach for whatever
111 reason, there are two alternatives for using GTK. First, you can use
112 only the C subset of C++ when interfacing with GTK and then use the C
113 interface as described in this tutorial. Second, you can use GTK and
114 C++ together by declaring all callbacks as static functions in C++
115 classes, and again calling GTK using its C interface. If you choose
116 this last approach, you can include as the callback's data value a
117 pointer to the object to be manipulated (the so-called "this" value).
118 Selecting between these options is simply a matter of preference,
119 since in all three approaches you get C++ and GTK. None of these
120 approaches requires the use of a specialized preprocessor, so no
121 matter what you choose you can use standard C++ with GTK.</para>
123 <para>This tutorial is an attempt to document as much as possible of GTK,
124 but it is by no means complete. This tutorial assumes a good
125 understanding of C, and how to create C programs. It would be a great
126 benefit for the reader to have previous X programming experience, but
127 it shouldn't be necessary. If you are learning GTK as your first
128 widget set, please comment on how you found this tutorial, and what
129 you had trouble with. There are also C++, Objective C, ADA, Guile and
130 other language bindings available, but I don't follow these.</para>
132 <para>This document is a "work in progress". Please look for updates on
133 <ulink url="http://www.gtk.org/">http://www.gtk.org/</ulink>.</para>
135 <para>I would very much like to hear of any problems you have learning GTK
136 from this document, and would appreciate input as to how it may be
137 improved. Please see the section on <link linkend="ch-Contributing">Contributing
138 </link> for further information.</para>
142 <!-- ***************************************************************** -->
143 <chapter id="ch-GettingStarted">
144 <title>Getting Started</title>
146 <para>The first thing to do, of course, is download the GTK source and
147 install it. You can always get the latest version from <ulink
148 url="ftp://ftp.gtk.org/pub/gtk">ftp.gtk.org</ulink>. You can also view
149 other sources of GTK information on
150 <ulink url="http://www.gtk.org/">http://www.gtk.org/</ulink>. GTK
151 uses GNU autoconf for configuration. Once untar'd, type
152 <literal>./configure --help</literal> to see a list of options.</para>
154 <para>The GTK source distribution also contains the complete source to all
155 of the examples used in this tutorial, along with Makefiles to aid
158 <para>To begin our introduction to GTK, we'll start with the simplest
159 program possible. This program will create a 200x200 pixel window and
160 has no way of exiting except to be killed by using the shell.</para>
165 <imagedata fileref="base.png" format="png">
170 <programlisting role="C">
171 <!-- example-start base base.c -->
173 #include <gtk/gtk.h>
180 gtk_init (&argc, &argv);
182 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
183 gtk_widget_show (window);
192 <para>You can compile the above program with gcc using:</para>
193 <para><literallayout>
194 <literal>gcc base.c -o base `pkg-config --cflags --libs gtk-2.0`</literal>
195 </literallayout></para>
197 <para>The meaning of the unusual compilation options is explained below in
198 <link linkend="sec-Compiling">Compiling Hello World</link>.</para>
200 <para>All programs will of course include <filename>gtk/gtk.h</filename> which
201 declares the variables, functions, structures, etc. that will be used in your GTK
204 <para>The next line:</para>
206 <programlisting role="C">
207 gtk_init (&argc, &argv);
210 <para>calls the function gtk_init(gint *argc, gchar ***argv) which will be called
211 in all GTK applications. This sets up a few things for us such as the default visual
212 and color map and then proceeds to call gdk_init(gint *argc, gchar ***argv).
213 This function initializes the library for use, sets up default signal handlers, and
214 checks the arguments passed to your application on the command line, looking for
215 one of the following:</para>
217 <itemizedlist spacing=Compact>
218 <listitem><simpara> <literal>--gtk-module</literal></simpara>
220 <listitem><simpara> <literal>--g-fatal-warnings</literal></simpara>
222 <listitem><simpara> <literal>--gtk-debug</literal></simpara>
224 <listitem><simpara> <literal>--gtk-no-debug</literal></simpara>
226 <listitem><simpara> <literal>--gdk-debug</literal></simpara>
228 <listitem><simpara> <literal>--gdk-no-debug</literal></simpara>
230 <listitem><simpara> <literal>--display</literal></simpara>
232 <listitem><simpara> <literal>--sync</literal></simpara>
234 <listitem><simpara> <literal>--name</literal></simpara>
236 <listitem><simpara> <literal>--class</literal></simpara>
240 <para>It removes these from the argument list, leaving anything it does not
241 recognize for your application to parse or ignore. This creates a set
242 of standard arguments accepted by all GTK applications.</para>
244 <para>The next two lines of code create and display a window.</para>
246 <programlisting role="C">
247 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
248 gtk_widget_show (window);
251 <para>The <literal>GTK_WINDOW_TOPLEVEL</literal> argument specifies that we want the
252 window to undergo window manager decoration and placement. Rather than
253 create a window of 0x0 size, a window without children is set to
254 200x200 by default so you can still manipulate it.</para>
256 <para>The gtk_widget_show() function lets GTK know that we are done setting
257 the attributes of this widget, and that it can display it.</para>
259 <para>The last line enters the GTK main processing loop.</para>
261 <programlisting role="C">
265 <para>gtk_main() is another call you will see in every GTK application.
266 When control reaches this point, GTK will sleep waiting for X events
267 (such as button or key presses), timeouts, or file IO notifications to
268 occur. In our simple example, however, events are ignored.</para>
270 <!-- ----------------------------------------------------------------- -->
271 <sect1 id="sec-HelloWorld">
272 <title>Hello World in GTK</title>
274 <para>Now for a program with a widget (a button). It's the classic
275 hello world a la GTK.</para>
280 <imagedata fileref="helloworld.png" format="png">
285 <programlisting role="C">
286 <!-- example-start helloworld helloworld.c -->
288 #include <gtk/gtk.h>
290 /* This is a callback function. The data arguments are ignored
291 * in this example. More on callbacks below. */
292 void hello( GtkWidget *widget,
295 g_print ("Hello World\n");
298 gint delete_event( GtkWidget *widget,
302 /* If you return FALSE in the "delete_event" signal handler,
303 * GTK will emit the "destroy" signal. Returning TRUE means
304 * you don't want the window to be destroyed.
305 * This is useful for popping up 'are you sure you want to quit?'
308 g_print ("delete event occurred\n");
310 /* Change TRUE to FALSE and the main window will be destroyed with
311 * a "delete_event". */
316 /* Another callback */
317 void destroy( GtkWidget *widget,
326 /* GtkWidget is the storage type for widgets */
330 /* This is called in all GTK applications. Arguments are parsed
331 * from the command line and are returned to the application. */
332 gtk_init (&argc, &argv);
334 /* create a new window */
335 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
337 /* When the window is given the "delete_event" signal (this is given
338 * by the window manager, usually by the "close" option, or on the
339 * titlebar), we ask it to call the delete_event () function
340 * as defined above. The data passed to the callback
341 * function is NULL and is ignored in the callback function. */
342 g_signal_connect (G_OBJECT (window), "delete_event",
343 G_CALLBACK (delete_event), NULL);
345 /* Here we connect the "destroy" event to a signal handler.
346 * This event occurs when we call gtk_widget_destroy() on the window,
347 * or if we return FALSE in the "delete_event" callback. */
348 g_signal_connect (G_OBJECT (window), "destroy",
349 G_CALLBACK (destroy), NULL);
351 /* Sets the border width of the window. */
352 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
354 /* Creates a new button with the label "Hello World". */
355 button = gtk_button_new_with_label ("Hello World");
357 /* When the button receives the "clicked" signal, it will call the
358 * function hello() passing it NULL as its argument. The hello()
359 * function is defined above. */
360 g_signal_connect (G_OBJECT (button), "clicked",
361 G_CALLBACK (hello), NULL);
363 /* This will cause the window to be destroyed by calling
364 * gtk_widget_destroy(window) when "clicked". Again, the destroy
365 * signal could come from here, or the window manager. */
366 g_signal_connect_swapped (G_OBJECT (button), "clicked",
367 G_CALLBACK (gtk_widget_destroy),
370 /* This packs the button into the window (a gtk container). */
371 gtk_container_add (GTK_CONTAINER (window), button);
373 /* The final step is to display this newly created widget. */
374 gtk_widget_show (button);
377 gtk_widget_show (window);
379 /* All GTK applications must have a gtk_main(). Control ends here
380 * and waits for an event to occur (like a key press or
391 <!-- ----------------------------------------------------------------- -->
392 <sect1 id="sec-Compiling">
393 <title>Compiling Hello World</title>
395 <para>To compile use:</para>
397 <para><literallayout>
398 <literal>gcc -Wall -g helloworld.c -o helloworld `pkg-config --cflags gtk-2.0` \</literal>
399 <literal> `pkg-config --libs gtk-2.0`</literal>
400 </literallayout></para>
402 <para>This uses the program <literal>pkg-config</literal>, which can be obtained from
403 <ulink url="http://www.freedesktop.org">www.freedesktop.org</ulink>. This program
404 reads the <filename>.pc</filename> which comes with GTK to determine what
405 compiler switches are needed to compile programs that use GTK.
406 <literal>pkg-config --cflags gtk+-2.0</literal> will output a list of include
407 directories for the compiler to look in, and
408 <literal>pkg-config --libs gtk+-2.0</literal>
409 will output the list of libraries for the compiler to link with and
410 the directories to find them in. In the above example they could have
411 been combined into a single instance, such as
412 <literal>pkg-config --cflags --libs gtk+-2.0</literal>.</para>
414 <para>Note that the type of single quote used in the compile command above
415 is significant.</para>
417 <para>The libraries that are usually linked in are:</para>
420 <listitem><simpara>The GTK library (<literal>-lgtk</literal>), the widget library,
421 based on top of GDK.</simpara>
424 <listitem><simpara>The GDK library (<literal>-lgdk</literal>), the Xlib wrapper.</simpara>
427 <listitem><simpara>The gdk-pixbuf library (<literal>-lgdk_pixbuf</literal>), the image
428 manipulation library.</simpara>
431 <listitem><simpara>The Pango library (<literal>-lpango</literal>) for internationalized
435 <listitem><simpara>The gobject library (<literal>-lgobject</literal>), containing the
436 type system on which GTK is based.</simpara>
439 <listitem><simpara>The gmodule library (<literal>-lgmodule</literal>), which is used
440 to load run time extensions.</simpara>
443 <listitem><simpara>The GLib library (<literal>-lglib</literal>), containing miscellaneous
444 functions; only g_print() is used in this particular example. GTK is built on top
445 of GLib so you will always require this library. See the section on
446 <link linkend="ch-glib">GLib</link> for details.</simpara>
449 <listitem><simpara>The Xlib library (<literal>-lX11</literal>) which is used by GDK.</simpara>
452 <listitem><simpara>The Xext library (<literal>-lXext</literal>). This contains code
453 for shared memory pixmaps and other X extensions.</simpara>
456 <listitem><simpara>The math library (<literal>-lm</literal>). This is used by GTK
457 for various purposes.</simpara>
463 <!-- ----------------------------------------------------------------- -->
464 <sect1 id="sec-TheoryOfSignalsAndCallbacks">
465 <title>Theory of Signals and Callbacks</title>
468 <para>In version 2.0, the signal system has been moved from GTK to GLib, therefore the
469 functions and types explained in this section have a "g_" prefix rather than a "gtk_"
470 prefix. We won't go into details about the extensions which the GLib 2.0 signal system
471 has relative to the GTK 1.2 signal system.</para>
474 <para>Before we look in detail at <emphasis>helloworld</emphasis>, we'll discuss signals
475 and callbacks. GTK is an event driven toolkit, which means it will
476 sleep in gtk_main() until an event occurs and control is passed to the
477 appropriate function.</para>
479 <para>This passing of control is done using the idea of "signals". (Note
480 that these signals are not the same as the Unix system signals, and
481 are not implemented using them, although the terminology is almost
482 identical.) When an event occurs, such as the press of a mouse button,
483 the appropriate signal will be "emitted" by the widget that was
484 pressed. This is how GTK does most of its useful work. There are
485 signals that all widgets inherit, such as "destroy", and there are
486 signals that are widget specific, such as "toggled" on a toggle
489 <para>To make a button perform an action, we set up a signal handler to
490 catch these signals and call the appropriate function. This is done by
491 using a function such as:</para>
493 <programlisting role="C">
494 gulong g_signal_connect( gpointer *object,
497 gpointer func_data );
500 <para>where the first argument is the widget which will be emitting the
501 signal, and the second the name of the signal you wish to catch. The
502 third is the function you wish to be called when it is caught, and the
503 fourth, the data you wish to have passed to this function.</para>
505 <para>The function specified in the third argument is called a "callback
506 function", and should generally be of the form</para>
508 <programlisting role="C">
509 void callback_func( GtkWidget *widget,
510 gpointer callback_data );
513 <para>where the first argument will be a pointer to the widget that emitted
514 the signal, and the second a pointer to the data given as the last
515 argument to the g_signal_connect() function as shown above.</para>
517 <para>Note that the above form for a signal callback function declaration is
518 only a general guide, as some widget specific signals generate
519 different calling parameters.</para>
521 <para>Another call used in the <emphasis>helloworld</emphasis> example, is:</para>
523 <programlisting role="C">
524 gulong g_signal_connect_swapped( gpointer *object,
527 gpointer *slot_object );
530 <para>g_signal_connect_swapped() is the same as g_signal_connect() except
531 that the callback function only uses one argument, a pointer to a GTK
532 object. So when using this function to connect signals, the callback
533 should be of the form</para>
535 <programlisting role="C">
536 void callback_func( GtkObject *object );
539 <para>where the object is usually a widget. We usually don't setup callbacks
540 for g_signal_connect_swapped() however. They are usually used to call a
541 GTK function that accepts a single widget or object as an argument, as
542 is the case in our <emphasis>helloworld</emphasis> example.</para>
544 <para>The purpose of having two functions to connect signals is simply to
545 allow the callbacks to have a different number of arguments. Many
546 functions in the GTK library accept only a single GtkWidget pointer as
547 an argument, so you want to use the g_signal_connect_swapped() for
548 these, whereas for your functions, you may need to have additional
549 data supplied to the callbacks.</para>
553 <!-- ----------------------------------------------------------------- -->
554 <sect1 id="sec-Events">
555 <title>Events</title>
557 <para>In addition to the signal mechanism described above, there is a set
558 of <emphasis>events</emphasis> that reflect the X event mechanism. Callbacks may
559 also be attached to these events. These events are:</para>
561 <itemizedlist spacing=Compact>
562 <listitem><simpara> event</simpara>
564 <listitem><simpara> button_press_event</simpara>
566 <listitem><simpara> button_release_event</simpara>
568 <listitem><simpara> scroll_event</simpara>
570 <listitem><simpara> motion_notify_event</simpara>
572 <listitem><simpara> delete_event</simpara>
574 <listitem><simpara> destroy_event</simpara>
576 <listitem><simpara> expose_event</simpara>
578 <listitem><simpara> key_press_event</simpara>
580 <listitem><simpara> key_release_event</simpara>
582 <listitem><simpara> enter_notify_event</simpara>
584 <listitem><simpara> leave_notify_event</simpara>
586 <listitem><simpara> configure_event</simpara>
588 <listitem><simpara> focus_in_event</simpara>
590 <listitem><simpara> focus_out_event</simpara>
592 <listitem><simpara> map_event</simpara>
594 <listitem><simpara> unmap_event</simpara>
596 <listitem><simpara> property_notify_event</simpara>
598 <listitem><simpara> selection_clear_event</simpara>
600 <listitem><simpara> selection_request_event</simpara>
602 <listitem><simpara> selection_notify_event</simpara>
604 <listitem><simpara> proximity_in_event</simpara>
606 <listitem><simpara> proximity_out_event</simpara>
608 <listitem><simpara> visibility_notify_event</simpara>
610 <listitem><simpara> client_event</simpara>
612 <listitem><simpara> no_expose_event</simpara>
614 <listitem><simpara> window_state_event</simpara>
618 <para>In order to connect a callback function to one of these events you
619 use the function g_signal_connect(), as described above, using one of
620 the above event names as the <literal>name</literal> parameter. The callback
621 function for events has a slightly different form than that for
624 <programlisting role="C">
625 gint callback_func( GtkWidget *widget,
627 gpointer callback_data );
630 <para>GdkEvent is a C <literal>union</literal> structure whose type will depend upon
631 which of the above events has occurred. In order for us to tell which event
632 has been issued each of the possible alternatives has a <literal>type</literal>
633 member that reflects the event being issued. The other components
634 of the event structure will depend upon the type of the
635 event. Possible values for the type are:</para>
637 <programlisting role="C">
657 GDK_SELECTION_REQUEST
668 GDK_VISIBILITY_NOTIFY
675 <para>So, to connect a callback function to one of these events we would use
676 something like:</para>
678 <programlisting role="C">
679 g_signal_connect (G_OBJECT (button), "button_press_event",
680 G_CALLBACK (button_press_callback), NULL);
683 <para>This assumes that <literal>button</literal> is a Button widget. Now, when the
684 mouse is over the button and a mouse button is pressed, the function
685 button_press_callback() will be called. This function may be declared as:</para>
687 <programlisting role="C">
688 static gint button_press_callback( GtkWidget *widget,
689 GdkEventButton *event,
693 <para>Note that we can declare the second argument as type
694 <literal>GdkEventButton</literal> as we know what type of event will occur for this
695 function to be called.</para>
697 <para>The value returned from this function indicates whether the event
698 should be propagated further by the GTK event handling
699 mechanism. Returning TRUE indicates that the event has been handled,
700 and that it should not propagate further. Returning FALSE continues
701 the normal event handling. See the section on
702 <link linkend="ch-AdvancedEventsAndSignals">Advanced Event and Signal Handling</link>
703 for more details on this propagation process.</para>
705 <para>For details on the GdkEvent data types, see the appendix entitled
706 <link linkend="app-GDKEventTypes">GDK Event Types</link>.</para>
708 <para>The GDK selection and drag-and-drop APIs also emit a number of events which
709 are reflected in GTK by the signals. See <link
710 linkend="sec-SignalsOnSourceWidgets">Signals on the source widget</link> and <link
711 linkend="sec-SignalsOnDestWidgets">Signals on the destination widget</link>
712 for details on the signatures of the callback functions for these signals:</para>
714 <itemizedlist spacing=Compact>
715 <listitem><simpara> selection_received</simpara>
717 <listitem><simpara> selection_get</simpara>
719 <listitem><simpara> drag_begin_event</simpara>
721 <listitem><simpara> drag_end_event</simpara>
723 <listitem><simpara> drag_data_delete</simpara>
725 <listitem><simpara> drag_motion</simpara>
727 <listitem><simpara> drag_drop</simpara>
729 <listitem><simpara> drag_data_get</simpara>
731 <listitem><simpara> drag_data_received</simpara>
737 <!-- ----------------------------------------------------------------- -->
738 <sect1 id="sec-SteppingThroughHelloWorld">
739 <title>Stepping Through Hello World</title>
741 <para>Now that we know the theory behind this, let's clarify by walking
742 through the example <emphasis>helloworld</emphasis> program.</para>
744 <para>Here is the callback function that will be called when the button is
745 "clicked". We ignore both the widget and the data in this example, but
746 it is not hard to do things with them. The next example will use the
747 data argument to tell us which button was pressed.</para>
749 <programlisting role="C">
750 void hello( GtkWidget *widget,
753 g_print ("Hello World\n");
757 <para>The next callback is a bit special. The "delete_event" occurs when the
758 window manager sends this event to the application. We have a choice
759 here as to what to do about these events. We can ignore them, make
760 some sort of response, or simply quit the application.</para>
762 <para>The value you return in this callback lets GTK know what action to
763 take. By returning TRUE, we let it know that we don't want to have
764 the "destroy" signal emitted, keeping our application running. By
765 returning FALSE, we ask that "destroy" be emitted, which in turn will
766 call our "destroy" signal handler.</para>
769 <programlisting role="C">
770 gint delete_event( GtkWidget *widget,
774 g_print ("delete event occurred\n");
780 <para>Here is another callback function which causes the program to quit by
781 calling gtk_main_quit(). This function tells GTK that it is to exit
782 from gtk_main when control is returned to it.</para>
784 <programlisting role="C">
785 void destroy( GtkWidget *widget,
792 <para>I assume you know about the main() function... yes, as with other
793 applications, all GTK applications will also have one of these.</para>
795 <programlisting role="C">
801 <para>This next part declares pointers to a structure of type
802 GtkWidget. These are used below to create a window and a button.</para>
804 <programlisting role="C">
809 <para>Here is our gtk_init() again. As before, this initializes the toolkit,
810 and parses the arguments found on the command line. Any argument it
811 recognizes from the command line, it removes from the list, and
812 modifies argc and argv to make it look like they never existed,
813 allowing your application to parse the remaining arguments.</para>
815 <programlisting role="C">
816 gtk_init (&argc, &argv);
819 <para>Create a new window. This is fairly straightforward. Memory is
820 allocated for the GtkWidget *window structure so it now points to a
821 valid structure. It sets up a new window, but it is not displayed
822 until we call gtk_widget_show(window) near the end of our program.</para>
824 <programlisting role="C">
825 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
828 <para>Here are two examples of connecting a signal handler to an object, in
829 this case, the window. Here, the "delete_event" and "destroy" signals
830 are caught. The first is emitted when we use the window manager to
831 kill the window, or when we use the gtk_widget_destroy() call passing
832 in the window widget as the object to destroy. The second is emitted
833 when, in the "delete_event" handler, we return FALSE.
835 The <literal>G_OBJECT</literal> and <literal>G_CALLBACK</literal> are macros
836 that perform type casting and checking for us, as well as aid the readability of
839 <programlisting role="C">
840 g_signal_connect (G_OBJECT (window), "delete_event",
841 G_CALLBACK (delete_event), NULL);
842 g_signal_connect (G_OBJECT (window), "destroy",
843 G_CALLBACK (destroy), NULL);
846 <para>This next function is used to set an attribute of a container object.
847 This just sets the window so it has a blank area along the inside of
848 it 10 pixels wide where no widgets will go. There are other similar
849 functions which we will look at in the section on
850 <link linkend="ch-SettingWidgetAttributes">Setting Widget Attributes</link></para>
852 <para>And again, <literal>GTK_CONTAINER</literal> is a macro to perform type casting.</para>
854 <programlisting role="C">
855 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
858 <para>This call creates a new button. It allocates space for a new GtkWidget
859 structure in memory, initializes it, and makes the button pointer
860 point to it. It will have the label "Hello World" on it when
863 <programlisting role="C">
864 button = gtk_button_new_with_label ("Hello World");
867 <para>Here, we take this button, and make it do something useful. We attach
868 a signal handler to it so when it emits the "clicked" signal, our
869 hello() function is called. The data is ignored, so we simply pass in
870 NULL to the hello() callback function. Obviously, the "clicked" signal
871 is emitted when we click the button with our mouse pointer.</para>
873 <programlisting role="C">
874 g_signal_connect (G_OBJECT (button), "clicked",
875 G_CALLBACK (hello), NULL);
878 <para>We are also going to use this button to exit our program. This will
879 illustrate how the "destroy" signal may come from either the window
880 manager, or our program. When the button is "clicked", same as above,
881 it calls the first hello() callback function, and then this one in the
882 order they are set up. You may have as many callback functions as you
883 need, and all will be executed in the order you connected
884 them. Because the gtk_widget_destroy() function accepts only a
885 GtkWidget *widget as an argument, we use the g_signal_connect_swapped()
886 function here instead of straight g_signal_connect().</para>
888 <programlisting role="C">
889 g_signal_connect_swapped (G_OBJECT (button), "clicked",
890 G_CALLBACK (gtk_widget_destroy),
894 <para>This is a packing call, which will be explained in depth later on in
895 <link linkend="ch-PackingWidgets">Packing Widgets</link>. But it is
896 fairly easy to understand. It simply tells GTK that the button is to
897 be placed in the window where it will be displayed. Note that a GTK
898 container can only contain one widget. There are other widgets, that
899 are described later, which are designed to layout multiple widgets in
903 <programlisting role="C">
904 gtk_container_add (GTK_CONTAINER (window), button);
907 <para>Now we have everything set up the way we want it to be. With all the
908 signal handlers in place, and the button placed in the window where it
909 should be, we ask GTK to "show" the widgets on the screen. The window
910 widget is shown last so the whole window will pop up at once rather
911 than seeing the window pop up, and then the button form inside of
912 it. Although with such a simple example, you'd never notice.</para>
914 <programlisting role="C">
915 gtk_widget_show (button);
917 gtk_widget_show (window);
920 <para>And of course, we call gtk_main() which waits for events to come from
921 the X server and will call on the widgets to emit signals when these
924 <programlisting role="C">
928 <para>And the final return. Control returns here after gtk_quit() is called.</para>
930 <programlisting role="C">
934 <para>Now, when we click the mouse button on a GTK button, the widget emits
935 a "clicked" signal. In order for us to use this information, our
936 program sets up a signal handler to catch that signal, which
937 dispatches the function of our choice. In our example, when the button
938 we created is "clicked", the hello() function is called with a NULL
939 argument, and then the next handler for this signal is called. This
940 calls the gtk_widget_destroy() function, passing it the window widget
941 as its argument, destroying the window widget. This causes the window
942 to emit the "destroy" signal, which is caught, and calls our destroy()
943 callback function, which simply exits GTK.</para>
945 <para>Another course of events is to use the window manager to kill the
946 window, which will cause the "delete_event" to be emitted. This will
947 call our "delete_event" handler. If we return TRUE here, the window
948 will be left as is and nothing will happen. Returning FALSE will cause
949 GTK to emit the "destroy" signal which of course calls the "destroy"
950 callback, exiting GTK.</para>
955 <!-- ***************************************************************** -->
956 <chapter id="ch-MovingOn">
957 <title>Moving On</title>
959 <!-- ----------------------------------------------------------------- -->
960 <sect1 id="sec-DataTypes">
961 <title>Data Types</title>
963 <para>There are a few things you probably noticed in the previous examples
964 that need explaining. The gint, gchar, etc. that you see are typedefs
965 to int and char, respectively, that are part of the GLib system. This
966 is done to get around that nasty dependency on the size of simple data
967 types when doing calculations.</para>
969 <para>A good example is "gint32" which will be typedef'd to a 32 bit integer
970 for any given platform, whether it be the 64 bit alpha, or the 32 bit
971 i386. The typedefs are very straightforward and intuitive. They are
972 all defined in <filename>glib/glib.h</filename> (which gets included from
973 <filename>gtk.h</filename>).</para>
975 <para>You'll also notice GTK's ability to use GtkWidget when the function
976 calls for a GtkObject. GTK is an object oriented design, and a widget
981 <!-- ----------------------------------------------------------------- -->
982 <sect1 id="sec-MoreOnSignalHandlers">
983 <title>More on Signal Handlers</title>
985 <para>Lets take another look at the gtk_signal_connect() declaration.</para>
987 <programlisting role="C">
988 gulong g_signal_connect( gpointer object,
991 gpointer func_data );
994 <para>Notice the gulong return value? This is a tag that identifies your
995 callback function. As stated above, you may have as many callbacks per
996 signal and per object as you need, and each will be executed in turn,
997 in the order they were attached.</para>
999 <para>This tag allows you to remove this callback from the list by using:</para>
1001 <programlisting role="C">
1002 void g_signal_handler_disconnect( gpointer object,
1006 <para>So, by passing in the widget you wish to remove the handler from, and
1007 the tag returned by one of the signal_connect functions, you can
1008 disconnect a signal handler.</para>
1010 <para>You can also temporarily disable signal handlers with the
1011 g_signal_handler_block() and g_signal_handler_unblock() family of
1014 <programlisting role="C">
1015 void g_signal_handler_block( gpointer object,
1018 void g_signal_handlers_block_by_func( gpointer object,
1022 void g_signal_handler_unblock( gpointer object,
1025 void g_signal_handlers_unblock_by_func( gpointer object,
1032 <!-- ----------------------------------------------------------------- -->
1033 <sect1 id="sec-AnUpgradedHelloWorld">
1034 <title>An Upgraded Hello World</title>
1036 <para>Let's take a look at a slightly improved <emphasis>helloworld</emphasis> with
1037 better examples of callbacks. This will also introduce us to our next
1038 topic, packing widgets.</para>
1043 <imagedata fileref="helloworld2.png" format="png">
1045 </inlinemediaobject>
1048 <programlisting role="C">
1049 <!-- example-start helloworld2 helloworld2.c -->
1051 #include <gtk/gtk.h>
1053 /* Our new improved callback. The data passed to this function
1054 * is printed to stdout. */
1055 void callback( GtkWidget *widget,
1058 g_print ("Hello again - %s was pressed\n", (gchar *) data);
1061 /* another callback */
1062 gint delete_event( GtkWidget *widget,
1073 /* GtkWidget is the storage type for widgets */
1078 /* This is called in all GTK applications. Arguments are parsed
1079 * from the command line and are returned to the application. */
1080 gtk_init (&argc, &argv);
1082 /* Create a new window */
1083 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1085 /* This is a new call, which just sets the title of our
1086 * new window to "Hello Buttons!" */
1087 gtk_window_set_title (GTK_WINDOW (window), "Hello Buttons!");
1089 /* Here we just set a handler for delete_event that immediately
1091 g_signal_connect (G_OBJECT (window), "delete_event",
1092 G_CALLBACK (delete_event), NULL);
1094 /* Sets the border width of the window. */
1095 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
1097 /* We create a box to pack widgets into. This is described in detail
1098 * in the "packing" section. The box is not really visible, it
1099 * is just used as a tool to arrange widgets. */
1100 box1 = gtk_hbox_new (FALSE, 0);
1102 /* Put the box into the main window. */
1103 gtk_container_add (GTK_CONTAINER (window), box1);
1105 /* Creates a new button with the label "Button 1". */
1106 button = gtk_button_new_with_label ("Button 1");
1108 /* Now when the button is clicked, we call the "callback" function
1109 * with a pointer to "button 1" as its argument */
1110 g_signal_connect (G_OBJECT (button), "clicked",
1111 G_CALLBACK (callback), "button 1");
1113 /* Instead of gtk_container_add, we pack this button into the invisible
1114 * box, which has been packed into the window. */
1115 gtk_box_pack_start (GTK_BOX(box1), button, TRUE, TRUE, 0);
1117 /* Always remember this step, this tells GTK that our preparation for
1118 * this button is complete, and it can now be displayed. */
1119 gtk_widget_show (button);
1121 /* Do these same steps again to create a second button */
1122 button = gtk_button_new_with_label ("Button 2");
1124 /* Call the same callback function with a different argument,
1125 * passing a pointer to "button 2" instead. */
1126 g_signal_connect (G_OBJECT (button), "clicked",
1127 G_CALLBACK (callback), "button 2");
1129 gtk_box_pack_start(GTK_BOX (box1), button, TRUE, TRUE, 0);
1131 /* The order in which we show the buttons is not really important, but I
1132 * recommend showing the window last, so it all pops up at once. */
1133 gtk_widget_show (button);
1135 gtk_widget_show (box1);
1137 gtk_widget_show (window);
1139 /* Rest in gtk_main and wait for the fun to begin! */
1144 <!-- example-end -->
1147 <para>Compile this program using the same linking arguments as our first
1148 example. You'll notice this time there is no easy way to exit the
1149 program, you have to use your window manager or command line to kill
1150 it. A good exercise for the reader would be to insert a third "Quit"
1151 button that will exit the program. You may also wish to play with the
1152 options to gtk_box_pack_start() while reading the next section. Try
1153 resizing the window, and observe the behavior.</para>
1158 <!-- ***************************************************************** -->
1159 <chapter id="ch-PackingWidgets">
1160 <title>Packing Widgets</title>
1162 <para>When creating an application, you'll want to put more than one widget
1163 inside a window. Our first <emphasis>helloworld</emphasis> example only used one
1164 widget so we could simply use a gtk_container_add() call to "pack" the
1165 widget into the window. But when you want to put more than one widget
1166 into a window, how do you control where that widget is positioned?
1167 This is where packing comes in.</para>
1169 <!-- ----------------------------------------------------------------- -->
1170 <sect1 id="sec-TheoryOfPackingBoxes">
1171 <title>Theory of Packing Boxes</title>
1173 <para>Most packing is done by creating boxes. These
1174 are invisible widget containers that we can pack our widgets into
1175 which come in two forms, a horizontal box, and a vertical box. When
1176 packing widgets into a horizontal box, the objects are inserted
1177 horizontally from left to right or right to left depending on the call
1178 used. In a vertical box, widgets are packed from top to bottom or vice
1179 versa. You may use any combination of boxes inside or beside other
1180 boxes to create the desired effect.</para>
1182 <para>To create a new horizontal box, we use a call to gtk_hbox_new(), and
1183 for vertical boxes, gtk_vbox_new(). The gtk_box_pack_start() and
1184 gtk_box_pack_end() functions are used to place objects inside of these
1185 containers. The gtk_box_pack_start() function will start at the top
1186 and work its way down in a vbox, and pack left to right in an hbox.
1187 gtk_box_pack_end() will do the opposite, packing from bottom to top in
1188 a vbox, and right to left in an hbox. Using these functions allows us
1189 to right justify or left justify our widgets and may be mixed in any
1190 way to achieve the desired effect. We will use gtk_box_pack_start() in
1191 most of our examples. An object may be another container or a
1192 widget. In fact, many widgets are actually containers themselves,
1193 including the button, but we usually only use a label inside a button.</para>
1195 <para>By using these calls, GTK knows where you want to place your widgets
1196 so it can do automatic resizing and other nifty things. There are also
1197 a number of options as to how your widgets should be packed. As you
1198 can imagine, this method gives us a quite a bit of flexibility when
1199 placing and creating widgets.</para>
1203 <!-- ----------------------------------------------------------------- -->
1204 <sect1 id="sec-DetailsOfBoxes">
1205 <title>Details of Boxes</title>
1207 <para>Because of this flexibility, packing boxes in GTK can be confusing at
1208 first. There are a lot of options, and it's not immediately obvious how
1209 they all fit together. In the end, however, there are basically five
1210 different styles.</para>
1215 <imagedata fileref="packbox1.png" format="png">
1217 </inlinemediaobject>
1220 <para>Each line contains one horizontal box (hbox) with several buttons. The
1221 call to gtk_box_pack is shorthand for the call to pack each of the
1222 buttons into the hbox. Each of the buttons is packed into the hbox the
1223 same way (i.e., same arguments to the gtk_box_pack_start() function).</para>
1225 <para>This is the declaration of the gtk_box_pack_start() function.</para>
1227 <programlisting role="C">
1228 void gtk_box_pack_start( GtkBox *box,
1235 <para>The first argument is the box you are packing the object into, the
1236 second is the object. The objects will all be buttons for now, so
1237 we'll be packing buttons into boxes.</para>
1239 <para>The expand argument to gtk_box_pack_start() and gtk_box_pack_end()
1240 controls whether the widgets are laid out in the box to fill in all
1241 the extra space in the box so the box is expanded to fill the area
1242 allotted to it (TRUE); or the box is shrunk to just fit the widgets
1243 (FALSE). Setting expand to FALSE will allow you to do right and left
1244 justification of your widgets. Otherwise, they will all expand to fit
1245 into the box, and the same effect could be achieved by using only one
1246 of gtk_box_pack_start() or gtk_box_pack_end().</para>
1248 <para>The fill argument to the gtk_box_pack functions control whether the
1249 extra space is allocated to the objects themselves (TRUE), or as extra
1250 padding in the box around these objects (FALSE). It only has an effect
1251 if the expand argument is also TRUE.</para>
1253 <para>When creating a new box, the function looks like this:</para>
1255 <programlisting role="C">
1256 GtkWidget *gtk_hbox_new ( gboolean homogeneous,
1260 <para>The homogeneous argument to gtk_hbox_new() (and the same for
1261 gtk_vbox_new()) controls whether each object in the box has the same
1262 size (i.e., the same width in an hbox, or the same height in a
1263 vbox). If it is set, the gtk_box_pack() routines function essentially
1264 as if the <literal>expand</literal> argument was always turned on.</para>
1266 <para>What's the difference between spacing (set when the box is created)
1267 and padding (set when elements are packed)? Spacing is added between
1268 objects, and padding is added on either side of an object. The
1269 following figure should make it clearer:</para>
1274 <imagedata fileref="packbox2.png" format="png">
1276 </inlinemediaobject>
1279 <para>Here is the code used to create the above images. I've commented it
1280 fairly heavily so I hope you won't have any problems following
1281 it. Compile it yourself and play with it.</para>
1285 <!-- ----------------------------------------------------------------- -->
1286 <sect1 id="sec-PackingDemonstrationProgram">
1287 <title>Packing Demonstration Program</title>
1289 <programlisting role="C">
1290 <!-- example-start packbox packbox.c -->
1292 #include <stdio.h>
1293 #include <stdlib.h>
1294 #include "gtk/gtk.h"
1296 gint delete_event( GtkWidget *widget,
1304 /* Make a new hbox filled with button-labels. Arguments for the
1305 * variables we're interested are passed in to this function.
1306 * We do not show the box, but do show everything inside. */
1307 GtkWidget *make_box( gboolean homogeneous,
1317 /* Create a new hbox with the appropriate homogeneous
1318 * and spacing settings */
1319 box = gtk_hbox_new (homogeneous, spacing);
1321 /* Create a series of buttons with the appropriate settings */
1322 button = gtk_button_new_with_label ("gtk_box_pack");
1323 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1324 gtk_widget_show (button);
1326 button = gtk_button_new_with_label ("(box,");
1327 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1328 gtk_widget_show (button);
1330 button = gtk_button_new_with_label ("button,");
1331 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1332 gtk_widget_show (button);
1334 /* Create a button with the label depending on the value of
1337 button = gtk_button_new_with_label ("TRUE,");
1339 button = gtk_button_new_with_label ("FALSE,");
1341 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1342 gtk_widget_show (button);
1344 /* This is the same as the button creation for "expand"
1345 * above, but uses the shorthand form. */
1346 button = gtk_button_new_with_label (fill ? "TRUE," : "FALSE,");
1347 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1348 gtk_widget_show (button);
1350 sprintf (padstr, "%d);", padding);
1352 button = gtk_button_new_with_label (padstr);
1353 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1354 gtk_widget_show (button);
1366 GtkWidget *separator;
1371 /* Our init, don't forget this! :) */
1372 gtk_init (&argc, &argv);
1375 fprintf (stderr, "usage: packbox num, where num is 1, 2, or 3.\n");
1376 /* This just does cleanup in GTK and exits with an exit status of 1. */
1380 which = atoi (argv[1]);
1382 /* Create our window */
1383 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1385 /* You should always remember to connect the delete_event signal
1386 * to the main window. This is very important for proper intuitive
1388 g_signal_connect (G_OBJECT (window), "delete_event",
1389 G_CALLBACK (delete_event), NULL);
1390 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
1392 /* We create a vertical box (vbox) to pack the horizontal boxes into.
1393 * This allows us to stack the horizontal boxes filled with buttons one
1394 * on top of the other in this vbox. */
1395 box1 = gtk_vbox_new (FALSE, 0);
1397 /* which example to show. These correspond to the pictures above. */
1400 /* create a new label. */
1401 label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1403 /* Align the label to the left side. We'll discuss this function and
1404 * others in the section on Widget Attributes. */
1405 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1407 /* Pack the label into the vertical box (vbox box1). Remember that
1408 * widgets added to a vbox will be packed one on top of the other in
1410 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1412 /* Show the label */
1413 gtk_widget_show (label);
1415 /* Call our make box function - homogeneous = FALSE, spacing = 0,
1416 * expand = FALSE, fill = FALSE, padding = 0 */
1417 box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1418 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1419 gtk_widget_show (box2);
1421 /* Call our make box function - homogeneous = FALSE, spacing = 0,
1422 * expand = TRUE, fill = FALSE, padding = 0 */
1423 box2 = make_box (FALSE, 0, TRUE, FALSE, 0);
1424 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1425 gtk_widget_show (box2);
1427 /* Args are: homogeneous, spacing, expand, fill, padding */
1428 box2 = make_box (FALSE, 0, TRUE, TRUE, 0);
1429 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1430 gtk_widget_show (box2);
1432 /* Creates a separator, we'll learn more about these later,
1433 * but they are quite simple. */
1434 separator = gtk_hseparator_new ();
1436 /* Pack the separator into the vbox. Remember each of these
1437 * widgets is being packed into a vbox, so they'll be stacked
1439 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1440 gtk_widget_show (separator);
1442 /* Create another new label, and show it. */
1443 label = gtk_label_new ("gtk_hbox_new (TRUE, 0);");
1444 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1445 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1446 gtk_widget_show (label);
1448 /* Args are: homogeneous, spacing, expand, fill, padding */
1449 box2 = make_box (TRUE, 0, TRUE, FALSE, 0);
1450 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1451 gtk_widget_show (box2);
1453 /* Args are: homogeneous, spacing, expand, fill, padding */
1454 box2 = make_box (TRUE, 0, TRUE, TRUE, 0);
1455 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1456 gtk_widget_show (box2);
1458 /* Another new separator. */
1459 separator = gtk_hseparator_new ();
1460 /* The last 3 arguments to gtk_box_pack_start are:
1461 * expand, fill, padding. */
1462 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1463 gtk_widget_show (separator);
1469 /* Create a new label, remember box1 is a vbox as created
1470 * near the beginning of main() */
1471 label = gtk_label_new ("gtk_hbox_new (FALSE, 10);");
1472 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1473 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1474 gtk_widget_show (label);
1476 /* Args are: homogeneous, spacing, expand, fill, padding */
1477 box2 = make_box (FALSE, 10, TRUE, FALSE, 0);
1478 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1479 gtk_widget_show (box2);
1481 /* Args are: homogeneous, spacing, expand, fill, padding */
1482 box2 = make_box (FALSE, 10, TRUE, TRUE, 0);
1483 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1484 gtk_widget_show (box2);
1486 separator = gtk_hseparator_new ();
1487 /* The last 3 arguments to gtk_box_pack_start are:
1488 * expand, fill, padding. */
1489 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1490 gtk_widget_show (separator);
1492 label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1493 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1494 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1495 gtk_widget_show (label);
1497 /* Args are: homogeneous, spacing, expand, fill, padding */
1498 box2 = make_box (FALSE, 0, TRUE, FALSE, 10);
1499 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1500 gtk_widget_show (box2);
1502 /* Args are: homogeneous, spacing, expand, fill, padding */
1503 box2 = make_box (FALSE, 0, TRUE, TRUE, 10);
1504 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1505 gtk_widget_show (box2);
1507 separator = gtk_hseparator_new ();
1508 /* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */
1509 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1510 gtk_widget_show (separator);
1515 /* This demonstrates the ability to use gtk_box_pack_end() to
1516 * right justify widgets. First, we create a new box as before. */
1517 box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1519 /* Create the label that will be put at the end. */
1520 label = gtk_label_new ("end");
1521 /* Pack it using gtk_box_pack_end(), so it is put on the right
1522 * side of the hbox created in the make_box() call. */
1523 gtk_box_pack_end (GTK_BOX (box2), label, FALSE, FALSE, 0);
1524 /* Show the label. */
1525 gtk_widget_show (label);
1527 /* Pack box2 into box1 (the vbox remember ? :) */
1528 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1529 gtk_widget_show (box2);
1531 /* A separator for the bottom. */
1532 separator = gtk_hseparator_new ();
1533 /* This explicitly sets the separator to 400 pixels wide by 5 pixels
1534 * high. This is so the hbox we created will also be 400 pixels wide,
1535 * and the "end" label will be separated from the other labels in the
1536 * hbox. Otherwise, all the widgets in the hbox would be packed as
1537 * close together as possible. */
1538 gtk_widget_set_size_request (separator, 400, 5);
1539 /* pack the separator into the vbox (box1) created near the start
1541 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1542 gtk_widget_show (separator);
1545 /* Create another new hbox.. remember we can use as many as we need! */
1546 quitbox = gtk_hbox_new (FALSE, 0);
1548 /* Our quit button. */
1549 button = gtk_button_new_with_label ("Quit");
1551 /* Setup the signal to terminate the program when the button is clicked */
1552 g_signal_connect_swapped (G_OBJECT (button), "clicked",
1553 G_CALLBACK (gtk_main_quit),
1555 /* Pack the button into the quitbox.
1556 * The last 3 arguments to gtk_box_pack_start are:
1557 * expand, fill, padding. */
1558 gtk_box_pack_start (GTK_BOX (quitbox), button, TRUE, FALSE, 0);
1559 /* pack the quitbox into the vbox (box1) */
1560 gtk_box_pack_start (GTK_BOX (box1), quitbox, FALSE, FALSE, 0);
1562 /* Pack the vbox (box1) which now contains all our widgets, into the
1564 gtk_container_add (GTK_CONTAINER (window), box1);
1566 /* And show everything left */
1567 gtk_widget_show (button);
1568 gtk_widget_show (quitbox);
1570 gtk_widget_show (box1);
1571 /* Showing the window last so everything pops up at once. */
1572 gtk_widget_show (window);
1574 /* And of course, our main function. */
1577 /* Control returns here when gtk_main_quit() is called, but not when
1578 * exit() is used. */
1582 <!-- example-end -->
1587 <!-- ----------------------------------------------------------------- -->
1588 <sect1 id="sec-PackingUsingTables">
1589 <title>Packing Using Tables</title>
1591 <para>Let's take a look at another way of packing - Tables. These can be
1592 extremely useful in certain situations.</para>
1594 <para>Using tables, we create a grid that we can place widgets in. The
1595 widgets may take up as many spaces as we specify.</para>
1597 <para>The first thing to look at, of course, is the gtk_table_new() function:</para>
1599 <programlisting role="C">
1600 GtkWidget *gtk_table_new( guint rows,
1602 gboolean homogeneous );
1605 <para>The first argument is the number of rows to make in the table, while
1606 the second, obviously, is the number of columns.</para>
1608 <para>The homogeneous argument has to do with how the table's boxes are
1609 sized. If homogeneous is TRUE, the table boxes are resized to the size
1610 of the largest widget in the table. If homogeneous is FALSE, the size
1611 of a table boxes is dictated by the tallest widget in its same row,
1612 and the widest widget in its column.</para>
1614 <para>The rows and columns are laid out from 0 to n, where n was the number
1615 specified in the call to gtk_table_new. So, if you specify rows = 2
1616 and columns = 2, the layout would look something like this:</para>
1618 <programlisting role="C">
1620 0+----------+----------+
1622 1+----------+----------+
1624 2+----------+----------+
1627 <para>Note that the coordinate system starts in the upper left hand corner.
1628 To place a widget into a box, use the following function:</para>
1630 <programlisting role="C">
1631 void gtk_table_attach( GtkTable *table,
1636 guint bottom_attach,
1637 GtkAttachOptions xoptions,
1638 GtkAttachOptions yoptions,
1643 <para>The first argument ("table") is the table you've created and the
1644 second ("child") the widget you wish to place in the table.</para>
1646 <para>The left and right attach arguments specify where to place the widget,
1647 and how many boxes to use. If you want a button in the lower right
1648 table entry of our 2x2 table, and want it to fill that entry <emphasis>only</emphasis>,
1649 left_attach would be = 1, right_attach = 2, top_attach = 1,
1650 bottom_attach = 2.</para>
1652 <para>Now, if you wanted a widget to take up the whole top row of our 2x2
1653 table, you'd use left_attach = 0, right_attach = 2, top_attach = 0,
1654 bottom_attach = 1.</para>
1656 <para>The xoptions and yoptions are used to specify packing options and may
1657 be bitwise OR'ed together to allow multiple options.</para>
1659 <para>These options are:</para>
1663 <term><literal>GTK_FILL</literal></term>
1664 <listitem><para>If the table box is larger than the widget, and
1665 <literal>GTK_FILL</literal> is specified, the widget will expand to use all the room
1671 <term><literal>GTK_SHRINK</literal></term>
1672 <listitem><para>If the table widget was allocated less space
1673 then was requested (usually by the user resizing the window), then the
1674 widgets would normally just be pushed off the bottom of the window and
1675 disappear. If <literal>GTK_SHRINK</literal> is specified, the widgets will shrink
1676 with the table.</para>
1681 <term><literal>GTK_EXPAND</literal></term>
1682 <listitem><para>This will cause the table to expand to use up
1683 any remaining space in the window.</para>
1688 <para>Padding is just like in boxes, creating a clear area around the widget
1689 specified in pixels.</para>
1691 <para>gtk_table_attach() has a <emphasis>lot</emphasis> of options.
1692 So, there's a shortcut:</para>
1694 <programlisting role="C">
1695 void gtk_table_attach_defaults( GtkTable *table,
1700 guint bottom_attach );
1703 <para>The X and Y options default to <literal>GTK_FILL | GTK_EXPAND</literal>,
1704 and X and Y padding are set to 0. The rest of the arguments are identical to the
1705 previous function.</para>
1707 <para>We also have gtk_table_set_row_spacing() and
1708 gtk_table_set_col_spacing(). These places spacing between the rows at
1709 the specified row or column.</para>
1711 <programlisting role="C">
1712 void gtk_table_set_row_spacing( GtkTable *table,
1719 <programlisting role="C">
1720 void gtk_table_set_col_spacing ( GtkTable *table,
1725 <para>Note that for columns, the space goes to the right of the column, and
1726 for rows, the space goes below the row.</para>
1728 <para>You can also set a consistent spacing of all rows and/or columns with:</para>
1730 <programlisting role="C">
1731 void gtk_table_set_row_spacings( GtkTable *table,
1737 <programlisting role="C">
1738 void gtk_table_set_col_spacings( GtkTable *table,
1742 <para>Note that with these calls, the last row and last column do not get
1747 <!-- ----------------------------------------------------------------- -->
1748 <sect1 id="sec-TablePackingExamples">
1749 <title>Table Packing Example</title>
1751 <para>Here we make a window with three buttons in a 2x2 table.
1752 The first two buttons will be placed in the upper row.
1753 A third, quit button, is placed in the lower row, spanning both columns.
1754 Which means it should look something like this:</para>
1759 <imagedata fileref="table.png" format="png">
1761 </inlinemediaobject>
1764 <para>Here's the source code:</para>
1766 <programlisting role="C">
1767 <!-- example-start table table.c -->
1769 #include <gtk/gtk.h>
1772 * The data passed to this function is printed to stdout */
1773 void callback( GtkWidget *widget,
1776 g_print ("Hello again - %s was pressed\n", (char *) data);
1779 /* This callback quits the program */
1780 gint delete_event( GtkWidget *widget,
1795 gtk_init (&argc, &argv);
1797 /* Create a new window */
1798 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1800 /* Set the window title */
1801 gtk_window_set_title (GTK_WINDOW (window), "Table");
1803 /* Set a handler for delete_event that immediately
1805 g_signal_connect (G_OBJECT (window), "delete_event",
1806 G_CALLBACK (delete_event), NULL);
1808 /* Sets the border width of the window. */
1809 gtk_container_set_border_width (GTK_CONTAINER (window), 20);
1811 /* Create a 2x2 table */
1812 table = gtk_table_new (2, 2, TRUE);
1814 /* Put the table in the main window */
1815 gtk_container_add (GTK_CONTAINER (window), table);
1817 /* Create first button */
1818 button = gtk_button_new_with_label ("button 1");
1820 /* When the button is clicked, we call the "callback" function
1821 * with a pointer to "button 1" as its argument */
1822 g_signal_connect (G_OBJECT (button), "clicked",
1823 G_CALLBACK (callback), (gpointer) "button 1");
1826 /* Insert button 1 into the upper left quadrant of the table */
1827 gtk_table_attach_defaults (GTK_TABLE (table), button, 0, 1, 0, 1);
1829 gtk_widget_show (button);
1831 /* Create second button */
1833 button = gtk_button_new_with_label ("button 2");
1835 /* When the button is clicked, we call the "callback" function
1836 * with a pointer to "button 2" as its argument */
1837 g_signal_connect (G_OBJECT (button), "clicked",
1838 G_CALLBACK (callback), (gpointer) "button 2");
1839 /* Insert button 2 into the upper right quadrant of the table */
1840 gtk_table_attach_defaults (GTK_TABLE (table), button, 1, 2, 0, 1);
1842 gtk_widget_show (button);
1844 /* Create "Quit" button */
1845 button = gtk_button_new_with_label ("Quit");
1847 /* When the button is clicked, we call the "delete_event" function
1848 * and the program exits */
1849 g_signal_connect (G_OBJECT (button), "clicked",
1850 G_CALLBACK (delete_event), NULL);
1852 /* Insert the quit button into the both
1853 * lower quadrants of the table */
1854 gtk_table_attach_defaults (GTK_TABLE (table), button, 0, 2, 1, 2);
1856 gtk_widget_show (button);
1858 gtk_widget_show (table);
1859 gtk_widget_show (window);
1865 <!-- example-end -->
1871 <!-- ***************************************************************** -->
1872 <chapter id="ch-WidgetOverview">
1873 <title>Widget Overview</title>
1875 <para>The general steps to creating a widget in GTK are:</para>
1877 <listitem><simpara> gtk_*_new() - one of various functions to create a new widget.
1878 These are all detailed in this section.</simpara>
1881 <listitem><simpara> Connect all signals and events we wish to use to the
1882 appropriate handlers.</simpara>
1885 <listitem><simpara> Set the attributes of the widget.</simpara>
1888 <listitem><simpara> Pack the widget into a container using the appropriate call
1889 such as gtk_container_add() or gtk_box_pack_start().</simpara>
1892 <listitem><simpara> gtk_widget_show() the widget.</simpara>
1896 <para>gtk_widget_show() lets GTK know that we are done setting the
1897 attributes of the widget, and it is ready to be displayed. You may
1898 also use gtk_widget_hide to make it disappear again. The order in
1899 which you show the widgets is not important, but I suggest showing the
1900 window last so the whole window pops up at once rather than seeing the
1901 individual widgets come up on the screen as they're formed. The
1902 children of a widget (a window is a widget too) will not be displayed
1903 until the window itself is shown using the gtk_widget_show() function.</para>
1905 <!-- ----------------------------------------------------------------- -->
1906 <sect1 id="sec-Casting">
1907 <title>Casting</title>
1909 <para>You'll notice as you go on that GTK uses a type casting system. This
1910 is always done using macros that both test the ability to cast the
1911 given item, and perform the cast. Some common ones you will see are:</para>
1913 <programlisting role="C">
1917 GTK_SIGNAL_FUNC (function)
1918 GTK_CONTAINER (container)
1923 <para>These are all used to cast arguments in functions. You'll see them in the
1924 examples, and can usually tell when to use them simply by looking at the
1925 function's declaration.</para>
1927 <para>As you can see below in the class hierarchy, all GtkWidgets are
1928 derived from the GObject base class. This means you can use a widget
1929 in any place the function asks for an object - simply use the
1930 <literal>G_OBJECT()</literal> macro.</para>
1932 <para>For example:</para>
1934 <programlisting role="C">
1935 g_signal_connect( G_OBJECT (button), "clicked",
1936 G_CALLBACK (callback_function), callback_data);
1939 <para>This casts the button into an object, and provides a cast for the
1940 function pointer to the callback.</para>
1942 <para>Many widgets are also containers. If you look in the class hierarchy
1943 below, you'll notice that many widgets derive from the Container
1944 class. Any one of these widgets may be used with the
1945 <literal>GTK_CONTAINER</literal> macro to pass them to functions that ask for
1948 <para>Unfortunately, these macros are not extensively covered in the
1949 tutorial, but I recommend taking a look through the GTK header
1950 files or the GTK API reference manual. It can be very educational. In fact,
1951 it's not difficult to learn how a widget works just by looking at the
1952 function declarations.</para>
1956 <!-- ----------------------------------------------------------------- -->
1957 <sect1 id="sec-WidgetHierarchy">
1958 <title>Widget Hierarchy</title>
1960 <para>For your reference, here is the class hierarchy tree used to implement
1961 widgets. (Deprecated widgets and auxiliary classes have been omitted.)</para>
1963 <programlisting role="C">
1970 | | | `GtkAccelLabel
1977 | | | | `GtkAspectFrame
1979 | | | | +GtkToggleButton
1980 | | | | | `GtkCheckButton
1981 | | | | | `GtkRadioButton
1982 | | | | `GtkOptionMenu
1984 | | | | +GtkMenuItem
1985 | | | | +GtkCheckMenuItem
1986 | | | | | `GtkRadioMenuItem
1987 | | | | +GtkImageMenuItem
1988 | | | | +GtkSeparatorMenuItem
1989 | | | | `GtkTearoffMenuItem
1992 | | | | | +GtkColorSelectionDialog
1993 | | | | | +GtkFileSelection
1994 | | | | | +GtkFontSelectionDialog
1995 | | | | | +GtkInputDialog
1996 | | | | | `GtkMessageDialog
2000 | | | +GtkScrolledWindow
2004 | | | | +GtkHButtonBox
2005 | | | | `GtkVButtonBox
2007 | | | | +GtkColorSelection
2008 | | | | +GtkFontSelection
2009 | | | | `GtkGammaCurve
2051 | +GtkCellRendererPixbuf
2052 | +GtkCellRendererText
2053 | +GtkCellRendererToggle
2061 <!-- ----------------------------------------------------------------- -->
2062 <sect1 id="sec-WidgetsWithoutWindows">
2063 <title>Widgets Without Windows</title>
2065 <para>The following widgets do not have an associated window. If you want to
2066 capture events, you'll have to use the EventBox. See the section on
2067 the <link linkend="sec-EventBox">EventBox</link> widget.</para>
2069 <programlisting role="C">
2096 <para>We'll further our exploration of GTK by examining each widget in turn,
2097 creating a few simple functions to display them. Another good source
2098 is the <literal>testgtk</literal> program that comes with GTK. It can be found in
2099 <filename>tests/testgtk.c</filename>.</para>
2104 <!-- !!! continue 2.0 review here !!! -->
2106 <!-- ***************************************************************** -->
2107 <chapter id="ch-ButtonWidget">
2108 <title>The Button Widget</title>
2110 <!-- ----------------------------------------------------------------- -->
2111 <sect1 id="sec-NormalButtons">
2112 <title>Normal Buttons</title>
2114 <para>We've almost seen all there is to see of the button widget. It's
2115 pretty simple. There are however two ways to create a button. You can
2116 use the gtk_button_new_with_label() to create a button with a label,
2117 or use gtk_button_new() to create a blank button. It's then up to you
2118 to pack a label or pixmap into this new button. To do this, create a
2119 new box, and then pack your objects into this box using the usual
2120 gtk_box_pack_start, and then use gtk_container_add to pack the box
2121 into the button.</para>
2123 <para>Here's an example of using gtk_button_new to create a button with a
2124 picture and a label in it. I've broken up the code to create a box
2125 from the rest so you can use it in your programs. There are further
2126 examples of using pixmaps later in the tutorial.</para>
2131 <imagedata fileref="buttons.png" format="png">
2133 </inlinemediaobject>
2136 <programlisting role="C">
2137 <!-- example-start buttons buttons.c -->
2139 #include <stdlib.h>
2140 #include <gtk/gtk.h>
2142 /* Create a new hbox with an image and a label packed into it
2143 * and return the box. */
2145 GtkWidget *xpm_label_box( GtkWidget *parent,
2146 gchar *xpm_filename,
2151 GtkWidget *pixmapwid;
2156 /* Create box for xpm and label */
2157 box1 = gtk_hbox_new (FALSE, 0);
2158 gtk_container_set_border_width (GTK_CONTAINER (box1), 2);
2160 /* Get the style of the button to get the
2161 * background color. */
2162 style = gtk_widget_get_style (parent);
2164 /* Now on to the xpm stuff */
2165 pixmap = gdk_pixmap_create_from_xpm (parent->window, &mask,
2166 &style->bg[GTK_STATE_NORMAL],
2168 pixmapwid = gtk_image_new_from_file (xpm_filename);
2170 /* Create a label for the button */
2171 label = gtk_label_new (label_text);
2173 /* Pack the pixmap and label into the box */
2174 gtk_box_pack_start (GTK_BOX (box1),
2175 pixmapwid, FALSE, FALSE, 3);
2177 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 3);
2179 gtk_widget_show (pixmapwid);
2180 gtk_widget_show (label);
2185 /* Our usual callback function */
2186 void callback( GtkWidget *widget,
2189 g_print ("Hello again - %s was pressed\n", (char *) data);
2195 /* GtkWidget is the storage type for widgets */
2200 gtk_init (&argc, &argv);
2202 /* Create a new window */
2203 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2205 gtk_window_set_title (GTK_WINDOW (window), "Pixmap'd Buttons!");
2207 /* It's a good idea to do this for all windows. */
2208 g_signal_connect (G_OBJECT (window), "destroy",
2209 G_CALLBACK (gtk_main_quit), NULL);
2211 g_signal_connect (G_OBJECT (window), "delete_event",
2212 G_CALLBACK (gtk_main_quit), NULL);
2214 /* Sets the border width of the window. */
2215 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
2216 gtk_widget_realize (window);
2218 /* Create a new button */
2219 button = gtk_button_new ();
2221 /* Connect the "clicked" signal of the button to our callback */
2222 g_signal_connect (G_OBJECT (button), "clicked",
2223 G_CALLBACK (callback), (gpointer) "cool button");
2225 /* This calls our box creating function */
2226 box1 = xpm_label_box(window, "info.xpm", "cool button");
2228 /* Pack and show all our widgets */
2229 gtk_widget_show (box1);
2231 gtk_container_add (GTK_CONTAINER (button), box1);
2233 gtk_widget_show (button);
2235 gtk_container_add (GTK_CONTAINER (window), button);
2237 gtk_widget_show (window);
2239 /* Rest in gtk_main and wait for the fun to begin! */
2244 <!-- example-end -->
2247 <para>The xpm_label_box function could be used to pack xpm's and labels into
2248 any widget that can be a container.</para>
2250 <para>Notice in <literal>xpm_label_box</literal> how there is a call to
2251 <literal>gtk_widget_get_style</literal>. Every widget has a "style", consisting of
2252 foreground and background colors for a variety of situations, font
2253 selection, and other graphics data relevant to a widget. These style
2254 values are defaulted in each widget, and are required by many GDK
2255 function calls, such as <literal>gdk_pixmap_create_from_xpm</literal>, which here is
2256 given the "normal" background color. The style data of widgets may
2257 be customized, using <link linkend="ch-GTKRCFiles">GTK's rc files</link>.</para>
2259 <para>Also notice the call to <literal>gtk_widget_realize</literal> after setting the
2260 window's border width. This function uses GDK to create the X
2261 windows related to the widget. The function is automatically called
2262 when you invoke <literal>gtk_widget_show</literal> for a widget, and so has not been
2263 shown in earlier examples. But the call to
2264 <literal>gdk_pixmap_create_from_xpm</literal> requires that its <literal>window</literal> argument
2265 refer to a real X window, so it is necessary to realize the widget
2266 before this GDK call.</para>
2268 <para>The Button widget has the following signals:</para>
2271 <listitem><simpara><literal>pressed</literal> - emitted when pointer button is pressed within
2272 Button widget</simpara>
2274 <listitem><simpara><literal>released</literal> - emitted when pointer button is released within
2275 Button widget</simpara>
2277 <listitem><simpara><literal>clicked</literal> - emitted when pointer button is pressed and then
2278 released within Button widget</simpara>
2280 <listitem><simpara><literal>enter</literal> - emitted when pointer enters Button widget</simpara>
2282 <listitem><simpara><literal>leave</literal> - emitted when pointer leaves Button widget</simpara>
2288 <!-- ----------------------------------------------------------------- -->
2289 <sect1 id="sec-ToggleButtons">
2290 <title>Toggle Buttons</title>
2292 <para>Toggle buttons are derived from normal buttons and are very similar,
2293 except they will always be in one of two states, alternated by a
2294 click. They may be depressed, and when you click again, they will pop
2295 back up. Click again, and they will pop back down.</para>
2297 <para>Toggle buttons are the basis for check buttons and radio buttons, as
2298 such, many of the calls used for toggle buttons are inherited by radio
2299 and check buttons. I will point these out when we come to them.</para>
2301 <para>Creating a new toggle button:</para>
2303 <programlisting role="C">
2304 GtkWidget *gtk_toggle_button_new( void );
2306 GtkWidget *gtk_toggle_button_new_with_label( gchar *label );
2309 <para>As you can imagine, these work identically to the normal button widget
2310 calls. The first creates a blank toggle button, and the second, a
2311 button with a label widget already packed into it.</para>
2313 <para>To retrieve the state of the toggle widget, including radio and check
2314 buttons, we use a construct as shown in our example below. This tests
2315 the state of the toggle, by accessing the <literal>active</literal> field of the
2316 toggle widget's structure, after first using the
2317 <literal>GTK_TOGGLE_BUTTON</literal> macro to cast the widget pointer into a toggle
2318 widget pointer. The signal of interest to us emitted by toggle
2319 buttons (the toggle button, check button, and radio button widgets) is
2320 the "toggled" signal. To check the state of these buttons, set up a
2321 signal handler to catch the toggled signal, and access the structure
2322 to determine its state. The callback will look something like:</para>
2324 <programlisting role="C">
2325 void toggle_button_callback (GtkWidget *widget, gpointer data)
2327 if (GTK_TOGGLE_BUTTON (widget)->active)
2329 /* If control reaches here, the toggle button is down */
2333 /* If control reaches here, the toggle button is up */
2338 <para>To force the state of a toggle button, and its children, the radio and
2339 check buttons, use this function:</para>
2341 <programlisting role="C">
2342 void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,
2346 <para>The above call can be used to set the state of the toggle button, and
2347 its children the radio and check buttons. Passing in your created
2348 button as the first argument, and a TRUE or FALSE for the second state
2349 argument to specify whether it should be down (depressed) or up
2350 (released). Default is up, or FALSE.</para>
2352 <para>Note that when you use the gtk_toggle_button_set_active() function, and
2353 the state is actually changed, it causes the "clicked" and "toggled"
2354 signals to be emitted from the button.</para>
2356 <programlisting role="C">
2357 gboolean gtk_toggle_button_get_active (GtkToggleButton *toggle_button);
2360 <para>This returns the current state of the toggle button as a boolean
2361 TRUE/FALSE value.</para>
2365 <!-- ----------------------------------------------------------------- -->
2366 <sect1 id="sec-CheckButtons">
2367 <title>Check Buttons</title>
2369 <para>Check buttons inherit many properties and functions from the the
2370 toggle buttons above, but look a little different. Rather than being
2371 buttons with text inside them, they are small squares with the text to
2372 the right of them. These are often used for toggling options on and
2373 off in applications.</para>
2375 <para>The two creation functions are similar to those of the normal button.</para>
2377 <programlisting role="C">
2378 GtkWidget *gtk_check_button_new( void );
2380 GtkWidget *gtk_check_button_new_with_label ( gchar *label );
2383 <para>The new_with_label function creates a check button with a label beside
2386 <para>Checking the state of the check button is identical to that of the
2387 toggle button.</para>
2391 <!-- ----------------------------------------------------------------- -->
2392 <sect1 id="sec-RadioButtons">
2393 <title>Radio Buttons</title>
2395 <para>Radio buttons are similar to check buttons except they are grouped so
2396 that only one may be selected/depressed at a time. This is good for
2397 places in your application where you need to select from a short list
2400 <para>Creating a new radio button is done with one of these calls:</para>
2402 <programlisting role="C">
2403 GtkWidget *gtk_radio_button_new( GSList *group );
2405 GtkWidget *gtk_radio_button_new_with_label( GSList *group,
2409 <para>You'll notice the extra argument to these calls. They require a group
2410 to perform their duty properly. The first call to
2411 gtk_radio_button_new or gtk_radio_button_new_with_label
2412 should pass NULL as the first argument. Then create a group using:</para>
2414 <programlisting role="C">
2415 GSList *gtk_radio_button_group( GtkRadioButton *radio_button );
2418 <para>The important thing to remember is that gtk_radio_button_group must be
2419 called for each new button added to the group, with the previous
2420 button passed in as an argument. The result is then passed into the
2421 next call to gtk_radio_button_new or
2422 gtk_radio_button_new_with_label. This allows a chain of buttons to be
2423 established. The example below should make this clear.</para>
2425 <para>You can shorten this slightly by using the following syntax, which
2426 removes the need for a variable to hold the list of buttons. This form
2427 is used in the example to create the third button:</para>
2429 <programlisting role="C">
2430 button2 = gtk_radio_button_new_with_label(
2431 gtk_radio_button_group (GTK_RADIO_BUTTON (button1)),
2435 <para>It is also a good idea to explicitly set which button should be the
2436 default depressed button with:</para>
2438 <programlisting role="C">
2439 void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,
2443 <para>This is described in the section on toggle buttons, and works in
2444 exactly the same way. Once the radio buttons are grouped together,
2445 only one of the group may be active at a time. If the user clicks on
2446 one radio button, and then on another, the first radio button will
2447 first emit a "toggled" signal (to report becoming inactive), and then
2448 the second will emit its "toggled" signal (to report becoming active).</para>
2450 <para>The following example creates a radio button group with three buttons.</para>
2455 <imagedata fileref="radiobuttons.png" format="png">
2457 </inlinemediaobject>
2460 <programlisting role="C">
2461 <!-- example-start radiobuttons radiobuttons.c -->
2463 #include <glib.h>
2464 #include <gtk/gtk.h>
2466 gint close_application( GtkWidget *widget,
2477 GtkWidget *window = NULL;
2481 GtkWidget *separator;
2484 gtk_init (&argc, &argv);
2486 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2488 g_signal_connect (G_OBJECT (window), "delete_event",
2489 G_CALLBACK (close_application),
2492 gtk_window_set_title (GTK_WINDOW (window), "radio buttons");
2493 gtk_container_set_border_width (GTK_CONTAINER (window), 0);
2495 box1 = gtk_vbox_new (FALSE, 0);
2496 gtk_container_add (GTK_CONTAINER (window), box1);
2497 gtk_widget_show (box1);
2499 box2 = gtk_vbox_new (FALSE, 10);
2500 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2501 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2502 gtk_widget_show (box2);
2504 button = gtk_radio_button_new_with_label (NULL, "button1");
2505 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2506 gtk_widget_show (button);
2508 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
2509 button = gtk_radio_button_new_with_label (group, "button2");
2510 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2511 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2512 gtk_widget_show (button);
2514 button = gtk_radio_button_new_with_label(
2515 gtk_radio_button_get_group (GTK_RADIO_BUTTON (button)),
2517 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2518 gtk_widget_show (button);
2520 separator = gtk_hseparator_new ();
2521 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
2522 gtk_widget_show (separator);
2524 box2 = gtk_vbox_new (FALSE, 10);
2525 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2526 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
2527 gtk_widget_show (box2);
2529 button = gtk_button_new_with_label ("close");
2530 g_signal_connect_swapped (G_OBJECT (button), "clicked",
2531 G_CALLBACK (close_application),
2533 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2534 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
2535 gtk_widget_grab_default (button);
2536 gtk_widget_show (button);
2537 gtk_widget_show (window);
2543 <!-- example-end -->
2546 <!-- TODO: check out gtk_radio_button_new_from_widget function - TRG -->
2551 <!-- ***************************************************************** -->
2552 <chapter id="ch-Adjustments">
2553 <title>Adjustments</title>
2555 <para>GTK has various widgets that can be visually adjusted by the user
2556 using the mouse or the keyboard, such as the range widgets, described
2557 in the <link linkend="ch-RangeWidgets">Range Widgets</link>
2558 section. There are also a few widgets that display some adjustable
2559 portion of a larger area of data, such as the text widget and the
2560 viewport widget.</para>
2562 <para>Obviously, an application needs to be able to react to changes the
2563 user makes in range widgets. One way to do this would be to have each
2564 widget emit its own type of signal when its adjustment changes, and
2565 either pass the new value to the signal handler, or require it to look
2566 inside the widget's data structure in order to ascertain the value.
2567 But you may also want to connect the adjustments of several widgets
2568 together, so that adjusting one adjusts the others. The most obvious
2569 example of this is connecting a scrollbar to a panning viewport or a
2570 scrolling text area. If each widget has its own way of setting or
2571 getting the adjustment value, then the programmer may have to write
2572 their own signal handlers to translate between the output of one
2573 widget's signal and the "input" of another's adjustment setting
2576 <para>GTK solves this problem using the Adjustment object, which is not a
2577 widget but a way for widgets to store and pass adjustment information
2578 in an abstract and flexible form. The most obvious use of Adjustment
2579 is to store the configuration parameters and values of range widgets,
2580 such as scrollbars and scale controls. However, since Adjustments are
2581 derived from Object, they have some special powers beyond those of
2582 normal data structures. Most importantly, they can emit signals, just
2583 like widgets, and these signals can be used not only to allow your
2584 program to react to user input on adjustable widgets, but also to
2585 propagate adjustment values transparently between adjustable widgets.</para>
2587 <para>You will see how adjustments fit in when you see the other widgets
2588 that incorporate them:
2589 <link linkend="sec-ProgressBars">Progress Bars</link>,
2590 <link linkend="sec-Viewports">Viewports</link>,
2591 <link linkend="sec-ScrolledWindows">Scrolled Windows</link>, and others.</para>
2593 <!-- ----------------------------------------------------------------- -->
2594 <sect1 id="sec-CreatingAnAdjustment">
2595 <title>Creating an Adjustment</title>
2597 <para>Many of the widgets which use adjustment objects do so automatically,
2598 but some cases will be shown in later examples where you may need to
2599 create one yourself. You create an adjustment using:</para>
2601 <programlisting role="C">
2602 GtkObject *gtk_adjustment_new( gfloat value,
2605 gfloat step_increment,
2606 gfloat page_increment,
2610 <para>The <literal>value</literal> argument is the initial value you want to give to the
2611 adjustment, usually corresponding to the topmost or leftmost position
2612 of an adjustable widget. The <literal>lower</literal> argument specifies the lowest
2613 value which the adjustment can hold. The <literal>step_increment</literal> argument
2614 specifies the "smaller" of the two increments by which the user can
2615 change the value, while the <literal>page_increment</literal> is the "larger" one.
2616 The <literal>page_size</literal> argument usually corresponds somehow to the visible
2617 area of a panning widget. The <literal>upper</literal> argument is used to represent
2618 the bottom most or right most coordinate in a panning widget's
2619 child. Therefore it is <emphasis>not</emphasis> always the largest number that
2620 <literal>value</literal> can take, since the <literal>page_size</literal> of such widgets is
2621 usually non-zero.</para>
2625 <!-- ----------------------------------------------------------------- -->
2626 <sect1 id="sec-UsingAdjustments">
2627 <title>Using Adjustments the Easy Way</title>
2629 <para>The adjustable widgets can be roughly divided into those which use and
2630 require specific units for these values and those which treat them as
2631 arbitrary numbers. The group which treats the values as arbitrary
2632 numbers includes the range widgets (scrollbars and scales, the
2633 progress bar widget, and the spin button widget). These widgets are
2634 all the widgets which are typically "adjusted" directly by the user
2635 with the mouse or keyboard. They will treat the <literal>lower</literal> and
2636 <literal>upper</literal> values of an adjustment as a range within which the user
2637 can manipulate the adjustment's <literal>value</literal>. By default, they will only
2638 modify the <literal>value</literal> of an adjustment.</para>
2640 <para>The other group includes the text widget, the viewport widget, the
2641 compound list widget, and the scrolled window widget. All of these
2642 widgets use pixel values for their adjustments. These are also all
2643 widgets which are typically "adjusted" indirectly using scrollbars.
2644 While all widgets which use adjustments can either create their own
2645 adjustments or use ones you supply, you'll generally want to let this
2646 particular category of widgets create its own adjustments. Usually,
2647 they will eventually override all the values except the <literal>value</literal>
2648 itself in whatever adjustments you give them, but the results are, in
2649 general, undefined (meaning, you'll have to read the source code to
2650 find out, and it may be different from widget to widget).</para>
2652 <para>Now, you're probably thinking, since text widgets and viewports insist
2653 on setting everything except the <literal>value</literal> of their adjustments,
2654 while scrollbars will <emphasis>only</emphasis> touch the adjustment's <literal>value</literal>, if
2655 you <emphasis>share</emphasis> an adjustment object between a scrollbar and a text
2656 widget, manipulating the scrollbar will automagically adjust the text
2657 widget? Of course it will! Just like this:</para>
2659 <programlisting role="C">
2660 /* creates its own adjustments */
2661 text = gtk_text_new (NULL, NULL);
2662 /* uses the newly-created adjustment for the scrollbar as well */
2663 vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
2668 <!-- ----------------------------------------------------------------- -->
2669 <sect1 id="sec-AdjustmentInternals">
2670 <title>Adjustment Internals</title>
2672 <para>Ok, you say, that's nice, but what if I want to create my own handlers
2673 to respond when the user adjusts a range widget or a spin button, and
2674 how do I get at the value of the adjustment in these handlers? To
2675 answer these questions and more, let's start by taking a look at
2676 <literal>struct _GtkAdjustment</literal> itself:</para>
2678 <programlisting role="C">
2679 struct _GtkAdjustment
2686 gfloat step_increment;
2687 gfloat page_increment;
2692 <para>The first thing you should know is that there aren't any handy-dandy
2693 macros or accessor functions for getting the <literal>value</literal> out of an
2694 Adjustment, so you'll have to (horror of horrors) do it like a
2695 <emphasis>real</emphasis> C programmer. Don't worry - the <literal>GTK_ADJUSTMENT
2696 (Object)</literal> macro does run-time type checking (as do all the GTK
2697 type-casting macros, actually).</para>
2699 <para>Since, when you set the <literal>value</literal> of an adjustment, you generally
2700 want the change to be reflected by every widget that uses this
2701 adjustment, GTK provides this convenience function to do this:</para>
2703 <programlisting role="C">
2704 void gtk_adjustment_set_value( GtkAdjustment *adjustment,
2708 <para>As mentioned earlier, Adjustment is a subclass of Object just
2709 like all the various widgets, and thus it is able to emit signals.
2710 This is, of course, why updates happen automagically when you share an
2711 adjustment object between a scrollbar and another adjustable widget;
2712 all adjustable widgets connect signal handlers to their adjustment's
2713 <literal>value_changed</literal> signal, as can your program. Here's the definition
2714 of this signal in <literal>struct _GtkAdjustmentClass</literal>:</para>
2716 <programlisting role="C">
2717 void (* value_changed) (GtkAdjustment *adjustment);
2720 <para>The various widgets that use the Adjustment object will emit this
2721 signal on an adjustment whenever they change its value. This happens
2722 both when user input causes the slider to move on a range widget, as
2723 well as when the program explicitly changes the value with
2724 <literal>gtk_adjustment_set_value()</literal>. So, for example, if you have a scale
2725 widget, and you want to change the rotation of a picture whenever its
2726 value changes, you would create a callback like this:</para>
2728 <programlisting role="C">
2729 void cb_rotate_picture (GtkAdjustment *adj, GtkWidget *picture)
2731 set_picture_rotation (picture, adj->value);
2735 <para>and connect it to the scale widget's adjustment like this:</para>
2737 <programlisting role="C">
2738 gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
2739 GTK_SIGNAL_FUNC (cb_rotate_picture), picture);
2742 <para>What about when a widget reconfigures the <literal>upper</literal> or <literal>lower</literal>
2743 fields of its adjustment, such as when a user adds more text to a text
2744 widget? In this case, it emits the <literal>changed</literal> signal, which looks
2747 <programlisting role="C">
2748 void (* changed) (GtkAdjustment *adjustment);
2751 <para>Range widgets typically connect a handler to this signal, which
2752 changes their appearance to reflect the change - for example, the size
2753 of the slider in a scrollbar will grow or shrink in inverse proportion
2754 to the difference between the <literal>lower</literal> and <literal>upper</literal> values of its
2757 <para>You probably won't ever need to attach a handler to this signal,
2758 unless you're writing a new type of range widget. However, if you
2759 change any of the values in a Adjustment directly, you should emit
2760 this signal on it to reconfigure whatever widgets are using it, like
2763 <programlisting role="C">
2764 gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");
2767 <para>Now go forth and adjust!</para>
2772 <!-- ***************************************************************** -->
2773 <chapter id="ch-RangeWidgets">
2774 <title>Range Widgets</title>
2776 <para>The category of range widgets includes the ubiquitous scrollbar widget
2777 and the less common "scale" widget. Though these two types of widgets
2778 are generally used for different purposes, they are quite similar in
2779 function and implementation. All range widgets share a set of common
2780 graphic elements, each of which has its own X window and receives
2781 events. They all contain a "trough" and a "slider" (what is sometimes
2782 called a "thumbwheel" in other GUI environments). Dragging the slider
2783 with the pointer moves it back and forth within the trough, while
2784 clicking in the trough advances the slider towards the location of the
2785 click, either completely, or by a designated amount, depending on
2786 which mouse button is used.</para>
2788 <para>As mentioned in <link linkend="ch-Adjustments">Adjustments</link> above,
2789 all range widgets are associated with an adjustment object, from which
2790 they calculate the length of the slider and its position within the
2791 trough. When the user manipulates the slider, the range widget will
2792 change the value of the adjustment.</para>
2794 <!-- ----------------------------------------------------------------- -->
2795 <sect1 id="sec-ScrollbarWidgets">
2796 <title>Scrollbar Widgets</title>
2798 <para>These are your standard, run-of-the-mill scrollbars. These should be
2799 used only for scrolling some other widget, such as a list, a text box,
2800 or a viewport (and it's generally easier to use the scrolled window
2801 widget in most cases). For other purposes, you should use scale
2802 widgets, as they are friendlier and more featureful.</para>
2804 <para>There are separate types for horizontal and vertical scrollbars.
2805 There really isn't much to say about these. You create them with the
2806 following functions, defined in <literal><gtk/gtkhscrollbar.h></literal>
2807 and <literal><gtk/gtkvscrollbar.h></literal>:</para>
2809 <programlisting role="C">
2810 GtkWidget *gtk_hscrollbar_new( GtkAdjustment *adjustment );
2812 GtkWidget *gtk_vscrollbar_new( GtkAdjustment *adjustment );
2815 <para>and that's about it (if you don't believe me, look in the header
2816 files!). The <literal>adjustment</literal> argument can either be a pointer to an
2817 existing Adjustment, or NULL, in which case one will be created for
2818 you. Specifying NULL might actually be useful in this case, if you
2819 wish to pass the newly-created adjustment to the constructor function
2820 of some other widget which will configure it for you, such as a text
2825 <!-- ----------------------------------------------------------------- -->
2826 <sect1 id="sec-ScaleWidgets">
2827 <title>Scale Widgets</title>
2829 <para>Scale widgets are used to allow the user to visually select and
2830 manipulate a value within a specific range. You might want to use a
2831 scale widget, for example, to adjust the magnification level on a
2832 zoomed preview of a picture, or to control the brightness of a color,
2833 or to specify the number of minutes of inactivity before a screensaver
2834 takes over the screen.</para>
2836 <!-- ----------------------------------------------------------------- -->
2838 <title>Creating a Scale Widget</title>
2840 <para>As with scrollbars, there are separate widget types for horizontal and
2841 vertical scale widgets. (Most programmers seem to favour horizontal
2842 scale widgets.) Since they work essentially the same way, there's no
2843 need to treat them separately here. The following functions, defined
2844 in <literal><gtk/gtkvscale.h></literal> and
2845 <literal><gtk/gtkhscale.h></literal>, create vertical and horizontal scale
2846 widgets, respectively:</para>
2848 <programlisting role="C">
2849 GtkWidget *gtk_vscale_new( GtkAdjustment *adjustment );
2851 GtkWidget *gtk_hscale_new( GtkAdjustment *adjustment );
2854 <para>The <literal>adjustment</literal> argument can either be an adjustment which has
2855 already been created with <literal>gtk_adjustment_new()</literal>, or <literal>NULL</literal>, in
2856 which case, an anonymous Adjustment is created with all of its
2857 values set to <literal>0.0</literal> (which isn't very useful in this case). In
2858 order to avoid confusing yourself, you probably want to create your
2859 adjustment with a <literal>page_size</literal> of <literal>0.0</literal> so that its <literal>upper</literal>
2860 value actually corresponds to the highest value the user can select.
2861 (If you're <emphasis>already</emphasis> thoroughly confused, read the section on <link
2862 linkend="ch-Adjustments">Adjustments</link> again for an explanation of
2863 what exactly adjustments do and how to create and manipulate them.)</para>
2867 <!-- ----------------------------------------------------------------- -->
2869 <title>Functions and Signals (well, functions, at least)</title>
2871 <para>Scale widgets can display their current value as a number beside the
2872 trough. The default behaviour is to show the value, but you can change
2873 this with this function:</para>
2875 <programlisting role="C">
2876 void gtk_scale_set_draw_value( GtkScale *scale,
2880 <para>As you might have guessed, <literal>draw_value</literal> is either <literal>TRUE</literal> or
2881 <literal>FALSE</literal>, with predictable consequences for either one.</para>
2883 <para>The value displayed by a scale widget is rounded to one decimal point
2884 by default, as is the <literal>value</literal> field in its GtkAdjustment. You can
2885 change this with:</para>
2887 <programlisting role="C">
2888 void gtk_scale_set_digits( GtkScale *scale,
2892 <para>where <literal>digits</literal> is the number of decimal places you want. You can
2893 set <literal>digits</literal> to anything you like, but no more than 13 decimal
2894 places will actually be drawn on screen.</para>
2896 <para>Finally, the value can be drawn in different positions
2897 relative to the trough:</para>
2899 <programlisting role="C">
2900 void gtk_scale_set_value_pos( GtkScale *scale,
2901 GtkPositionType pos );
2904 <para>The argument <literal>pos</literal> is of type <literal>GtkPositionType</literal>, which is
2905 defined in <literal><gtk/gtkenums.h></literal>, and can take one of the
2906 following values:</para>
2908 <programlisting role="C">
2915 <para>If you position the value on the "side" of the trough (e.g., on the
2916 top or bottom of a horizontal scale widget), then it will follow the
2917 slider up and down the trough.</para>
2919 <para>All the preceding functions are defined in
2920 <literal><gtk/gtkscale.h></literal>. The header files for all GTK widgets
2921 are automatically included when you include
2922 <literal><gtk/gtk.h></literal>. But you should look over the header files
2923 of all widgets that interest you,</para>
2928 <!-- ----------------------------------------------------------------- -->
2929 <sect1 id="sec-CommonRangeFunctions">
2930 <title>Common Range Functions</title>
2932 <para>The Range widget class is fairly complicated internally, but, like
2933 all the "base class" widgets, most of its complexity is only
2934 interesting if you want to hack on it. Also, almost all of the
2935 functions and signals it defines are only really used in writing
2936 derived widgets. There are, however, a few useful functions that are
2937 defined in <literal><gtk/gtkrange.h></literal> and will work on all range
2940 <!-- ----------------------------------------------------------------- -->
2942 <title>Setting the Update Policy</title>
2944 <para>The "update policy" of a range widget defines at what points during
2945 user interaction it will change the <literal>value</literal> field of its
2946 Adjustment and emit the "value_changed" signal on this
2947 Adjustment. The update policies, defined in
2948 <literal><gtk/gtkenums.h></literal> as type <literal>enum GtkUpdateType</literal>,
2952 <listitem><simpara>GTK_UPDATE_CONTINUOUS - This is the default. The
2953 "value_changed" signal is emitted continuously, i.e., whenever the
2954 slider is moved by even the tiniest amount.</simpara>
2957 <listitem><simpara>GTK_UPDATE_DISCONTINUOUS - The "value_changed" signal is
2958 only emitted once the slider has stopped moving and the user has
2959 released the mouse button.</simpara>
2962 <listitem><simpara>GTK_UPDATE_DELAYED - The "value_changed" signal is emitted
2963 when the user releases the mouse button, or if the slider stops moving
2964 for a short period of time.</simpara>
2968 <para>The update policy of a range widget can be set by casting it using the
2969 <literal>GTK_RANGE (Widget)</literal> macro and passing it to this function:</para>
2971 <programlisting role="C">
2972 void gtk_range_set_update_policy( GtkRange *range,
2973 GtkUpdateType policy);
2978 <!-- ----------------------------------------------------------------- -->
2980 <title>Getting and Setting Adjustments</title>
2982 <para>Getting and setting the adjustment for a range widget "on the fly" is
2983 done, predictably, with:</para>
2985 <programlisting role="C">
2986 GtkAdjustment* gtk_range_get_adjustment( GtkRange *range );
2988 void gtk_range_set_adjustment( GtkRange *range,
2989 GtkAdjustment *adjustment );
2992 <para><literal>gtk_range_get_adjustment()</literal> returns a pointer to the adjustment to
2993 which <literal>range</literal> is connected.</para>
2995 <para><literal>gtk_range_set_adjustment()</literal> does absolutely nothing if you pass it
2996 the adjustment that <literal>range</literal> is already using, regardless of whether
2997 you changed any of its fields or not. If you pass it a new
2998 Adjustment, it will unreference the old one if it exists (possibly
2999 destroying it), connect the appropriate signals to the new one, and
3000 call the private function <literal>gtk_range_adjustment_changed()</literal>, which
3001 will (or at least, is supposed to...) recalculate the size and/or
3002 position of the slider and redraw if necessary. As mentioned in the
3003 section on adjustments, if you wish to reuse the same Adjustment,
3004 when you modify its values directly, you should emit the "changed"
3005 signal on it, like this:</para>
3007 <programlisting role="C">
3008 gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");
3014 <!-- ----------------------------------------------------------------- -->
3015 <sect1 id="sec-KeyAndMouseBindings">
3016 <title>Key and Mouse bindings</title>
3018 <para>All of the GTK range widgets react to mouse clicks in more or less
3019 the same way. Clicking button-1 in the trough will cause its
3020 adjustment's <literal>page_increment</literal> to be added or subtracted from its
3021 <literal>value</literal>, and the slider to be moved accordingly. Clicking mouse
3022 button-2 in the trough will jump the slider to the point at which the
3023 button was clicked. Clicking any button on a scrollbar's arrows will
3024 cause its adjustment's value to change <literal>step_increment</literal> at a time.</para>
3026 <para>It may take a little while to get used to, but by default, scrollbars
3027 as well as scale widgets can take the keyboard focus in GTK. If you
3028 think your users will find this too confusing, you can always disable
3029 this by unsetting the <literal>GTK_CAN_FOCUS</literal> flag on the scrollbar, like
3032 <programlisting role="C">
3033 GTK_WIDGET_UNSET_FLAGS (scrollbar, GTK_CAN_FOCUS);
3036 <para>The key bindings (which are, of course, only active when the widget
3037 has focus) are slightly different between horizontal and vertical
3038 range widgets, for obvious reasons. They are also not quite the same
3039 for scale widgets as they are for scrollbars, for somewhat less
3040 obvious reasons (possibly to avoid confusion between the keys for
3041 horizontal and vertical scrollbars in scrolled windows, where both
3042 operate on the same area).</para>
3044 <!-- ----------------------------------------------------------------- -->
3046 <title>Vertical Range Widgets</title>
3048 <para>All vertical range widgets can be operated with the up and down arrow
3049 keys, as well as with the <literal>Page Up</literal> and <literal>Page Down</literal> keys. The
3050 arrows move the slider up and down by <literal>step_increment</literal>, while
3051 <literal>Page Up</literal> and <literal>Page Down</literal> move it by <literal>page_increment</literal>.</para>
3053 <para>The user can also move the slider all the way to one end or the other
3054 of the trough using the keyboard. With the VScale widget, this is
3055 done with the <literal>Home</literal> and <literal>End</literal> keys, whereas with the
3056 VScrollbar widget, this is done by typing <literal>Control-Page Up</literal>
3057 and <literal>Control-Page Down</literal>.</para>
3061 <!-- ----------------------------------------------------------------- -->
3063 <title>Horizontal Range Widgets</title>
3065 <para>The left and right arrow keys work as you might expect in these
3066 widgets, moving the slider back and forth by <literal>step_increment</literal>. The
3067 <literal>Home</literal> and <literal>End</literal> keys move the slider to the ends of the trough.
3068 For the HScale widget, moving the slider by <literal>page_increment</literal> is
3069 accomplished with <literal>Control-Left</literal> and <literal>Control-Right</literal>,
3070 while for HScrollbar, it's done with <literal>Control-Home</literal> and
3071 <literal>Control-End</literal>.</para>
3076 <!-- ----------------------------------------------------------------- -->
3077 <sect1 id="sec-RangeWidgetsExample">
3078 <title>Example</title>
3080 <para>This example is a somewhat modified version of the "range controls"
3081 test from <literal>testgtk.c</literal>. It basically puts up a window with three
3082 range widgets all connected to the same adjustment, and a couple of
3083 controls for adjusting some of the parameters mentioned above and in
3084 the section on adjustments, so you can see how they affect the way
3085 these widgets work for the user.</para>
3090 <imagedata fileref="rangewidgets.png" format="png">
3092 </inlinemediaobject>
3095 <programlisting role="C">
3096 <!-- example-start rangewidgets rangewidgets.c -->
3098 #include <gtk/gtk.h>
3100 GtkWidget *hscale, *vscale;
3102 void cb_pos_menu_select( GtkWidget *item,
3103 GtkPositionType pos )
3105 /* Set the value position on both scale widgets */
3106 gtk_scale_set_value_pos (GTK_SCALE (hscale), pos);
3107 gtk_scale_set_value_pos (GTK_SCALE (vscale), pos);
3110 void cb_update_menu_select( GtkWidget *item,
3111 GtkUpdateType policy )
3113 /* Set the update policy for both scale widgets */
3114 gtk_range_set_update_policy (GTK_RANGE (hscale), policy);
3115 gtk_range_set_update_policy (GTK_RANGE (vscale), policy);
3118 void cb_digits_scale( GtkAdjustment *adj )
3120 /* Set the number of decimal places to which adj->value is rounded */
3121 gtk_scale_set_digits (GTK_SCALE (hscale), (gint) adj->value);
3122 gtk_scale_set_digits (GTK_SCALE (vscale), (gint) adj->value);
3125 void cb_page_size( GtkAdjustment *get,
3126 GtkAdjustment *set )
3128 /* Set the page size and page increment size of the sample
3129 * adjustment to the value specified by the "Page Size" scale */
3130 set->page_size = get->value;
3131 set->page_increment = get->value;
3133 /* This sets the adjustment and makes it emit the "changed" signal to
3134 reconfigure all the widgets that are attached to this signal. */
3135 gtk_adjustment_set_value (set, CLAMP (set->value,
3137 (set->upper - set->page_size)));
3140 void cb_draw_value( GtkToggleButton *button )
3142 /* Turn the value display on the scale widgets off or on depending
3143 * on the state of the checkbutton */
3144 gtk_scale_set_draw_value (GTK_SCALE (hscale), button->active);
3145 gtk_scale_set_draw_value (GTK_SCALE (vscale), button->active);
3148 /* Convenience functions */
3150 GtkWidget *make_menu_item (gchar *name,
3156 item = gtk_menu_item_new_with_label (name);
3157 g_signal_connect (G_OBJECT (item), "activate",
3159 gtk_widget_show (item);
3164 void scale_set_default_values( GtkScale *scale )
3166 gtk_range_set_update_policy (GTK_RANGE (scale),
3167 GTK_UPDATE_CONTINUOUS);
3168 gtk_scale_set_digits (scale, 1);
3169 gtk_scale_set_value_pos (scale, GTK_POS_TOP);
3170 gtk_scale_set_draw_value (scale, TRUE);
3173 /* makes the sample window */
3175 void create_range_controls( void )
3178 GtkWidget *box1, *box2, *box3;
3180 GtkWidget *scrollbar;
3181 GtkWidget *separator;
3182 GtkWidget *opt, *menu, *item;
3185 GtkObject *adj1, *adj2;
3187 /* Standard window-creating stuff */
3188 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3189 g_signal_connect (G_OBJECT (window), "destroy",
3190 G_CALLBACK (gtk_main_quit),
3192 gtk_window_set_title (GTK_WINDOW (window), "range controls");
3194 box1 = gtk_vbox_new (FALSE, 0);
3195 gtk_container_add (GTK_CONTAINER (window), box1);
3196 gtk_widget_show (box1);
3198 box2 = gtk_hbox_new (FALSE, 10);
3199 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3200 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3201 gtk_widget_show (box2);
3203 /* value, lower, upper, step_increment, page_increment, page_size */
3204 /* Note that the page_size value only makes a difference for
3205 * scrollbar widgets, and the highest value you'll get is actually
3206 * (upper - page_size). */
3207 adj1 = gtk_adjustment_new (0.0, 0.0, 101.0, 0.1, 1.0, 1.0);
3209 vscale = gtk_vscale_new (GTK_ADJUSTMENT (adj1));
3210 scale_set_default_values (GTK_SCALE (vscale));
3211 gtk_box_pack_start (GTK_BOX (box2), vscale, TRUE, TRUE, 0);
3212 gtk_widget_show (vscale);
3214 box3 = gtk_vbox_new (FALSE, 10);
3215 gtk_box_pack_start (GTK_BOX (box2), box3, TRUE, TRUE, 0);
3216 gtk_widget_show (box3);
3218 /* Reuse the same adjustment */
3219 hscale = gtk_hscale_new (GTK_ADJUSTMENT (adj1));
3220 gtk_widget_set_size_request (GTK_WIDGET (hscale), 200, -1);
3221 scale_set_default_values (GTK_SCALE (hscale));
3222 gtk_box_pack_start (GTK_BOX (box3), hscale, TRUE, TRUE, 0);
3223 gtk_widget_show (hscale);
3225 /* Reuse the same adjustment again */
3226 scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adj1));
3227 /* Notice how this causes the scales to always be updated
3228 * continuously when the scrollbar is moved */
3229 gtk_range_set_update_policy (GTK_RANGE (scrollbar),
3230 GTK_UPDATE_CONTINUOUS);
3231 gtk_box_pack_start (GTK_BOX (box3), scrollbar, TRUE, TRUE, 0);
3232 gtk_widget_show (scrollbar);
3234 box2 = gtk_hbox_new (FALSE, 10);
3235 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3236 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3237 gtk_widget_show (box2);
3239 /* A checkbutton to control whether the value is displayed or not */
3240 button = gtk_check_button_new_with_label("Display value on scale widgets");
3241 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3242 g_signal_connect (G_OBJECT (button), "toggled",
3243 G_CALLBACK (cb_draw_value), NULL);
3244 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
3245 gtk_widget_show (button);
3247 box2 = gtk_hbox_new (FALSE, 10);
3248 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3250 /* An option menu to change the position of the value */
3251 label = gtk_label_new ("Scale Value Position:");
3252 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
3253 gtk_widget_show (label);
3255 opt = gtk_option_menu_new ();
3256 menu = gtk_menu_new ();
3258 item = make_menu_item ("Top",
3259 G_CALLBACK (cb_pos_menu_select),
3260 GINT_TO_POINTER (GTK_POS_TOP));
3261 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3263 item = make_menu_item ("Bottom", G_CALLBACK (cb_pos_menu_select),
3264 GINT_TO_POINTER (GTK_POS_BOTTOM));
3265 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3267 item = make_menu_item ("Left", G_CALLBACK (cb_pos_menu_select),
3268 GINT_TO_POINTER (GTK_POS_LEFT));
3269 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3271 item = make_menu_item ("Right", G_CALLBACK (cb_pos_menu_select),
3272 GINT_TO_POINTER (GTK_POS_RIGHT));
3273 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3275 gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
3276 gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
3277 gtk_widget_show (opt);
3279 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3280 gtk_widget_show (box2);
3282 box2 = gtk_hbox_new (FALSE, 10);
3283 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3285 /* Yet another option menu, this time for the update policy of the
3287 label = gtk_label_new ("Scale Update Policy:");
3288 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
3289 gtk_widget_show (label);
3291 opt = gtk_option_menu_new ();
3292 menu = gtk_menu_new ();
3294 item = make_menu_item ("Continuous",
3295 G_CALLBACK (cb_update_menu_select),
3296 GINT_TO_POINTER (GTK_UPDATE_CONTINUOUS));
3297 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3299 item = make_menu_item ("Discontinuous",
3300 G_CALLBACK (cb_update_menu_select),
3301 GINT_TO_POINTER (GTK_UPDATE_DISCONTINUOUS));
3302 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3304 item = make_menu_item ("Delayed",
3305 G_CALLBACK (cb_update_menu_select),
3306 GINT_TO_POINTER (GTK_UPDATE_DELAYED));
3307 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3309 gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
3310 gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
3311 gtk_widget_show (opt);
3313 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3314 gtk_widget_show (box2);
3316 box2 = gtk_hbox_new (FALSE, 10);
3317 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3319 /* An HScale widget for adjusting the number of digits on the
3321 label = gtk_label_new ("Scale Digits:");
3322 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
3323 gtk_widget_show (label);
3325 adj2 = gtk_adjustment_new (1.0, 0.0, 5.0, 1.0, 1.0, 0.0);
3326 g_signal_connect (G_OBJECT (adj2), "value_changed",
3327 G_CALLBACK (cb_digits_scale), NULL);
3328 scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
3329 gtk_scale_set_digits (GTK_SCALE (scale), 0);
3330 gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
3331 gtk_widget_show (scale);
3333 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3334 gtk_widget_show (box2);
3336 box2 = gtk_hbox_new (FALSE, 10);
3337 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3339 /* And, one last HScale widget for adjusting the page size of the
3341 label = gtk_label_new ("Scrollbar Page Size:");
3342 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
3343 gtk_widget_show (label);
3345 adj2 = gtk_adjustment_new (1.0, 1.0, 101.0, 1.0, 1.0, 0.0);
3346 g_signal_connect (G_OBJECT (adj2), "value_changed",
3347 G_CALLBACK (cb_page_size), adj1);
3348 scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
3349 gtk_scale_set_digits (GTK_SCALE (scale), 0);
3350 gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
3351 gtk_widget_show (scale);
3353 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3354 gtk_widget_show (box2);
3356 separator = gtk_hseparator_new ();
3357 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
3358 gtk_widget_show (separator);
3360 box2 = gtk_vbox_new (FALSE, 10);
3361 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3362 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
3363 gtk_widget_show (box2);
3365 button = gtk_button_new_with_label ("Quit");
3366 g_signal_connect_swapped (G_OBJECT (button), "clicked",
3367 G_CALLBACK (gtk_main_quit),
3369 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
3370 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
3371 gtk_widget_grab_default (button);
3372 gtk_widget_show (button);
3374 gtk_widget_show (window);
3380 gtk_init (&argc, &argv);
3382 create_range_controls ();
3389 <!-- example-end -->
3392 <para>You will notice that the program does not call <literal>gtk_signal_connect</literal>
3393 for the "delete_event", but only for the "destroy" signal. This will
3394 still perform the desired function, because an unhandled
3395 "delete_event" will result in a "destroy" signal being given to the
3401 <!-- ***************************************************************** -->
3402 <chapter id="ch-MiscWidgets">
3403 <title>Miscellaneous Widgets</title>
3405 <!-- ----------------------------------------------------------------- -->
3406 <sect1 id="sec-Labels">
3407 <title>Labels</title>
3409 <para>Labels are used a lot in GTK, and are relatively simple. Labels emit
3410 no signals as they do not have an associated X window. If you need to
3411 catch signals, or do clipping, place it inside a <link linkend="sec-EventBox">
3412 EventBox</link> widget or a Button widget.</para>
3414 <para>To create a new label, use:</para>
3416 <programlisting role="C">
3417 GtkWidget *gtk_label_new( char *str );
3420 <para>The sole argument is the string you wish the label to display.</para>
3422 <para>To change the label's text after creation, use the function:</para>
3424 <programlisting role="C">
3425 void gtk_label_set_text( GtkLabel *label,
3429 <para>The first argument is the label you created previously (cast
3430 using the <literal>GTK_LABEL()</literal> macro), and the second is the new string.</para>
3432 <para>The space needed for the new string will be automatically adjusted if
3433 needed. You can produce multi-line labels by putting line breaks in
3434 the label string.</para>
3436 <para>To retrieve the current string, use:</para>
3438 <programlisting role="C">
3439 void gtk_label_get( GtkLabel *label,
3443 <para>The first argument is the label you've created, and the second,
3444 the return for the string. Do not free the return string, as it is
3445 used internally by GTK.</para>
3447 <para>The label text can be justified using:</para>
3449 <programlisting role="C">
3450 void gtk_label_set_justify( GtkLabel *label,
3451 GtkJustification jtype );
3454 <para>Values for <literal>jtype</literal> are:</para>
3455 <programlisting role="C">
3458 GTK_JUSTIFY_CENTER (the default)
3462 <para>The label widget is also capable of line wrapping the text
3463 automatically. This can be activated using:</para>
3465 <programlisting role="C">
3466 void gtk_label_set_line_wrap (GtkLabel *label,
3470 <para>The <literal>wrap</literal> argument takes a TRUE or FALSE value.</para>
3472 <para>If you want your label underlined, then you can set a pattern on the
3475 <programlisting role="C">
3476 void gtk_label_set_pattern (GtkLabel *label,
3477 const gchar *pattern);
3480 <para>The pattern argument indicates how the underlining should look. It
3481 consists of a string of underscore and space characters. An underscore
3482 indicates that the corresponding character in the label should be
3483 underlined. For example, the string <literal>"__ __"</literal> would underline the
3484 first two characters and eight and ninth characters.</para>
3486 <para>Below is a short example to illustrate these functions. This example
3487 makes use of the Frame widget to better demonstrate the label
3488 styles. You can ignore this for now as the <link linkend="sec-Frames">Frame</link> widget is explained later on.</para>
3493 <imagedata fileref="label.png" format="png">
3495 </inlinemediaobject>
3498 <programlisting role="C">
3499 <!-- example-start label label.c -->
3501 #include <gtk/gtk.h>
3506 static GtkWidget *window = NULL;
3512 /* Initialise GTK */
3513 gtk_init (&argc, &argv);
3515 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3516 g_signal_connect (G_OBJECT (window), "destroy",
3517 G_CALLBACK (gtk_main_quit),
3520 gtk_window_set_title (GTK_WINDOW (window), "Label");
3521 vbox = gtk_vbox_new (FALSE, 5);
3522 hbox = gtk_hbox_new (FALSE, 5);
3523 gtk_container_add (GTK_CONTAINER (window), hbox);
3524 gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
3525 gtk_container_set_border_width (GTK_CONTAINER (window), 5);
3527 frame = gtk_frame_new ("Normal Label");
3528 label = gtk_label_new ("This is a Normal label");
3529 gtk_container_add (GTK_CONTAINER (frame), label);
3530 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3532 frame = gtk_frame_new ("Multi-line Label");
3533 label = gtk_label_new ("This is a Multi-line label.\nSecond line\n" \
3535 gtk_container_add (GTK_CONTAINER (frame), label);
3536 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3538 frame = gtk_frame_new ("Left Justified Label");
3539 label = gtk_label_new ("This is a Left-Justified\n" \
3540 "Multi-line label.\nThird line");
3541 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
3542 gtk_container_add (GTK_CONTAINER (frame), label);
3543 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3545 frame = gtk_frame_new ("Right Justified Label");
3546 label = gtk_label_new ("This is a Right-Justified\nMulti-line label.\n" \
3547 "Fourth line, (j/k)");
3548 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT);
3549 gtk_container_add (GTK_CONTAINER (frame), label);
3550 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3552 vbox = gtk_vbox_new (FALSE, 5);
3553 gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
3554 frame = gtk_frame_new ("Line wrapped label");
3555 label = gtk_label_new ("This is an example of a line-wrapped label. It " \
3556 "should not be taking up the entire " /* big space to test spacing */\
3557 "width allocated to it, but automatically " \
3558 "wraps the words to fit. " \
3559 "The time has come, for all good men, to come to " \
3560 "the aid of their party. " \
3561 "The sixth sheik's six sheep's sick.\n" \
3562 " It supports multiple paragraphs correctly, " \
3563 "and correctly adds "\
3564 "many extra spaces. ");
3565 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
3566 gtk_container_add (GTK_CONTAINER (frame), label);
3567 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3569 frame = gtk_frame_new ("Filled, wrapped label");
3570 label = gtk_label_new ("This is an example of a line-wrapped, filled label. " \
3571 "It should be taking "\
3572 "up the entire width allocated to it. " \
3573 "Here is a sentence to prove "\
3574 "my point. Here is another sentence. "\
3575 "Here comes the sun, do de do de do.\n"\
3576 " This is a new paragraph.\n"\
3577 " This is another newer, longer, better " \
3578 "paragraph. It is coming to an end, "\
3580 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_FILL);
3581 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
3582 gtk_container_add (GTK_CONTAINER (frame), label);
3583 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3585 frame = gtk_frame_new ("Underlined label");
3586 label = gtk_label_new ("This label is underlined!\n"
3587 "This one is underlined in quite a funky fashion");
3588 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
3589 gtk_label_set_pattern (GTK_LABEL (label),
3590 "_________________________ _ _________ _ ______ __ _______ ___");
3591 gtk_container_add (GTK_CONTAINER (frame), label);
3592 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3594 gtk_widget_show_all (window);
3600 <!-- example-end -->
3605 <!-- ----------------------------------------------------------------- -->
3606 <sect1 id="sec-Arrows">
3607 <title>Arrows</title>
3609 <para>The Arrow widget draws an arrowhead, facing in a number of possible
3610 directions and having a number of possible styles. It can be very
3611 useful when placed on a button in many applications. Like the Label
3612 widget, it emits no signals.</para>
3614 <para>There are only two functions for manipulating an Arrow widget:</para>
3616 <programlisting role="C">
3617 GtkWidget *gtk_arrow_new( GtkArrowType arrow_type,
3618 GtkShadowType shadow_type );
3620 void gtk_arrow_set( GtkArrow *arrow,
3621 GtkArrowType arrow_type,
3622 GtkShadowType shadow_type );
3625 <para>The first creates a new arrow widget with the indicated type and
3626 appearance. The second allows these values to be altered
3627 retrospectively. The <literal>arrow_type</literal> argument may take one of the
3628 following values:</para>
3630 <programlisting role="C">
3637 <para>These values obviously indicate the direction in which the arrow will
3638 point. The <literal>shadow_type</literal> argument may take one of these values:</para>
3640 <programlisting role="C">
3642 GTK_SHADOW_OUT (the default)
3643 GTK_SHADOW_ETCHED_IN
3644 GTK_SHADOW_ETCHED_OUT
3647 <para>Here's a brief example to illustrate their use.</para>
3652 <imagedata fileref="arrow.png" format="png">
3654 </inlinemediaobject>
3657 <programlisting role="C">
3658 <!-- example-start arrow arrow.c -->
3660 #include <gtk/gtk.h>
3662 /* Create an Arrow widget with the specified parameters
3663 * and pack it into a button */
3664 GtkWidget *create_arrow_button( GtkArrowType arrow_type,
3665 GtkShadowType shadow_type )
3670 button = gtk_button_new ();
3671 arrow = gtk_arrow_new (arrow_type, shadow_type);
3673 gtk_container_add (GTK_CONTAINER (button), arrow);
3675 gtk_widget_show (button);
3676 gtk_widget_show (arrow);
3684 /* GtkWidget is the storage type for widgets */
3689 /* Initialize the toolkit */
3690 gtk_init (&argc, &argv);
3692 /* Create a new window */
3693 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3695 gtk_window_set_title (GTK_WINDOW (window), "Arrow Buttons");
3697 /* It's a good idea to do this for all windows. */
3698 g_signal_connect (G_OBJECT (window), "destroy",
3699 G_CALLBACK (gtk_main_quit), NULL);
3701 /* Sets the border width of the window. */
3702 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
3704 /* Create a box to hold the arrows/buttons */
3705 box = gtk_hbox_new (FALSE, 0);
3706 gtk_container_set_border_width (GTK_CONTAINER (box), 2);
3707 gtk_container_add (GTK_CONTAINER (window), box);
3709 /* Pack and show all our widgets */
3710 gtk_widget_show (box);
3712 button = create_arrow_button (GTK_ARROW_UP, GTK_SHADOW_IN);
3713 gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3715 button = create_arrow_button (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
3716 gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3718 button = create_arrow_button (GTK_ARROW_LEFT, GTK_SHADOW_ETCHED_IN);
3719 gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3721 button = create_arrow_button (GTK_ARROW_RIGHT, GTK_SHADOW_ETCHED_OUT);
3722 gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3724 gtk_widget_show (window);
3726 /* Rest in gtk_main and wait for the fun to begin! */
3731 <!-- example-end -->
3736 <!-- ----------------------------------------------------------------- -->
3737 <sect1 id="sec-TheTooltipsObject">
3738 <title>The Tooltips Object</title>
3740 <para>These are the little text strings that pop up when you leave your
3741 pointer over a button or other widget for a few seconds. They are easy
3742 to use, so I will just explain them without giving an example. If you
3743 want to see some code, take a look at the testgtk.c program
3744 distributed with GTK.</para>
3746 <para>Widgets that do not receive events (widgets that do not have their
3747 own window) will not work with tooltips.</para>
3749 <para>The first call you will use creates a new tooltip. You only need to do
3750 this once for a set of tooltips as the <literal>GtkTooltips</literal> object this
3751 function returns can be used to create multiple tooltips.</para>
3753 <programlisting role="C">
3754 GtkTooltips *gtk_tooltips_new( void );
3757 <para>Once you have created a new tooltip, and the widget you wish to use it
3758 on, simply use this call to set it:</para>
3760 <programlisting role="C">
3761 void gtk_tooltips_set_tip( GtkTooltips *tooltips,
3763 const gchar *tip_text,
3764 const gchar *tip_private );
3767 <para>The first argument is the tooltip you've already created, followed by
3768 the widget you wish to have this tooltip pop up for, and the text you
3769 wish it to say. The last argument is a text string that can be used as
3770 an identifier when using GtkTipsQuery to implement context sensitive
3771 help. For now, you can set it to NULL.</para>
3773 <!-- TODO: sort out what how to do the context sensitive help -->
3775 <para>Here's a short example:</para>
3777 <programlisting role="C">
3778 GtkTooltips *tooltips;
3783 tooltips = gtk_tooltips_new ();
3784 button = gtk_button_new_with_label ("button 1");
3788 gtk_tooltips_set_tip (tooltips, button, "This is button 1", NULL);
3791 <para>There are other calls that can be used with tooltips. I will just list
3792 them with a brief description of what they do.</para>
3794 <programlisting role="C">
3795 void gtk_tooltips_enable( GtkTooltips *tooltips );
3798 <para>Enable a disabled set of tooltips.</para>
3800 <programlisting role="C">
3801 void gtk_tooltips_disable( GtkTooltips *tooltips );
3804 <para>Disable an enabled set of tooltips.</para>
3806 <programlisting role="C">
3807 void gtk_tooltips_set_delay( GtkTooltips *tooltips,
3811 <para>Sets how many milliseconds you have to hold your pointer over the
3812 widget before the tooltip will pop up. The default is 500
3813 milliseconds (half a second).</para>
3815 <programlisting role="C">
3816 void gtk_tooltips_set_colors( GtkTooltips *tooltips,
3817 GdkColor *background,
3818 GdkColor *foreground );
3821 <para>Set the foreground and background color of the tooltips.</para>
3823 <para>And that's all the functions associated with tooltips. More than
3824 you'll ever want to know :-)</para>
3828 <!-- ----------------------------------------------------------------- -->
3829 <sect1 id="sec-ProgressBars">
3830 <title>Progress Bars</title>
3832 <para>Progress bars are used to show the status of an operation. They are
3833 pretty easy to use, as you will see with the code below. But first
3834 lets start out with the calls to create a new progress bar.</para>
3836 <para>There are two ways to create a progress bar, one simple that takes
3837 no arguments, and one that takes an Adjustment object as an
3838 argument. If the former is used, the progress bar creates its own
3839 adjustment object.</para>
3841 <programlisting role="C">
3842 GtkWidget *gtk_progress_bar_new( void );
3844 GtkWidget *gtk_progress_bar_new_with_adjustment( GtkAdjustment *adjustment );
3847 <para>The second method has the advantage that we can use the adjustment
3848 object to specify our own range parameters for the progress bar.</para>
3850 <para>The adjustment of a progress object can be changed dynamically using:</para>
3852 <programlisting role="C">
3853 void gtk_progress_set_adjustment( GtkProgress *progress,
3854 GtkAdjustment *adjustment );
3857 <para>Now that the progress bar has been created we can use it.</para>
3859 <programlisting role="C">
3860 void gtk_progress_bar_update( GtkProgressBar *pbar,
3861 gfloat percentage );
3864 <para>The first argument is the progress bar you wish to operate on, and the
3865 second argument is the amount "completed", meaning the amount the
3866 progress bar has been filled from 0-100%. This is passed to the
3867 function as a real number ranging from 0 to 1.</para>
3869 <para>GTK v1.2 has added new functionality to the progress bar that enables
3870 it to display its value in different ways, and to inform the user of
3871 its current value and its range.</para>
3873 <para>A progress bar may be set to one of a number of orientations using the
3876 <programlisting role="C">
3877 void gtk_progress_bar_set_orientation( GtkProgressBar *pbar,
3878 GtkProgressBarOrientation orientation );
3881 <para>The <literal>orientation</literal> argument may take one of the following
3882 values to indicate the direction in which the progress bar moves:</para>
3884 <programlisting role="C">
3885 GTK_PROGRESS_LEFT_TO_RIGHT
3886 GTK_PROGRESS_RIGHT_TO_LEFT
3887 GTK_PROGRESS_BOTTOM_TO_TOP
3888 GTK_PROGRESS_TOP_TO_BOTTOM
3891 <para>When used as a measure of how far a process has progressed, the
3892 ProgressBar can be set to display its value in either a continuous
3893 or discrete mode. In continuous mode, the progress bar is updated for
3894 each value. In discrete mode, the progress bar is updated in a number
3895 of discrete blocks. The number of blocks is also configurable.</para>
3897 <para>The style of a progress bar can be set using the following function.</para>
3899 <programlisting role="C">
3900 void gtk_progress_bar_set_bar_style( GtkProgressBar *pbar,
3901 GtkProgressBarStyle style );
3904 <para>The <literal>style</literal> parameter can take one of two values:</para>
3906 <programlisting role="C">
3907 GTK_PROGRESS_CONTINUOUS
3908 GTK_PROGRESS_DISCRETE
3911 <para>The number of discrete blocks can be set by calling</para>
3913 <programlisting role="C">
3914 void gtk_progress_bar_set_discrete_blocks( GtkProgressBar *pbar,
3918 <para>As well as indicating the amount of progress that has occured, the
3919 progress bar may be set to just indicate that there is some
3920 activity. This can be useful in situations where progress cannot be
3921 measured against a value range. Activity mode is not effected by the
3922 bar style that is described above, and overrides it. This mode is
3923 either TRUE or FALSE, and is selected by the following function.</para>
3925 <programlisting role="C">
3926 void gtk_progress_set_activity_mode( GtkProgress *progress,
3927 guint activity_mode );
3930 <para>The step size of the activity indicator, and the number of blocks are
3931 set using the following functions.</para>
3933 <programlisting role="C">
3934 void gtk_progress_bar_set_activity_step( GtkProgressBar *pbar,
3937 void gtk_progress_bar_set_activity_blocks( GtkProgressBar *pbar,
3941 <para>When in continuous mode, the progress bar can also display a
3942 configurable text string within its trough, using the following
3945 <programlisting role="C">
3946 void gtk_progress_set_format_string( GtkProgress *progress,
3950 <para>The <literal>format</literal> argument is similiar to one that would be used in a C
3951 <literal>printf</literal> statement. The following directives may be used within the
3952 format string:</para>
3955 <listitem><simpara> %p - percentage</simpara>
3957 <listitem><simpara> %v - value</simpara>
3959 <listitem><simpara> %l - lower range value</simpara>
3961 <listitem><simpara> %u - upper range value</simpara>
3965 <para>The displaying of this text string can be toggled using:</para>
3967 <programlisting role="C">
3968 void gtk_progress_set_show_text( GtkProgress *progress,
3972 <para>The <literal>show_text</literal> argument is a boolean TRUE/FALSE value. The
3973 appearance of the text can be modified further using:</para>
3975 <programlisting role="C">
3976 void gtk_progress_set_text_alignment( GtkProgress *progress,
3981 <para>The <literal>x_align</literal> and <literal>y_align</literal> arguments take values between 0.0
3982 and 1.0. Their values indicate the position of the text string within
3983 the trough. Values of 0.0 for both would place the string in the top
3984 left hand corner; values of 0.5 (the default) centres the text, and
3985 values of 1.0 places the text in the lower right hand corner.</para>
3987 <para>The current text setting of a progress object can be retrieved using
3988 the current or a specified adjustment value using the following two
3989 functions. The character string returned by these functions should be
3990 freed by the application (using the g_free() function). These
3991 functions return the formatted string that would be displayed within
3994 <programlisting role="C">
3995 gchar *gtk_progress_get_current_text( GtkProgress *progress );
3997 gchar *gtk_progress_get_text_from_value( GtkProgress *progress,
4001 <para>There is yet another way to change the range and value of a progress
4002 object using the following function:</para>
4004 <programlisting role="C">
4005 void gtk_progress_configure( GtkProgress *progress,
4011 <para>This function provides quite a simple interface to the range and value
4012 of a progress object.</para>
4014 <para>The remaining functions can be used to get and set the current value
4015 of a progess object in various types and formats:</para>
4017 <programlisting role="C">
4018 void gtk_progress_set_percentage( GtkProgress *progress,
4019 gfloat percentage );
4021 void gtk_progress_set_value( GtkProgress *progress,
4024 gfloat gtk_progress_get_value( GtkProgress *progress );
4026 gfloat gtk_progress_get_current_percentage( GtkProgress *progress );
4028 gfloat gtk_progress_get_percentage_from_value( GtkProgress *progress,
4032 <para>These functions are pretty self explanatory. The last function uses
4033 the the adjustment of the specified progess object to compute the
4034 percentage value of the given range value.</para>
4036 <para>Progress Bars are usually used with timeouts or other such functions
4037 (see section on <link linkend="ch-Timeouts">Timeouts, I/O and Idle Functions</link>) to give
4038 the illusion of multitasking. All will employ the
4039 gtk_progress_bar_update function in the same manner.</para>
4041 <para>Here is an example of the progress bar, updated using timeouts. This
4042 code also shows you how to reset the Progress Bar.</para>
4047 <imagedata fileref="progressbar.png" format="png">
4049 </inlinemediaobject>
4052 <programlisting role="C">
4053 <!-- example-start progressbar progressbar.c -->
4055 #include <gtk/gtk.h>
4057 typedef struct _ProgressData {
4061 gboolean activity_mode;
4064 /* Update the value of the progress bar so that we get
4066 gint progress_timeout( gpointer data )
4068 ProgressData *pdata = (ProgressData *)data;
4071 if (pdata->activity_mode)
4072 gtk_progress_bar_pulse (GTK_PROGRESS_BAR (pdata->pbar));
4075 /* Calculate the value of the progress bar using the
4076 * value range set in the adjustment object */
4078 new_val = gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR (pdata->pbar)) + 0.01;
4080 if (new_val > 1.0)
4083 /* Set the new value */
4084 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (pdata->pbar), new_val);
4087 /* As this is a timeout function, return TRUE so that it
4088 * continues to get called */
4092 /* Callback that toggles the text display within the progress bar trough */
4093 void toggle_show_text( GtkWidget *widget,
4094 ProgressData *pdata )
4098 text = gtk_progress_bar_get_text (GTK_PROGRESS_BAR (pdata->pbar));
4099 if (text && *text)
4100 gtk_progress_bar_set_text (GTK_PROGRESS_BAR (pdata->pbar), "");
4102 gtk_progress_bar_set_text (GTK_PROGRESS_BAR (pdata->pbar), "some text");
4105 /* Callback that toggles the activity mode of the progress bar */
4106 void toggle_activity_mode( GtkWidget *widget,
4107 ProgressData *pdata )
4109 pdata->activity_mode = !pdata->activity_mode;
4110 if (pdata->activity_mode)
4111 gtk_progress_bar_pulse (GTK_PROGRESS_BAR (pdata->pbar));
4113 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (pdata->pbar), 0.0);
4117 /* Callback that toggles the orientation of the progress bar */
4118 void toggle_orientation( GtkWidget *widget,
4119 ProgressData *pdata )
4121 switch (gtk_progress_bar_get_orientation (GTK_PROGRESS_BAR (pdata->pbar))) {
4122 case GTK_PROGRESS_LEFT_TO_RIGHT:
4123 gtk_progress_bar_set_orientation (GTK_PROGRESS_BAR (pdata->pbar),
4124 GTK_PROGRESS_RIGHT_TO_LEFT);
4126 case GTK_PROGRESS_RIGHT_TO_LEFT:
4127 gtk_progress_bar_set_orientation (GTK_PROGRESS_BAR (pdata->pbar),
4128 GTK_PROGRESS_LEFT_TO_RIGHT);
4136 /* Clean up allocated memory and remove the timer */
4137 void destroy_progress( GtkWidget *widget,
4138 ProgressData *pdata)
4140 gtk_timeout_remove (pdata->timer);
4141 pdata->timer = 0;
4142 pdata->window = NULL;
4150 ProgressData *pdata;
4152 GtkWidget *separator;
4158 gtk_init (&argc, &argv);
4160 /* Allocate memory for the data that is passed to the callbacks */
4161 pdata = g_malloc (sizeof (ProgressData));
4163 pdata->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4164 gtk_window_set_resizable (GTK_WINDOW (pdata->window), TRUE);
4166 g_signal_connect (G_OBJECT (pdata->window), "destroy",
4167 G_CALLBACK (destroy_progress),
4169 gtk_window_set_title (GTK_WINDOW (pdata->window), "GtkProgressBar");
4170 gtk_container_set_border_width (GTK_CONTAINER (pdata->window), 0);
4172 vbox = gtk_vbox_new (FALSE, 5);
4173 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
4174 gtk_container_add (GTK_CONTAINER (pdata->window), vbox);
4175 gtk_widget_show (vbox);
4177 /* Create a centering alignment object */
4178 align = gtk_alignment_new (0.5, 0.5, 0, 0);
4179 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 5);
4180 gtk_widget_show (align);
4182 /* Create the GtkProgressBar */
4183 pdata->pbar = gtk_progress_bar_new ();
4185 gtk_container_add (GTK_CONTAINER (align), pdata->pbar);
4186 gtk_widget_show (pdata->pbar);
4188 /* Add a timer callback to update the value of the progress bar */
4189 pdata->timer = gtk_timeout_add (100, progress_timeout, pdata);
4191 separator = gtk_hseparator_new ();
4192 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
4193 gtk_widget_show (separator);
4195 /* rows, columns, homogeneous */
4196 table = gtk_table_new (2, 2, FALSE);
4197 gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0);
4198 gtk_widget_show (table);
4200 /* Add a check button to select displaying of the trough text */
4201 check = gtk_check_button_new_with_label ("Show text");
4202 gtk_table_attach (GTK_TABLE (table), check, 0, 1, 0, 1,
4203 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
4205 g_signal_connect (G_OBJECT (check), "clicked",
4206 G_CALLBACK (toggle_show_text),
4208 gtk_widget_show (check);
4210 /* Add a check button to toggle activity mode */
4211 check = gtk_check_button_new_with_label ("Activity mode");
4212 gtk_table_attach (GTK_TABLE (table), check, 0, 1, 1, 2,
4213 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
4215 g_signal_connect (G_OBJECT (check), "clicked",
4216 G_CALLBACK (toggle_activity_mode),
4218 gtk_widget_show (check);
4220 /* Add a check button to toggle orientation */
4221 check = gtk_check_button_new_with_label ("Right to Left");
4222 gtk_table_attach (GTK_TABLE (table), check, 0, 1, 2, 3,
4223 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
4225 g_signal_connect (G_OBJECT (check), "clicked",
4226 G_CALLBACK (toggle_orientation),
4228 gtk_widget_show (check);
4230 /* Add a button to exit the program */
4231 button = gtk_button_new_with_label ("close");
4232 g_signal_connect_swapped (G_OBJECT (button), "clicked",
4233 G_CALLBACK (gtk_widget_destroy),
4235 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
4237 /* This makes it so the button is the default. */
4238 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
4240 /* This grabs this button to be the default button. Simply hitting
4241 * the "Enter" key will cause this button to activate. */
4242 gtk_widget_grab_default (button);
4243 gtk_widget_show (button);
4245 gtk_widget_show (pdata->window);
4251 <!-- example-end -->
4256 <!-- ----------------------------------------------------------------- -->
4257 <sect1 id="sec-Dialogs">
4258 <title>Dialogs</title>
4260 <para>The Dialog widget is very simple, and is actually just a window with a
4261 few things pre-packed into it for you. The structure for a Dialog is:</para>
4263 <programlisting role="C">
4269 GtkWidget *action_area;
4273 <para>So you see, it simply creates a window, and then packs a vbox into the
4274 top, which contains a separator and then an hbox called the
4275 "action_area".</para>
4277 <para>The Dialog widget can be used for pop-up messages to the user, and
4278 other similar tasks. It is really basic, and there is only one
4279 function for the dialog box, which is:</para>
4281 <programlisting role="C">
4282 GtkWidget *gtk_dialog_new( void );
4285 <para>So to create a new dialog box, use,</para>
4287 <programlisting role="C">
4289 window = gtk_dialog_new ();
4292 <para>This will create the dialog box, and it is now up to you to use it.
4293 You could pack a button in the action_area by doing something like this:</para>
4295 <programlisting role="C">
4297 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area),
4298 button, TRUE, TRUE, 0);
4299 gtk_widget_show (button);
4302 <para>And you could add to the vbox area by packing, for instance, a label
4303 in it, try something like this:</para>
4305 <programlisting role="C">
4306 label = gtk_label_new ("Dialogs are groovy");
4307 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox),
4308 label, TRUE, TRUE, 0);
4309 gtk_widget_show (label);
4312 <para>As an example in using the dialog box, you could put two buttons in
4313 the action_area, a Cancel button and an Ok button, and a label in the
4314 vbox area, asking the user a question or giving an error etc. Then
4315 you could attach a different signal to each of the buttons and perform
4316 the operation the user selects.</para>
4318 <para>If the simple functionality provided by the default vertical and
4319 horizontal boxes in the two areas doesn't give you enough control for
4320 your application, then you can simply pack another layout widget into
4321 the boxes provided. For example, you could pack a table into the
4322 vertical box.</para>
4326 <!-- ----------------------------------------------------------------- -->
4327 <sect1 id="sec-Pixmaps">
4328 <title>Pixmaps</title>
4330 <para>Pixmaps are data structures that contain pictures. These pictures can
4331 be used in various places, but most commonly as icons on the X
4332 desktop, or as cursors.</para>
4334 <para>A pixmap which only has 2 colors is called a bitmap, and there are a
4335 few additional routines for handling this common special case.</para>
4337 <para>To understand pixmaps, it would help to understand how X window
4338 system works. Under X, applications do not need to be running on the
4339 same computer that is interacting with the user. Instead, the various
4340 applications, called "clients", all communicate with a program which
4341 displays the graphics and handles the keyboard and mouse. This
4342 program which interacts directly with the user is called a "display
4343 server" or "X server." Since the communication might take place over
4344 a network, it's important to keep some information with the X server.
4345 Pixmaps, for example, are stored in the memory of the X server. This
4346 means that once pixmap values are set, they don't need to keep getting
4347 transmitted over the network; instead a command is sent to "display
4348 pixmap number XYZ here." Even if you aren't using X with GTK
4349 currently, using constructs such as Pixmaps will make your programs
4350 work acceptably under X.</para>
4352 <para>To use pixmaps in GTK, we must first build a GdkPixmap structure using
4353 routines from the GDK layer. Pixmaps can either be created from
4354 in-memory data, or from data read from a file. We'll go through each
4355 of the calls to create a pixmap.</para>
4357 <programlisting role="C">
4358 GdkPixmap *gdk_bitmap_create_from_data( GdkWindow *window,
4364 <para>This routine is used to create a single-plane pixmap (2 colors) from
4365 data in memory. Each bit of the data represents whether that pixel is
4366 off or on. Width and height are in pixels. The GdkWindow pointer is to
4367 the current window, since a pixmap's resources are meaningful only in
4368 the context of the screen where it is to be displayed.</para>
4370 <programlisting role="C">
4371 GdkPixmap *gdk_pixmap_create_from_data( GdkWindow *window,
4380 <para>This is used to create a pixmap of the given depth (number of colors) from
4381 the bitmap data specified. <literal>fg</literal> and <literal>bg</literal> are the foreground and
4382 background color to use.</para>
4384 <programlisting role="C">
4385 GdkPixmap *gdk_pixmap_create_from_xpm( GdkWindow *window,
4387 GdkColor *transparent_color,
4388 const gchar *filename );
4391 <para>XPM format is a readable pixmap representation for the X Window
4392 System. It is widely used and many different utilities are available
4393 for creating image files in this format. The file specified by
4394 filename must contain an image in that format and it is loaded into
4395 the pixmap structure. The mask specifies which bits of the pixmap are
4396 opaque. All other bits are colored using the color specified by
4397 transparent_color. An example using this follows below.</para>
4399 <programlisting role="C">
4400 GdkPixmap *gdk_pixmap_create_from_xpm_d( GdkWindow *window,
4402 GdkColor *transparent_color,
4406 <para>Small images can be incorporated into a program as data in the XPM
4407 format. A pixmap is created using this data, instead of reading it
4408 from a file. An example of such data is</para>
4410 <programlisting role="C">
4412 static const char * xpm_data[] = {
4415 ". c #000000000000",
4416 "X c #FFFFFFFFFFFF",
4435 <para>When we're done using a pixmap and not likely to reuse it again soon,
4436 it is a good idea to release the resource using
4437 gdk_pixmap_unref(). Pixmaps should be considered a precious resource,
4438 because they take up memory in the end-user's X server process. Even
4439 though the X client you write may run on a powerful "server" computer,
4440 the user may be running the X server on a small personal computer.</para>
4442 <para>Once we've created a pixmap, we can display it as a GTK widget. We
4443 must create a GTK pixmap widget to contain the GDK pixmap. This is
4446 <programlisting role="C">
4447 GtkWidget *gtk_pixmap_new( GdkPixmap *pixmap,
4451 <para>The other pixmap widget calls are</para>
4453 <programlisting role="C">
4454 guint gtk_pixmap_get_type( void );
4456 void gtk_pixmap_set( GtkPixmap *pixmap,
4460 void gtk_pixmap_get( GtkPixmap *pixmap,
4465 <para>gtk_pixmap_set is used to change the pixmap that the widget is currently
4466 managing. Val is the pixmap created using GDK.</para>
4468 <para>The following is an example of using a pixmap in a button.</para>
4470 <programlisting role="C">
4471 <!-- example-start pixmap pixmap.c -->
4473 #include <gtk/gtk.h>
4476 /* XPM data of Open-File icon */
4477 static const char * xpm_data[] = {
4480 ". c #000000000000",
4481 "X c #FFFFFFFFFFFF",
4500 /* when invoked (via signal delete_event), terminates the application.
4502 gint close_application( GtkWidget *widget,
4511 /* is invoked when the button is clicked. It just prints a message.
4513 void button_clicked( GtkWidget *widget,
4515 g_print ("button clicked\n");
4521 /* GtkWidget is the storage type for widgets */
4522 GtkWidget *window, *pixmapwid, *button;
4527 /* create the main window, and attach delete_event signal to terminating
4529 gtk_init (&argc, &argv);
4530 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4531 g_signal_connect (G_OBJECT (window), "delete_event",
4532 G_CALLBACK (close_application), NULL);
4533 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
4534 gtk_widget_show (window);
4536 /* now for the pixmap from gdk */
4537 style = gtk_widget_get_style (window);
4538 pixmap = gdk_pixmap_create_from_xpm_d (window->window, &mask,
4539 &style->bg[GTK_STATE_NORMAL],
4540 (gchar **)xpm_data);
4542 /* a pixmap widget to contain the pixmap */
4543 pixmapwid = gtk_pixmap_new (pixmap, mask);
4544 gtk_widget_show (pixmapwid);
4546 /* a button to contain the pixmap widget */
4547 button = gtk_button_new ();
4548 gtk_container_add (GTK_CONTAINER (button), pixmapwid);
4549 gtk_container_add (GTK_CONTAINER (window), button);
4550 gtk_widget_show (button);
4552 g_signal_connect (G_OBJECT (button), "clicked",
4553 G_CALLBACK (button_clicked), NULL);
4555 /* show the window */
4560 <!-- example-end -->
4563 <para>To load a file from an XPM data file called icon0.xpm in the current
4564 directory, we would have created the pixmap thus</para>
4566 <programlisting role="C">
4567 /* load a pixmap from a file */
4568 pixmap = gdk_pixmap_create_from_xpm( window->window, &mask,
4569 &style->bg[GTK_STATE_NORMAL],
4571 pixmapwid = gtk_pixmap_new( pixmap, mask );
4572 gtk_widget_show( pixmapwid );
4573 gtk_container_add( GTK_CONTAINER(window), pixmapwid );
4576 <para>A disadvantage of using pixmaps is that the displayed object is always
4577 rectangular, regardless of the image. We would like to create desktops
4578 and applications with icons that have more natural shapes. For
4579 example, for a game interface, we would like to have round buttons to
4580 push. The way to do this is using shaped windows.</para>
4582 <para>A shaped window is simply a pixmap where the background pixels are
4583 transparent. This way, when the background image is multi-colored, we
4584 don't overwrite it with a rectangular, non-matching border around our
4585 icon. The following example displays a full wheelbarrow image on the
4588 <programlisting role="C">
4589 <!-- example-start wheelbarrow wheelbarrow.c -->
4591 #include <gtk/gtk.h>
4594 static char * WheelbarrowFull_xpm[] = {
4597 ". c #DF7DCF3CC71B",
4598 "X c #965875D669A6",
4599 "o c #71C671C671C6",
4600 "O c #A699A289A699",
4601 "+ c #965892489658",
4602 "@ c #8E38410330C2",
4603 "# c #D75C7DF769A6",
4604 "$ c #F7DECF3CC71B",
4605 "% c #96588A288E38",
4606 "& c #A69992489E79",
4607 "* c #8E3886178E38",
4608 "= c #104008200820",
4609 "- c #596510401040",
4610 "; c #C71B30C230C2",
4611 ": c #C71B9A699658",
4612 "> c #618561856185",
4613 ", c #20811C712081",
4614 "< c #104000000000",
4615 "1 c #861720812081",
4616 "2 c #DF7D4D344103",
4617 "3 c #79E769A671C6",
4618 "4 c #861782078617",
4619 "5 c #41033CF34103",
4620 "6 c #000000000000",
4621 "7 c #49241C711040",
4622 "8 c #492445144924",
4623 "9 c #082008200820",
4624 "0 c #69A618611861",
4625 "q c #B6DA71C65144",
4626 "w c #410330C238E3",
4627 "e c #CF3CBAEAB6DA",
4628 "r c #71C6451430C2",
4629 "t c #EFBEDB6CD75C",
4630 "y c #28A208200820",
4631 "u c #186110401040",
4632 "i c #596528A21861",
4633 "p c #71C661855965",
4634 "a c #A69996589658",
4635 "s c #30C228A230C2",
4636 "d c #BEFBA289AEBA",
4637 "f c #596545145144",
4638 "g c #30C230C230C2",
4639 "h c #8E3882078617",
4640 "j c #208118612081",
4641 "k c #38E30C300820",
4642 "l c #30C2208128A2",
4643 "z c #38E328A238E3",
4644 "x c #514438E34924",
4645 "c c #618555555965",
4646 "v c #30C2208130C2",
4647 "b c #38E328A230C2",
4648 "n c #28A228A228A2",
4649 "m c #41032CB228A2",
4650 "M c #104010401040",
4651 "N c #492438E34103",
4652 "B c #28A2208128A2",
4653 "V c #A699596538E3",
4654 "C c #30C21C711040",
4655 "Z c #30C218611040",
4656 "A c #965865955965",
4657 "S c #618534D32081",
4658 "D c #38E31C711040",
4659 "F c #082000000820",
4664 " >,<12#:34 ",
4668 "ty> 459@>+&& ",
4669 "$2u+ ><ipas8* ",
4670 "%$;=* *3:.Xa.dfg> ",
4671 "Oh$;ya *3d.a8j,Xe.d3g8+ ",
4672 " Oh$;ka *3d$a8lz,,xxc:.e3g54 ",
4673 " Oh$;kO *pd$%svbzz,sxxxxfX..&wn> ",
4674 " Oh$@mO *3dthwlsslszjzxxxxxxx3:td8M4 ",
4675 " Oh$@g& *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B* ",
4676 " Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5& ",
4677 " Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM* ",
4678 " OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
4679 " 2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
4680 " :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
4681 " +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
4682 " *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&en",
4683 " p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>",
4684 " OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ",
4685 " 3206Bwxxszx%et.eaAp77m77mmmf3&eeeg* ",
4686 " @26MvzxNzvlbwfpdettttttttttt.c,n& ",
4687 " *;16=lsNwwNwgsvslbwwvccc3pcfu<o ",
4688 " p;<69BvwwsszslllbBlllllllu<5+ ",
4689 " OS0y6FBlvvvzvzss,u=Blllj=54 ",
4690 " c1-699Blvlllllu7k96MMMg4 ",
4691 " *10y8n6FjvllllB<166668 ",
4692 " S-kg+>666<M<996-y6n<8* ",
4693 " p71=4 m69996kD8Z-66698&& ",
4694 " &i0ycm6n4 ogk17,0<6666g ",
4695 " N-k-<> >=01-kuu666> ",
4696 " ,6ky& &46-10ul,66, ",
4697 " Ou0<> o66y<ulw<66& ",
4698 " *kk5 >66By7=xu664 ",
4699 " <<M4 466lj<Mxu66o ",
4700 " *>> +66uv,zN666* ",
4710 /* When invoked (via signal delete_event), terminates the application */
4711 gint close_application( GtkWidget *widget,
4722 /* GtkWidget is the storage type for widgets */
4723 GtkWidget *window, *pixmap, *fixed;
4724 GdkPixmap *gdk_pixmap;
4729 /* Create the main window, and attach delete_event signal to terminate
4730 * the application. Note that the main window will not have a titlebar
4731 * since we're making it a popup. */
4732 gtk_init (&argc, &argv);
4733 window = gtk_window_new (GTK_WINDOW_POPUP);
4734 g_signal_connect (G_OBJECT (window), "delete_event",
4735 G_CALLBACK (close_application), NULL);
4736 gtk_widget_show (window);
4738 /* Now for the pixmap and the pixmap widget */
4739 style = gtk_widget_get_default_style();
4740 gc = style->black_gc;
4741 gdk_pixmap = gdk_pixmap_create_from_xpm_d (window->window, &mask,
4742 &style->bg[GTK_STATE_NORMAL],
4743 WheelbarrowFull_xpm);
4744 pixmap = gtk_image_new_from_pixmap (gdk_pixmap, mask);
4745 gtk_widget_show (pixmap);
4747 /* To display the pixmap, we use a fixed widget to place the pixmap */
4748 fixed = gtk_fixed_new ();
4749 gtk_widget_set_size_request (fixed, 200, 200);
4750 gtk_fixed_put (GTK_FIXED (fixed), pixmap, 0, 0);
4751 gtk_container_add (GTK_CONTAINER (window), fixed);
4752 gtk_widget_show (fixed);
4754 /* This masks out everything except for the image itself */
4755 gtk_widget_shape_combine_mask (window, mask, 0, 0);
4757 /* show the window */
4758 gtk_widget_show (window);
4763 <!-- example-end -->
4766 <para>To make the wheelbarrow image sensitive, we could attach the button
4767 press event signal to make it do something. The following few lines
4768 would make the picture sensitive to a mouse button being pressed which
4769 makes the application terminate.</para>
4771 <programlisting role="C">
4772 gtk_widget_set_events( window,
4773 gtk_widget_get_events( window ) |
4774 GDK_BUTTON_PRESS_MASK );
4776 gtk_signal_connect( GTK_OBJECT(window), "button_press_event",
4777 GTK_SIGNAL_FUNC(close_application), NULL );
4782 <!-- ----------------------------------------------------------------- -->
4783 <sect1 id="sec-Rulers">
4784 <title>Rulers</title>
4786 <para>Ruler widgets are used to indicate the location of the mouse pointer
4787 in a given window. A window can have a vertical ruler spanning across
4788 the width and a horizontal ruler spanning down the height. A small
4789 triangular indicator on the ruler shows the exact location of the
4790 pointer relative to the ruler.</para>
4792 <para>A ruler must first be created. Horizontal and vertical rulers are
4793 created using</para>
4795 <programlisting role="C">
4796 GtkWidget *gtk_hruler_new( void ); /* horizontal ruler */
4798 GtkWidget *gtk_vruler_new( void ); /* vertical ruler */
4801 <para>Once a ruler is created, we can define the unit of measurement. Units
4802 of measure for rulers can be<literal>GTK_PIXELS</literal>, <literal>GTK_INCHES</literal> or
4803 <literal>GTK_CENTIMETERS</literal>. This is set using</para>
4805 <programlisting role="C">
4806 void gtk_ruler_set_metric( GtkRuler *ruler,
4807 GtkMetricType metric );
4810 <para>The default measure is <literal>GTK_PIXELS</literal>.</para>
4812 <programlisting role="C">
4813 gtk_ruler_set_metric( GTK_RULER(ruler), GTK_PIXELS );
4816 <para>Other important characteristics of a ruler are how to mark the units
4817 of scale and where the position indicator is initially placed. These
4818 are set for a ruler using</para>
4820 <programlisting role="C">
4821 void gtk_ruler_set_range( GtkRuler *ruler,
4828 <para>The lower and upper arguments define the extent of the ruler, and
4829 max_size is the largest possible number that will be displayed.
4830 Position defines the initial position of the pointer indicator within
4833 <para>A vertical ruler can span an 800 pixel wide window thus</para>
4835 <programlisting role="C">
4836 gtk_ruler_set_range( GTK_RULER(vruler), 0, 800, 0, 800);
4839 <para>The markings displayed on the ruler will be from 0 to 800, with a
4840 number for every 100 pixels. If instead we wanted the ruler to range
4841 from 7 to 16, we would code</para>
4843 <programlisting role="C">
4844 gtk_ruler_set_range( GTK_RULER(vruler), 7, 16, 0, 20);
4847 <para>The indicator on the ruler is a small triangular mark that indicates
4848 the position of the pointer relative to the ruler. If the ruler is
4849 used to follow the mouse pointer, the motion_notify_event signal
4850 should be connected to the motion_notify_event method of the ruler.
4851 To follow all mouse movements within a window area, we would use</para>
4853 <programlisting role="C">
4854 #define EVENT_METHOD(i, x) GTK_WIDGET_GET_CLASS(i)->x
4856 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4857 (GtkSignalFunc)EVENT_METHOD(ruler, motion_notify_event),
4858 GTK_OBJECT(ruler) );
4861 <para>The following example creates a drawing area with a horizontal ruler
4862 above it and a vertical ruler to the left of it. The size of the
4863 drawing area is 600 pixels wide by 400 pixels high. The horizontal
4864 ruler spans from 7 to 13 with a mark every 100 pixels, while the
4865 vertical ruler spans from 0 to 400 with a mark every 100 pixels.
4866 Placement of the drawing area and the rulers is done using a table.</para>
4871 <imagedata fileref="rulers.png" format="png">
4873 </inlinemediaobject>
4876 <programlisting role="C">
4877 <!-- example-start rulers rulers.c -->
4879 #include <gtk/gtk.h>
4881 #define EVENT_METHOD(i, x) GTK_WIDGET_GET_CLASS(i)->x
4886 /* This routine gets control when the close button is clicked */
4887 gint close_application( GtkWidget *widget,
4895 /* The main routine */
4898 GtkWidget *window, *table, *area, *hrule, *vrule;
4900 /* Initialize GTK and create the main window */
4901 gtk_init (&argc, &argv);
4903 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4904 g_signal_connect (G_OBJECT (window), "delete_event",
4905 G_CALLBACK (close_application), NULL);
4906 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
4908 /* Create a table for placing the ruler and the drawing area */
4909 table = gtk_table_new (3, 2, FALSE);
4910 gtk_container_add (GTK_CONTAINER (window), table);
4912 area = gtk_drawing_area_new ();
4913 gtk_widget_set_size_request (GTK_WIDGET (area), XSIZE, YSIZE);
4914 gtk_table_attach (GTK_TABLE (table), area, 1, 2, 1, 2,
4915 GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0);
4916 gtk_widget_set_events (area, GDK_POINTER_MOTION_MASK |
4917 GDK_POINTER_MOTION_HINT_MASK);
4919 /* The horizontal ruler goes on top. As the mouse moves across the
4920 * drawing area, a motion_notify_event is passed to the
4921 * appropriate event handler for the ruler. */
4922 hrule = gtk_hruler_new ();
4923 gtk_ruler_set_metric (GTK_RULER (hrule), GTK_PIXELS);
4924 gtk_ruler_set_range (GTK_RULER (hrule), 7, 13, 0, 20);
4925 g_signal_connect_swapped (G_OBJECT (area), "motion_notify_event",
4926 G_CALLBACK (EVENT_METHOD (hrule, motion_notify_event)),
4928 gtk_table_attach (GTK_TABLE (table), hrule, 1, 2, 0, 1,
4929 GTK_EXPAND|GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0);
4931 /* The vertical ruler goes on the left. As the mouse moves across
4932 * the drawing area, a motion_notify_event is passed to the
4933 * appropriate event handler for the ruler. */
4934 vrule = gtk_vruler_new ();
4935 gtk_ruler_set_metric (GTK_RULER (vrule), GTK_PIXELS);
4936 gtk_ruler_set_range (GTK_RULER (vrule), 0, YSIZE, 10, YSIZE );
4937 g_signal_connect_swapped (G_OBJECT (area), "motion_notify_event",
4938 G_CALLBACK (EVENT_METHOD (vrule, motion_notify_event)),
4940 gtk_table_attach (GTK_TABLE (table), vrule, 0, 1, 1, 2,
4941 GTK_FILL, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0);
4943 /* Now show everything */
4944 gtk_widget_show (area);
4945 gtk_widget_show (hrule);
4946 gtk_widget_show (vrule);
4947 gtk_widget_show (table);
4948 gtk_widget_show (window);
4953 <!-- example-end -->
4958 <!-- ----------------------------------------------------------------- -->
4959 <sect1 id="sec-Statusbars">
4960 <title>Statusbars</title>
4962 <para>Statusbars are simple widgets used to display a text message. They
4963 keep a stack of the messages pushed onto them, so that popping the
4964 current message will re-display the previous text message.</para>
4966 <para>In order to allow different parts of an application to use the same
4967 statusbar to display messages, the statusbar widget issues Context
4968 Identifiers which are used to identify different "users". The message
4969 on top of the stack is the one displayed, no matter what context it is
4970 in. Messages are stacked in last-in-first-out order, not context
4971 identifier order.</para>
4973 <para>A statusbar is created with a call to:</para>
4975 <programlisting role="C">
4976 GtkWidget *gtk_statusbar_new( void );
4979 <para>A new Context Identifier is requested using a call to the following
4980 function with a short textual description of the context:</para>
4982 <programlisting role="C">
4983 guint gtk_statusbar_get_context_id( GtkStatusbar *statusbar,
4984 const gchar *context_description );
4987 <para>There are three functions that can operate on statusbars:</para>
4989 <programlisting role="C">
4990 guint gtk_statusbar_push( GtkStatusbar *statusbar,
4994 void gtk_statusbar_pop( GtkStatusbar *statusbar)
4997 void gtk_statusbar_remove( GtkStatusbar *statusbar,
5002 <para>The first, gtk_statusbar_push, is used to add a new message to the
5003 statusbar. It returns a Message Identifier, which can be passed later
5004 to the function gtk_statusbar_remove to remove the message with the
5005 given Message and Context Identifiers from the statusbar's stack.</para>
5007 <para>The function gtk_statusbar_pop removes the message highest in the
5008 stack with the given Context Identifier.</para>
5010 <para>The following example creates a statusbar and two buttons, one for
5011 pushing items onto the statusbar, and one for popping the last item
5017 <imagedata fileref="statusbar.png" format="png">
5019 </inlinemediaobject>
5022 <programlisting role="C">
5023 <!-- example-start statusbar statusbar.c -->
5025 #include <stdlib.h>
5026 #include <gtk/gtk.h>
5027 #include <glib.h>
5029 GtkWidget *status_bar;
5031 void push_item( GtkWidget *widget,
5034 static int count = 1;
5037 g_snprintf (buff, 20, "Item %d", count++);
5038 gtk_statusbar_push (GTK_STATUSBAR (status_bar), GPOINTER_TO_INT (data), buff);
5043 void pop_item( GtkWidget *widget,
5046 gtk_statusbar_pop (GTK_STATUSBAR (status_bar), GPOINTER_TO_INT (data));
5060 gtk_init (&argc, &argv);
5062 /* create a new window */
5063 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5064 gtk_widget_set_size_request (GTK_WIDGET (window), 200, 100);
5065 gtk_window_set_title (GTK_WINDOW (window), "GTK Statusbar Example");
5066 g_signal_connect (G_OBJECT (window), "delete_event",
5067 G_CALLBACK (exit), NULL);
5069 vbox = gtk_vbox_new (FALSE, 1);
5070 gtk_container_add (GTK_CONTAINER (window), vbox);
5071 gtk_widget_show (vbox);
5073 status_bar = gtk_statusbar_new ();
5074 gtk_box_pack_start (GTK_BOX (vbox), status_bar, TRUE, TRUE, 0);
5075 gtk_widget_show (status_bar);
5077 context_id = gtk_statusbar_get_context_id(
5078 GTK_STATUSBAR (status_bar), "Statusbar example");
5080 button = gtk_button_new_with_label ("push item");
5081 g_signal_connect (G_OBJECT (button), "clicked",
5082 G_CALLBACK (push_item), GINT_TO_POINTER (context_id));
5083 gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 2);
5084 gtk_widget_show (button);
5086 button = gtk_button_new_with_label ("pop last item");
5087 g_signal_connect (G_OBJECT (button), "clicked",
5088 G_CALLBACK (pop_item), GINT_TO_POINTER (context_id));
5089 gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 2);
5090 gtk_widget_show (button);
5092 /* always display the window as the last step so it all splashes on
5093 * the screen at once. */
5094 gtk_widget_show (window);
5100 <!-- example-end -->
5105 <!-- ----------------------------------------------------------------- -->
5106 <sect1 id="sec-TextEntries">
5107 <title>Text Entries</title>
5109 <para>The Entry widget allows text to be typed and displayed in a single line
5110 text box. The text may be set with function calls that allow new text
5111 to replace, prepend or append the current contents of the Entry widget.</para>
5113 <para>There are two functions for creating Entry widgets:</para>
5115 <programlisting role="C">
5116 GtkWidget *gtk_entry_new( void );
5118 GtkWidget *gtk_entry_new_with_max_length( guint16 max );
5121 <para>The first just creates a new Entry widget, whilst the second creates a
5122 new Entry and sets a limit on the length of the text within the Entry.</para>
5124 <para>There are several functions for altering the text which is currently
5125 within the Entry widget.</para>
5127 <programlisting role="C">
5128 void gtk_entry_set_text( GtkEntry *entry,
5129 const gchar *text );
5131 void gtk_entry_append_text( GtkEntry *entry,
5132 const gchar *text );
5134 void gtk_entry_prepend_text( GtkEntry *entry,
5135 const gchar *text );
5138 <para>The function gtk_entry_set_text sets the contents of the Entry widget,
5139 replacing the current contents. The functions gtk_entry_append_text
5140 and gtk_entry_prepend_text allow the current contents to be appended
5141 and prepended to.</para>
5143 <para>The next function allows the current insertion point to be set.</para>
5145 <programlisting role="C">
5146 void gtk_entry_set_position( GtkEntry *entry,
5150 <para>The contents of the Entry can be retrieved by using a call to the
5151 following function. This is useful in the callback functions described below.</para>
5153 <programlisting role="C">
5154 gchar *gtk_entry_get_text( GtkEntry *entry );
5157 <para>The value returned by this function is used internally, and must not
5158 be freed using either free() or g_free()</para>
5160 <para>If we don't want the contents of the Entry to be changed by someone typing
5161 into it, we can change its editable state.</para>
5163 <programlisting role="C">
5164 void gtk_entry_set_editable( GtkEntry *entry,
5165 gboolean editable );
5168 <para>The function above allows us to toggle the editable state of the
5169 Entry widget by passing in a TRUE or FALSE value for the <literal>editable</literal>
5172 <para>If we are using the Entry where we don't want the text entered to be
5173 visible, for example when a password is being entered, we can use the
5174 following function, which also takes a boolean flag.</para>
5176 <programlisting role="C">
5177 void gtk_entry_set_visibility( GtkEntry *entry,
5181 <para>A region of the text may be set as selected by using the following
5182 function. This would most often be used after setting some default
5183 text in an Entry, making it easy for the user to remove it.</para>
5185 <programlisting role="C">
5186 void gtk_entry_select_region( GtkEntry *entry,
5191 <para>If we want to catch when the user has entered text, we can connect to
5192 the <literal>activate</literal> or <literal>changed</literal> signal. Activate is raised when the
5193 user hits the enter key within the Entry widget. Changed is raised
5194 when the text changes at all, e.g., for every character entered or
5197 <para>The following code is an example of using an Entry widget.</para>
5202 <imagedata fileref="entry.png" format="png">
5204 </inlinemediaobject>
5207 <programlisting role="C">
5208 <!-- example-start entry entry.c -->
5210 #include <stdio.h>
5211 #include <stdlib.h>
5212 #include <gtk/gtk.h>
5214 void enter_callback( GtkWidget *widget,
5217 const gchar *entry_text;
5218 entry_text = gtk_entry_get_text (GTK_ENTRY (entry));
5219 printf("Entry contents: %s\n", entry_text);
5222 void entry_toggle_editable( GtkWidget *checkbutton,
5225 gtk_editable_set_editable (GTK_EDITABLE (entry),
5226 GTK_TOGGLE_BUTTON (checkbutton)->active);
5229 void entry_toggle_visibility( GtkWidget *checkbutton,
5232 gtk_entry_set_visibility (GTK_ENTRY (entry),
5233 GTK_TOGGLE_BUTTON (checkbutton)->active);
5241 GtkWidget *vbox, *hbox;
5247 gtk_init (&argc, &argv);
5249 /* create a new window */
5250 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5251 gtk_widget_set_size_request (GTK_WIDGET (window), 200, 100);
5252 gtk_window_set_title (GTK_WINDOW (window), "GTK Entry");
5253 g_signal_connect (G_OBJECT (window), "destroy",
5254 G_CALLBACK (gtk_main_quit), NULL);
5255 g_signal_connect_swapped (G_OBJECT (window), "delete_event",
5256 G_CALLBACK (gtk_widget_destroy),
5259 vbox = gtk_vbox_new (FALSE, 0);
5260 gtk_container_add (GTK_CONTAINER (window), vbox);
5261 gtk_widget_show (vbox);
5263 entry = gtk_entry_new ();
5264 gtk_entry_set_max_length (GTK_ENTRY (entry), 50);
5265 g_signal_connect (G_OBJECT (entry), "activate",
5266 G_CALLBACK (enter_callback),
5268 gtk_entry_set_text (GTK_ENTRY (entry), "hello");
5269 tmp_pos = GTK_ENTRY (entry)->text_length;
5270 gtk_editable_insert_text (GTK_EDITABLE (entry), " world", -1, &tmp_pos);
5271 gtk_editable_select_region (GTK_EDITABLE (entry),
5272 0, GTK_ENTRY (entry)->text_length);
5273 gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0);
5274 gtk_widget_show (entry);
5276 hbox = gtk_hbox_new (FALSE, 0);
5277 gtk_container_add (GTK_CONTAINER (vbox), hbox);
5278 gtk_widget_show (hbox);
5280 check = gtk_check_button_new_with_label ("Editable");
5281 gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
5282 g_signal_connect (G_OBJECT (check), "toggled",
5283 G_CALLBACK (entry_toggle_editable), entry);
5284 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), TRUE);
5285 gtk_widget_show (check);
5287 check = gtk_check_button_new_with_label ("Visible");
5288 gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
5289 g_signal_connect (G_OBJECT (check), "toggled",
5290 G_CALLBACK (entry_toggle_visibility), entry);
5291 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), TRUE);
5292 gtk_widget_show (check);
5294 button = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
5295 g_signal_connect_swapped (G_OBJECT (button), "clicked",
5296 G_CALLBACK (gtk_widget_destroy),
5298 gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
5299 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
5300 gtk_widget_grab_default (button);
5301 gtk_widget_show (button);
5303 gtk_widget_show (window);
5309 <!-- example-end -->
5314 <!-- ----------------------------------------------------------------- -->
5315 <sect1 id="sec-SpinButtons">
5316 <title>Spin Buttons</title>
5318 <para>The Spin Button widget is generally used to allow the user to select a
5319 value from a range of numeric values. It consists of a text
5320 entry box with up and down arrow buttons attached to the
5321 side. Selecting one of the buttons causes the value to "spin" up and
5322 down the range of possible values. The entry box may also be edited
5323 directly to enter a specific value.</para>
5325 <para>The Spin Button allows the value to have zero or a number of decimal
5326 places and to be incremented/decremented in configurable steps. The
5327 action of holding down one of the buttons optionally results in an
5328 acceleration of change in the value according to how long it is
5331 <para>The Spin Button uses an <link linkend="ch-Adjustments">Adjustment</link>
5332 object to hold information about the range of values that the spin
5333 button can take. This makes for a powerful Spin Button widget.</para>
5335 <para>Recall that an adjustment widget is created with the following
5336 function, which illustrates the information that it holds:</para>
5338 <programlisting role="C">
5339 GtkObject *gtk_adjustment_new( gfloat value,
5342 gfloat step_increment,
5343 gfloat page_increment,
5347 <para>These attributes of an Adjustment are used by the Spin Button in the
5348 following way:</para>
5351 <listitem><simpara> <literal>value</literal>: initial value for the Spin Button</simpara>
5353 <listitem><simpara> <literal>lower</literal>: lower range value</simpara>
5355 <listitem><simpara> <literal>upper</literal>: upper range value</simpara>
5357 <listitem><simpara> <literal>step_increment</literal>: value to increment/decrement when pressing
5358 mouse button 1 on a button</simpara>
5360 <listitem><simpara> <literal>page_increment</literal>: value to increment/decrement when pressing
5361 mouse button 2 on a button</simpara>
5363 <listitem><simpara> <literal>page_size</literal>: unused</simpara>
5367 <para>Additionally, mouse button 3 can be used to jump directly to the
5368 <literal>upper</literal> or <literal>lower</literal> values when used to select one of the
5369 buttons. Lets look at how to create a Spin Button:</para>
5371 <programlisting role="C">
5372 GtkWidget *gtk_spin_button_new( GtkAdjustment *adjustment,
5377 <para>The <literal>climb_rate</literal> argument take a value between 0.0 and 1.0 and
5378 indicates the amount of acceleration that the Spin Button has. The
5379 <literal>digits</literal> argument specifies the number of decimal places to which
5380 the value will be displayed.</para>
5382 <para>A Spin Button can be reconfigured after creation using the following
5385 <programlisting role="C">
5386 void gtk_spin_button_configure( GtkSpinButton *spin_button,
5387 GtkAdjustment *adjustment,
5392 <para>The <literal>spin_button</literal> argument specifies the Spin Button widget that is
5393 to be reconfigured. The other arguments are as specified above.</para>
5395 <para>The adjustment can be set and retrieved independantly using the
5396 following two functions:</para>
5398 <programlisting role="C">
5399 void gtk_spin_button_set_adjustment( GtkSpinButton *spin_button,
5400 GtkAdjustment *adjustment );
5402 GtkAdjustment *gtk_spin_button_get_adjustment( GtkSpinButton *spin_button );
5405 <para>The number of decimal places can also be altered using:</para>
5407 <programlisting role="C">
5408 void gtk_spin_button_set_digits( GtkSpinButton *spin_button,
5412 <para>The value that a Spin Button is currently displaying can be changed
5413 using the following function:</para>
5415 <programlisting role="C">
5416 void gtk_spin_button_set_value( GtkSpinButton *spin_button,
5420 <para>The current value of a Spin Button can be retrieved as either a
5421 floating point or integer value with the following functions:</para>
5423 <programlisting role="C">
5424 gfloat gtk_spin_button_get_value_as_float( GtkSpinButton *spin_button );
5426 gint gtk_spin_button_get_value_as_int( GtkSpinButton *spin_button );
5429 <para>If you want to alter the value of a Spin Value relative to its current
5430 value, then the following function can be used:</para>
5432 <programlisting role="C">
5433 void gtk_spin_button_spin( GtkSpinButton *spin_button,
5434 GtkSpinType direction,
5438 <para>The <literal>direction</literal> parameter can take one of the following values:</para>
5440 <programlisting role="C">
5441 GTK_SPIN_STEP_FORWARD
5442 GTK_SPIN_STEP_BACKWARD
5443 GTK_SPIN_PAGE_FORWARD
5444 GTK_SPIN_PAGE_BACKWARD
5447 GTK_SPIN_USER_DEFINED
5450 <para>This function packs in quite a bit of functionality, which I will
5451 attempt to clearly explain. Many of these settings use values from the
5452 Adjustment object that is associated with a Spin Button.</para>
5454 <para><literal>GTK_SPIN_STEP_FORWARD</literal> and <literal>GTK_SPIN_STEP_BACKWARD</literal> change the
5455 value of the Spin Button by the amount specified by <literal>increment</literal>,
5456 unless <literal>increment</literal> is equal to 0, in which case the value is
5457 changed by the value of <literal>step_increment</literal> in theAdjustment.</para>
5459 <para><literal>GTK_SPIN_PAGE_FORWARD</literal> and <literal>GTK_SPIN_PAGE_BACKWARD</literal> simply
5460 alter the value of the Spin Button by <literal>increment</literal>.</para>
5462 <para><literal>GTK_SPIN_HOME</literal> sets the value of the Spin Button to the bottom of
5463 the Adjustments range.</para>
5465 <para><literal>GTK_SPIN_END</literal> sets the value of the Spin Button to the top of the
5466 Adjustments range.</para>
5468 <para><literal>GTK_SPIN_USER_DEFINED</literal> simply alters the value of the Spin Button
5469 by the specified amount.</para>
5471 <para>We move away from functions for setting and retreving the range attributes
5472 of the Spin Button now, and move onto functions that effect the
5473 appearance and behaviour of the Spin Button widget itself.</para>
5475 <para>The first of these functions is used to constrain the text box of the
5476 Spin Button such that it may only contain a numeric value. This
5477 prevents a user from typing anything other than numeric values into
5478 the text box of a Spin Button:</para>
5480 <programlisting role="C">
5481 void gtk_spin_button_set_numeric( GtkSpinButton *spin_button,
5485 <para>You can set whether a Spin Button will wrap around between the upper
5486 and lower range values with the following function:</para>
5488 <programlisting role="C">
5489 void gtk_spin_button_set_wrap( GtkSpinButton *spin_button,
5493 <para>You can set a Spin Button to round the value to the nearest
5494 <literal>step_increment</literal>, which is set within the Adjustment object used
5495 with the Spin Button. This is accomplished with the following
5498 <programlisting role="C">
5499 void gtk_spin_button_set_snap_to_ticks( GtkSpinButton *spin_button,
5500 gboolean snap_to_ticks );
5503 <para>The update policy of a Spin Button can be changed with the following
5506 <programlisting role="C">
5507 void gtk_spin_button_set_update_policy( GtkSpinButton *spin_button,
5508 GtkSpinButtonUpdatePolicy policy );
5511 <para><!-- TODO: find out what this does - TRG --></para>
5513 <para>The possible values of <literal>policy</literal> are either <literal>GTK_UPDATE_ALWAYS</literal> or
5514 <literal>GTK_UPDATE_IF_VALID</literal>.</para>
5516 <para>These policies affect the behavior of a Spin Button when parsing
5517 inserted text and syncing its value with the values of the
5520 <para>In the case of <literal>GTK_UPDATE_IF_VALID</literal> the Spin Button only value
5521 gets changed if the text input is a numeric value that is within the
5522 range specified by the Adjustment. Otherwise the text is reset to the
5523 current value.</para>
5525 <para>In case of <literal>GTK_UPDATE_ALWAYS</literal> we ignore errors while converting
5526 text into a numeric value.</para>
5528 <para>The appearance of the buttons used in a Spin Button can be changed
5529 using the following function:</para>
5531 <programlisting role="C">
5532 void gtk_spin_button_set_shadow_type( GtkSpinButton *spin_button,
5533 GtkShadowType shadow_type );
5536 <para>As usual, the <literal>shadow_type</literal> can be one of:</para>
5538 <programlisting role="C">
5541 GTK_SHADOW_ETCHED_IN
5542 GTK_SHADOW_ETCHED_OUT
5545 <para>Finally, you can explicitly request that a Spin Button update itself:</para>
5547 <programlisting role="C">
5548 void gtk_spin_button_update( GtkSpinButton *spin_button );
5551 <para>It's example time again.</para>
5556 <imagedata fileref="spinbutton.png" format="png">
5558 </inlinemediaobject>
5561 <programlisting role="C">
5562 <!-- example-start spinbutton spinbutton.c -->
5564 #include <stdio.h>
5565 #include <gtk/gtk.h>
5567 static GtkWidget *spinner1;
5569 void toggle_snap( GtkWidget *widget,
5570 GtkSpinButton *spin )
5572 gtk_spin_button_set_snap_to_ticks (spin, GTK_TOGGLE_BUTTON (widget)->active);
5575 void toggle_numeric( GtkWidget *widget,
5576 GtkSpinButton *spin )
5578 gtk_spin_button_set_numeric (spin, GTK_TOGGLE_BUTTON (widget)->active);
5581 void change_digits( GtkWidget *widget,
5582 GtkSpinButton *spin )
5584 gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinner1),
5585 gtk_spin_button_get_value_as_int (spin));
5588 void get_value( GtkWidget *widget,
5593 GtkSpinButton *spin;
5595 spin = GTK_SPIN_BUTTON (spinner1);
5596 label = GTK_LABEL (g_object_get_data (G_OBJECT (widget), "user_data"));
5597 if (GPOINTER_TO_INT (data) == 1)
5598 sprintf (buf, "%d", gtk_spin_button_get_value_as_int (spin));
5600 sprintf (buf, "%0.*f", spin->digits,
5601 gtk_spin_button_get_value (spin));
5602 gtk_label_set_text (label, buf);
5612 GtkWidget *main_vbox;
5615 GtkWidget *spinner2;
5619 GtkWidget *val_label;
5622 /* Initialise GTK */
5623 gtk_init (&argc, &argv);
5625 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5627 g_signal_connect (G_OBJECT (window), "destroy",
5628 G_CALLBACK (gtk_main_quit),
5631 gtk_window_set_title (GTK_WINDOW (window), "Spin Button");
5633 main_vbox = gtk_vbox_new (FALSE, 5);
5634 gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 10);
5635 gtk_container_add (GTK_CONTAINER (window), main_vbox);
5637 frame = gtk_frame_new ("Not accelerated");
5638 gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
5640 vbox = gtk_vbox_new (FALSE, 0);
5641 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
5642 gtk_container_add (GTK_CONTAINER (frame), vbox);
5644 /* Day, month, year spinners */
5646 hbox = gtk_hbox_new (FALSE, 0);
5647 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
5649 vbox2 = gtk_vbox_new (FALSE, 0);
5650 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5652 label = gtk_label_new ("Day :");
5653 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5654 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5656 adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 31.0, 1.0,
5658 spinner = gtk_spin_button_new (adj, 0, 0);
5659 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
5660 gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5662 vbox2 = gtk_vbox_new (FALSE, 0);
5663 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5665 label = gtk_label_new ("Month :");
5666 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5667 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5669 adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 12.0, 1.0,
5671 spinner = gtk_spin_button_new (adj, 0, 0);
5672 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
5673 gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5675 vbox2 = gtk_vbox_new (FALSE, 0);
5676 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5678 label = gtk_label_new ("Year :");
5679 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5680 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5682 adj = (GtkAdjustment *) gtk_adjustment_new (1998.0, 0.0, 2100.0,
5684 spinner = gtk_spin_button_new (adj, 0, 0);
5685 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), FALSE);
5686 gtk_widget_set_size_request (spinner, 55, -1);
5687 gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5689 frame = gtk_frame_new ("Accelerated");
5690 gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
5692 vbox = gtk_vbox_new (FALSE, 0);
5693 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
5694 gtk_container_add (GTK_CONTAINER (frame), vbox);
5696 hbox = gtk_hbox_new (FALSE, 0);
5697 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5699 vbox2 = gtk_vbox_new (FALSE, 0);
5700 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5702 label = gtk_label_new ("Value :");
5703 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5704 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5706 adj = (GtkAdjustment *) gtk_adjustment_new (0.0, -10000.0, 10000.0,
5708 spinner1 = gtk_spin_button_new (adj, 1.0, 2);
5709 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner1), TRUE);
5710 gtk_widget_set_size_request (spinner1, 100, -1);
5711 gtk_box_pack_start (GTK_BOX (vbox2), spinner1, FALSE, TRUE, 0);
5713 vbox2 = gtk_vbox_new (FALSE, 0);
5714 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5716 label = gtk_label_new ("Digits :");
5717 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5718 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5720 adj = (GtkAdjustment *) gtk_adjustment_new (2, 1, 5, 1, 1, 0);
5721 spinner2 = gtk_spin_button_new (adj, 0.0, 0);
5722 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner2), TRUE);
5723 g_signal_connect (G_OBJECT (adj), "value_changed",
5724 G_CALLBACK (change_digits),
5726 gtk_box_pack_start (GTK_BOX (vbox2), spinner2, FALSE, TRUE, 0);
5728 hbox = gtk_hbox_new (FALSE, 0);
5729 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5731 button = gtk_check_button_new_with_label ("Snap to 0.5-ticks");
5732 g_signal_connect (G_OBJECT (button), "clicked",
5733 G_CALLBACK (toggle_snap),
5735 gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
5736 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
5738 button = gtk_check_button_new_with_label ("Numeric only input mode");
5739 g_signal_connect (G_OBJECT (button), "clicked",
5740 G_CALLBACK (toggle_numeric),
5742 gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
5743 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
5745 val_label = gtk_label_new ("");
5747 hbox = gtk_hbox_new (FALSE, 0);
5748 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5749 button = gtk_button_new_with_label ("Value as Int");
5750 g_object_set_data (G_OBJECT (button), "user_data", val_label);
5751 g_signal_connect (G_OBJECT (button), "clicked",
5752 G_CALLBACK (get_value),
5753 GINT_TO_POINTER (1));
5754 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
5756 button = gtk_button_new_with_label ("Value as Float");
5757 g_object_set_data (G_OBJECT (button), "user_data", val_label);
5758 g_signal_connect (G_OBJECT (button), "clicked",
5759 G_CALLBACK (get_value),
5760 GINT_TO_POINTER (2));
5761 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
5763 gtk_box_pack_start (GTK_BOX (vbox), val_label, TRUE, TRUE, 0);
5764 gtk_label_set_text (GTK_LABEL (val_label), "0");
5766 hbox = gtk_hbox_new (FALSE, 0);
5767 gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, TRUE, 0);
5769 button = gtk_button_new_with_label ("Close");
5770 g_signal_connect_swapped (G_OBJECT (button), "clicked",
5771 G_CALLBACK (gtk_widget_destroy),
5773 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
5775 gtk_widget_show_all (window);
5777 /* Enter the event loop */
5783 <!-- example-end -->
5788 <!-- ----------------------------------------------------------------- -->
5789 <sect1 id="sec-ComboBox">
5790 <title>Combo Box</title>
5792 <para>The combo box is another fairly simple widget that is really just a
5793 collection of other widgets. From the user's point of view, the widget
5794 consists of a text entry box and a pull down menu from which the user
5795 can select one of a set of predefined entries. Alternatively, the user
5796 can type a different option directly into the text box.</para>
5798 <para>The following extract from the structure that defines a Combo Box
5799 identifies several of the components:</para>
5801 <programlisting role="C">
5812 <para>As you can see, the Combo Box has two principal parts that you really
5813 care about: an entry and a list.</para>
5815 <para>First off, to create a combo box, use:</para>
5817 <programlisting role="C">
5818 GtkWidget *gtk_combo_new( void );
5821 <para>Now, if you want to set the string in the entry section of the combo
5822 box, this is done by manipulating the <literal>entry</literal> widget directly:</para>
5824 <programlisting role="C">
5825 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), "My String.");
5828 <para>To set the values in the popdown list, one uses the function:</para>
5830 <programlisting role="C">
5831 void gtk_combo_set_popdown_strings( GtkCombo *combo,
5835 <para>Before you can do this, you have to assemble a GList of the strings
5836 that you want. GList is a linked list implementation that is part of
5837 <link linkend="ch-GLib">GLib</link>, a library supporing GTK. For the
5838 moment, the quick and dirty explanation is that you need to set up a
5839 GList pointer, set it equal to NULL, then append strings to it with</para>
5841 <programlisting role="C">
5842 GList *g_list_append( GList *glist,
5846 <para>It is important that you set the initial GList pointer to NULL. The
5847 value returned from the g_list_append function must be used as the new
5848 pointer to the GList.</para>
5850 <para>Here's a typical code segment for creating a set of options:</para>
5852 <programlisting role="C">
5855 glist = g_list_append(glist, "String 1");
5856 glist = g_list_append(glist, "String 2");
5857 glist = g_list_append(glist, "String 3");
5858 glist = g_list_append(glist, "String 4");
5860 gtk_combo_set_popdown_strings( GTK_COMBO(combo), glist) ;
5862 /* can free glist now, combo takes a copy */
5865 <para>The combo widget makes a copy of the strings passed to it in the glist
5866 structure. As a result, you need to make sure you free the memory used
5867 by the list if that is appropriate for your application.</para>
5869 <para>At this point you have a working combo box that has been set up.
5870 There are a few aspects of its behavior that you can change. These
5871 are accomplished with the functions: </para>
5873 <programlisting role="C">
5874 void gtk_combo_set_use_arrows( GtkCombo *combo,
5877 void gtk_combo_set_use_arrows_always( GtkCombo *combo,
5880 void gtk_combo_set_case_sensitive( GtkCombo *combo,
5884 <para><literal>gtk_combo_set_use_arrows()</literal> lets the user change the value in the
5885 entry using the up/down arrow keys. This doesn't bring up the list, but
5886 rather replaces the current text in the entry with the next list entry
5887 (up or down, as your key choice indicates). It does this by searching
5888 in the list for the item corresponding to the current value in the
5889 entry and selecting the previous/next item accordingly. Usually in an
5890 entry the arrow keys are used to change focus (you can do that anyway
5891 using TAB). Note that when the current item is the last of the list
5892 and you press arrow-down it changes the focus (the same applies with
5893 the first item and arrow-up).</para>
5895 <para>If the current value in the entry is not in the list, then the
5896 function of <literal>gtk_combo_set_use_arrows()</literal> is disabled.</para>
5898 <para><literal>gtk_combo_set_use_arrows_always()</literal> similarly allows the use the
5899 the up/down arrow keys to cycle through the choices in the dropdown
5900 list, except that it wraps around the values in the list, completely
5901 disabling the use of the up and down arrow keys for changing focus.</para>
5903 <para><literal>gtk_combo_set_case_sensitive()</literal> toggles whether or not GTK
5904 searches for entries in a case sensitive manner. This is used when the
5905 Combo widget is asked to find a value from the list using the current
5906 entry in the text box. This completion can be performed in either a
5907 case sensitive or insensitive manner, depending upon the use of this
5908 function. The Combo widget can also simply complete the current entry
5909 if the user presses the key combination MOD-1 and "Tab". MOD-1 is
5910 often mapped to the "Alt" key, by the <literal>xmodmap</literal> utility. Note,
5911 however that some window managers also use this key combination, which
5912 will override its use within GTK.</para>
5914 <para>Now that we have a combo box, tailored to look and act how we want it,
5915 all that remains is being able to get data from the combo box. This is
5916 relatively straightforward. The majority of the time, all you are
5917 going to care about getting data from is the entry. The entry is
5918 accessed simply by <literal>GTK_ENTRY(GTK_COMBO(combo)->entry)</literal>. The
5919 two principal things that you are going to want to do with it are
5920 attach to the activate signal, which indicates that the user has
5921 pressed the Return or Enter key, and read the text. The first is
5922 accomplished using something like:</para>
5924 <programlisting role="C">
5925 gtk_signal_connect(GTK_OBJECT(GTK_COMB(combo)->entry), "activate",
5926 GTK_SIGNAL_FUNC (my_callback_function), my_data);
5929 <para>Getting the text at any arbitrary time is accomplished by simply using
5930 the entry function:</para>
5932 <programlisting role="C">
5933 gchar *gtk_entry_get_text(GtkEntry *entry);
5936 <para>Such as:</para>
5938 <programlisting role="C">
5941 string = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry));
5944 <para>That's about all there is to it. There is a function</para>
5946 <programlisting role="C">
5947 void gtk_combo_disable_activate(GtkCombo *combo);
5950 <para>that will disable the activate signal on the entry widget in the combo
5951 box. Personally, I can't think of why you'd want to use it, but it
5954 <!-- There is also a function to set the string on a particular item, void
5955 gtk_combo_set_item_string(GtkCombo *combo, GtkItem *item, const gchar
5956 *item_value), but this requires that you have a pointer to the
5957 appropriate Item. Frankly, I have no idea how to do that.
5962 <!-- ----------------------------------------------------------------- -->
5963 <sect1 id="sec-Calendar">
5964 <title>Calendar</title>
5966 <para>The Calendar widget is an effective way to display and retrieve
5967 monthly date related information. It is a very simple widget to create
5968 and work with.</para>
5970 <para>Creating a GtkCalendar widget is a simple as: </para>
5972 <programlisting role="C">
5973 GtkWidget *gtk_calendar_new();
5976 <para>There might be times where you need to change a lot of information
5977 within this widget and the following functions allow you to make
5978 multiple change to a Calendar widget without the user seeing multiple
5979 on-screen updates.</para>
5981 <programlisting role="C">
5982 void gtk_calendar_freeze( GtkCalendar *Calendar );
5984 void gtk_calendar_thaw ( GtkCalendar *Calendar );
5987 <para>They work just like the freeze/thaw functions of every other
5990 <para>The Calendar widget has a few options that allow you to change the way
5991 the widget both looks and operates by using the function</para>
5993 <programlisting role="C">
5994 void gtk_calendar_display_options( GtkCalendar *calendar,
5995 GtkCalendarDisplayOptions flags );
5998 <para>The <literal>flags</literal> argument can be formed by combining either of the
5999 following five options using the logical bitwise OR (|) operation:</para>
6002 <listitem><simpara> GTK_CALENDAR_SHOW_HEADING - this option specifies that
6003 the month and year should be shown when drawing the calendar.</simpara>
6006 <listitem><simpara> GTK_CALENDAR_SHOW_DAY_NAMES - this option specifies that the
6007 three letter descriptions should be displayed for each day (eg
6008 Mon,Tue, etc.).</simpara>
6011 <listitem><simpara> GTK_CALENDAR_NO_MONTH_CHANGE - this option states that the user
6012 should not and can not change the currently displayed month. This can
6013 be good if you only need to display a particular month such as if you
6014 are displaying 12 calendar widgets for every month in a particular
6018 <listitem><simpara> GTK_CALENDAR_SHOW_WEEK_NUMBERS - this option specifies that the
6019 number for each week should be displayed down the left side of the
6020 calendar. (eg. Jan 1 = Week 1,Dec 31 = Week 52).</simpara>
6023 <listitem><simpara> GTK_CALENDAR_WEEK_START_MONDAY - this option states that the
6024 calander week will start on Monday instead of Sunday which is the
6025 default. This only affects the order in which days are displayed from
6026 left to right.</simpara>
6030 <para>The following functions are used to set the the currently displayed
6033 <programlisting role="C">
6034 gint gtk_calendar_select_month( GtkCalendar *calendar,
6038 void gtk_calendar_select_day( GtkCalendar *calendar,
6042 <para>The return value from <literal>gtk_calendar_select_month()</literal> is a boolean
6043 value indicating whether the selection was successful.</para>
6045 <para>With <literal>gtk_calendar_select_day()</literal> the specified day number is
6046 selected within the current month, if that is possible. A
6047 <literal>day</literal> value of 0 will deselect any current selection.</para>
6049 <para>In addition to having a day selected, any number of days in the month
6050 may be "marked". A marked day is highlighted within the calendar
6051 display. The following functions are provided to manipulate marked
6054 <programlisting role="C">
6055 gint gtk_calendar_mark_day( GtkCalendar *calendar,
6058 gint gtk_calendar_unmark_day( GtkCalendar *calendar,
6061 void gtk_calendar_clear_marks( GtkCalendar *calendar);
6064 <para>The currently marked days are stored within an array within the
6065 GtkCalendar structure. This array is 31 elements long so to test
6066 whether a particular day is currently marked, you need to access the
6067 corresponding element of the array (don't forget in C that array
6068 elements are numbered 0 to n-1). For example:</para>
6070 <programlisting role="C">
6071 GtkCalendar *calendar;
6072 calendar = gtk_calendar_new();
6076 /* Is day 7 marked? */
6077 if (calendar->marked_date[7-1])
6081 <para>Note that marks are persistent across month and year changes.</para>
6083 <para>The final Calendar widget function is used to retrieve the currently
6084 selected date, month and/or year.</para>
6086 <programlisting role="C">
6087 void gtk_calendar_get_date( GtkCalendar *calendar,
6093 <para>This function requires you to pass the addresses of <literal>guint</literal>
6094 variables, into which the result will be placed. Passing <literal>NULL</literal> as
6095 a value will result in the corresponding value not being returned.</para>
6097 <para>The Calendar widget can generate a number of signals indicating date
6098 selection and change. The names of these signals are self explanatory,
6102 <listitem><simpara> <literal>month_changed</literal></simpara>
6104 <listitem><simpara> <literal>day_selected</literal></simpara>
6106 <listitem><simpara> <literal>day_selected_double_click</literal></simpara>
6108 <listitem><simpara> <literal>prev_month</literal></simpara>
6110 <listitem><simpara> <literal>next_month</literal></simpara>
6112 <listitem><simpara> <literal>prev_year</literal></simpara>
6114 <listitem><simpara> <literal>next_year</literal></simpara>
6118 <para>That just leaves us with the need to put all of this together into
6119 example code.</para>
6124 <imagedata fileref="calendar.png" format="png">
6126 </inlinemediaobject>
6129 <programlisting role="C">
6130 <!-- example-start calendar calendar.c -->
6132 * Copyright (C) 1998 Cesar Miquel, Shawn T. Amundson, Mattias Grönlund
6133 * Copyright (C) 2000 Tony Gale
6135 * This program is free software; you can redistribute it and/or modify
6136 * it under the terms of the GNU General Public License as published by
6137 * the Free Software Foundation; either version 2 of the License, or
6138 * (at your option) any later version.
6140 * This program is distributed in the hope that it will be useful,
6141 * but WITHOUT ANY WARRANTY; without even the implied warranty of
6142 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6143 * GNU General Public License for more details.
6145 * You should have received a copy of the GNU General Public License
6146 * along with this program; if not, write to the Free Software
6147 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
6150 #include <gtk/gtk.h>
6151 #include <stdio.h>
6152 #include <string.h>
6153 #include <time.h>
6156 #define DEF_PAD_SMALL 5
6158 #define TM_YEAR_BASE 1900
6160 typedef struct _CalendarData {
6161 GtkWidget *flag_checkboxes[5];
6162 gboolean settings[5];
6164 GtkWidget *font_dialog;
6166 GtkWidget *prev2_sig;
6167 GtkWidget *prev_sig;
6168 GtkWidget *last_sig;
6173 calendar_show_header,
6175 calendar_month_change,
6177 calendar_monday_first
6184 void calendar_date_to_string( CalendarData *data,
6191 memset (&tm, 0, sizeof (tm));
6192 gtk_calendar_get_date (GTK_CALENDAR (data->window),
6193 &tm.tm_year, &tm.tm_mon, &tm.tm_mday);
6194 tm.tm_year -= TM_YEAR_BASE;
6195 time = mktime (&tm);
6196 strftime (buffer, buff_len-1, "%x", gmtime (&time));
6199 void calendar_set_signal_strings( char *sig_str,
6202 const gchar *prev_sig;
6204 prev_sig = gtk_label_get_text (GTK_LABEL (data->prev_sig));
6205 gtk_label_set_text (GTK_LABEL (data->prev2_sig), prev_sig);
6207 prev_sig = gtk_label_get_text (GTK_LABEL (data->last_sig));
6208 gtk_label_set_text (GTK_LABEL (data->prev_sig), prev_sig);
6209 gtk_label_set_text (GTK_LABEL (data->last_sig), sig_str);
6212 void calendar_month_changed( GtkWidget *widget,
6213 CalendarData *data )
6215 char buffer[256] = "month_changed: ";
6217 calendar_date_to_string (data, buffer+15, 256-15);
6218 calendar_set_signal_strings (buffer, data);
6221 void calendar_day_selected( GtkWidget *widget,
6222 CalendarData *data )
6224 char buffer[256] = "day_selected: ";
6226 calendar_date_to_string (data, buffer+14, 256-14);
6227 calendar_set_signal_strings (buffer, data);
6230 void calendar_day_selected_double_click( GtkWidget *widget,
6231 CalendarData *data )
6234 char buffer[256] = "day_selected_double_click: ";
6236 calendar_date_to_string (data, buffer+27, 256-27);
6237 calendar_set_signal_strings (buffer, data);
6239 memset (&tm, 0, sizeof (tm));
6240 gtk_calendar_get_date (GTK_CALENDAR (data->window),
6241 &tm.tm_year, &tm.tm_mon, &tm.tm_mday);
6242 tm.tm_year -= TM_YEAR_BASE;
6244 if (GTK_CALENDAR (data->window)->marked_date[tm.tm_mday-1] == 0)
6246 gtk_calendar_mark_day (GTK_CALENDAR (data->window), tm.tm_mday);
6250 gtk_calendar_unmark_day (GTK_CALENDAR (data->window), tm.tm_mday);
6254 void calendar_prev_month( GtkWidget *widget,
6255 CalendarData *data )
6257 char buffer[256] = "prev_month: ";
6259 calendar_date_to_string (data, buffer+12, 256-12);
6260 calendar_set_signal_strings (buffer, data);
6263 void calendar_next_month( GtkWidget *widget,
6264 CalendarData *data )
6266 char buffer[256] = "next_month: ";
6268 calendar_date_to_string (data, buffer+12, 256-12);
6269 calendar_set_signal_strings (buffer, data);
6272 void calendar_prev_year( GtkWidget *widget,
6273 CalendarData *data )
6275 char buffer[256] = "prev_year: ";
6277 calendar_date_to_string (data, buffer+11, 256-11);
6278 calendar_set_signal_strings (buffer, data);
6281 void calendar_next_year( GtkWidget *widget,
6282 CalendarData *data )
6284 char buffer[256] = "next_year: ";
6286 calendar_date_to_string (data, buffer+11, 256-11);
6287 calendar_set_signal_strings (buffer, data);
6291 void calendar_set_flags( CalendarData *calendar )
6295 for (i = 0; i < 5; i++)
6296 if (calendar->settings[i])
6298 options=options + (1<<i);
6300 if (calendar->window)
6301 gtk_calendar_display_options (GTK_CALENDAR (calendar->window), options);
6304 void calendar_toggle_flag( GtkWidget *toggle,
6305 CalendarData *calendar )
6310 for (i = 0; i < 5; i++)
6311 if (calendar->flag_checkboxes[i] == toggle)
6314 calendar->settings[j] = !calendar->settings[j];
6315 calendar_set_flags (calendar);
6319 void calendar_font_selection_ok( GtkWidget *button,
6320 CalendarData *calendar )
6323 PangoFontDescription *font_desc;
6325 calendar->font = gtk_font_selection_dialog_get_font_name (
6326 GTK_FONT_SELECTION_DIALOG (calendar->font_dialog));
6327 if (calendar->window)
6329 font_desc = pango_font_description_from_string (calendar->font);
6332 style = gtk_style_copy (gtk_widget_get_style (calendar->window));
6333 style->font_desc = font_desc;
6334 gtk_widget_set_style (calendar->window, style);
6339 void calendar_select_font( GtkWidget *button,
6340 CalendarData *calendar )
6344 if (!calendar->font_dialog) {
6345 window = gtk_font_selection_dialog_new ("Font Selection Dialog");
6346 g_return_if_fail (GTK_IS_FONT_SELECTION_DIALOG (window));
6347 calendar->font_dialog = window;
6349 gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE);
6351 g_signal_connect (G_OBJECT (window), "destroy",
6352 G_CALLBACK (gtk_widget_destroyed),
6353 &calendar->font_dialog);
6355 g_signal_connect (G_OBJECT (GTK_FONT_SELECTION_DIALOG (window)->ok_button),
6356 "clicked", G_CALLBACK (calendar_font_selection_ok),
6358 g_signal_connect_swapped (G_OBJECT (GTK_FONT_SELECTION_DIALOG (window)->cancel_button),
6360 G_CALLBACK (gtk_widget_destroy),
6361 calendar->font_dialog);
6363 window=calendar->font_dialog;
6364 if (!GTK_WIDGET_VISIBLE (window))
6365 gtk_widget_show (window);
6367 gtk_widget_destroy (window);
6371 void create_calendar()
6374 GtkWidget *vbox, *vbox2, *vbox3;
6377 GtkWidget *calendar;
6381 GtkWidget *separator;
6384 static CalendarData calendar_data;
6392 { "Show Day Names" },
6393 { "No Month Change" },
6394 { "Show Week Numbers" },
6395 { "Week Start Monday" }
6399 calendar_data.window = NULL;
6400 calendar_data.font = NULL;
6401 calendar_data.font_dialog = NULL;
6403 for (i = 0; i < 5; i++) {
6404 calendar_data.settings[i] = 0;
6407 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6408 gtk_window_set_title (GTK_WINDOW (window), "GtkCalendar Example");
6409 gtk_container_set_border_width (GTK_CONTAINER (window), 5);
6410 g_signal_connect (G_OBJECT (window), "destroy",
6411 G_CALLBACK (gtk_main_quit),
6413 g_signal_connect (G_OBJECT (window), "delete-event",
6414 G_CALLBACK (gtk_false),
6417 gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
6419 vbox = gtk_vbox_new (FALSE, DEF_PAD);
6420 gtk_container_add (GTK_CONTAINER (window), vbox);
6423 * The top part of the window, Calendar, flags and fontsel.
6426 hbox = gtk_hbox_new (FALSE, DEF_PAD);
6427 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, DEF_PAD);
6428 hbbox = gtk_hbutton_box_new ();
6429 gtk_box_pack_start (GTK_BOX (hbox), hbbox, FALSE, FALSE, DEF_PAD);
6430 gtk_button_box_set_layout (GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_SPREAD);
6431 gtk_box_set_spacing (GTK_BOX (hbbox), 5);
6433 /* Calendar widget */
6434 frame = gtk_frame_new ("Calendar");
6435 gtk_box_pack_start (GTK_BOX (hbbox), frame, FALSE, TRUE, DEF_PAD);
6436 calendar=gtk_calendar_new ();
6437 calendar_data.window = calendar;
6438 calendar_set_flags (&calendar_data);
6439 gtk_calendar_mark_day (GTK_CALENDAR (calendar), 19);
6440 gtk_container_add( GTK_CONTAINER (frame), calendar);
6441 g_signal_connect (G_OBJECT (calendar), "month_changed",
6442 G_CALLBACK (calendar_month_changed),
6443 &calendar_data);
6444 g_signal_connect (G_OBJECT (calendar), "day_selected",
6445 G_CALLBACK (calendar_day_selected),
6446 &calendar_data);
6447 g_signal_connect (G_OBJECT (calendar), "day_selected_double_click",
6448 G_CALLBACK (calendar_day_selected_double_click),
6449 &calendar_data);
6450 g_signal_connect (G_OBJECT (calendar), "prev_month",
6451 G_CALLBACK (calendar_prev_month),
6452 &calendar_data);
6453 g_signal_connect (G_OBJECT (calendar), "next_month",
6454 G_CALLBACK (calendar_next_month),
6455 &calendar_data);
6456 g_signal_connect (G_OBJECT (calendar), "prev_year",
6457 G_CALLBACK (calendar_prev_year),
6458 &calendar_data);
6459 g_signal_connect (G_OBJECT (calendar), "next_year",
6460 G_CALLBACK (calendar_next_year),
6461 &calendar_data);
6464 separator = gtk_vseparator_new ();
6465 gtk_box_pack_start (GTK_BOX (hbox), separator, FALSE, TRUE, 0);
6467 vbox2 = gtk_vbox_new (FALSE, DEF_PAD);
6468 gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, DEF_PAD);
6470 /* Build the Right frame with the flags in */
6472 frame = gtk_frame_new ("Flags");
6473 gtk_box_pack_start (GTK_BOX (vbox2), frame, TRUE, TRUE, DEF_PAD);
6474 vbox3 = gtk_vbox_new (TRUE, DEF_PAD_SMALL);
6475 gtk_container_add (GTK_CONTAINER (frame), vbox3);
6477 for (i = 0; i < 5; i++)
6479 toggle = gtk_check_button_new_with_label (flags[i].label);
6480 g_signal_connect (G_OBJECT (toggle),
6482 G_CALLBACK (calendar_toggle_flag),
6483 &calendar_data);
6484 gtk_box_pack_start (GTK_BOX (vbox3), toggle, TRUE, TRUE, 0);
6485 calendar_data.flag_checkboxes[i] = toggle;
6487 /* Build the right font-button */
6488 button = gtk_button_new_with_label ("Font...");
6489 g_signal_connect (G_OBJECT (button),
6491 G_CALLBACK (calendar_select_font),
6492 &calendar_data);
6493 gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0);
6496 * Build the Signal-event part.
6499 frame = gtk_frame_new ("Signal events");
6500 gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, DEF_PAD);
6502 vbox2 = gtk_vbox_new (TRUE, DEF_PAD_SMALL);
6503 gtk_container_add (GTK_CONTAINER (frame), vbox2);
6505 hbox = gtk_hbox_new (FALSE, 3);
6506 gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0);
6507 label = gtk_label_new ("Signal:");
6508 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
6509 calendar_data.last_sig = gtk_label_new ("");
6510 gtk_box_pack_start (GTK_BOX (hbox), calendar_data.last_sig, FALSE, TRUE, 0);
6512 hbox = gtk_hbox_new (FALSE, 3);
6513 gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0);
6514 label = gtk_label_new ("Previous signal:");
6515 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
6516 calendar_data.prev_sig = gtk_label_new ("");
6517 gtk_box_pack_start (GTK_BOX (hbox), calendar_data.prev_sig, FALSE, TRUE, 0);
6519 hbox = gtk_hbox_new (FALSE, 3);
6520 gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0);
6521 label = gtk_label_new ("Second previous signal:");
6522 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
6523 calendar_data.prev2_sig = gtk_label_new ("");
6524 gtk_box_pack_start (GTK_BOX (hbox), calendar_data.prev2_sig, FALSE, TRUE, 0);
6526 bbox = gtk_hbutton_box_new ();
6527 gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
6528 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
6530 button = gtk_button_new_with_label ("Close");
6531 g_signal_connect (G_OBJECT (button), "clicked",
6532 G_CALLBACK (gtk_main_quit),
6534 gtk_container_add (GTK_CONTAINER (bbox), button);
6535 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
6536 gtk_widget_grab_default (button);
6538 gtk_widget_show_all (window);
6545 gtk_init (&argc, &argv);
6553 <!-- example-end -->
6558 <!-- ----------------------------------------------------------------- -->
6559 <sect1 id="sec-ColorSelection">
6560 <title>Color Selection</title>
6562 <para>The color selection widget is, not surprisingly, a widget for
6563 interactive selection of colors. This composite widget lets the user
6564 select a color by manipulating RGB (Red, Green, Blue) and HSV (Hue,
6565 Saturation, Value) triples. This is done either by adjusting single
6566 values with sliders or entries, or by picking the desired color from a
6567 hue-saturation wheel/value bar. Optionally, the opacity of the color
6568 can also be set.</para>
6570 <para>The color selection widget currently emits only one signal,
6571 "color_changed", which is emitted whenever the current color in the
6572 widget changes, either when the user changes it or if it's set
6573 explicitly through gtk_color_selection_set_color().</para>
6575 <para>Lets have a look at what the color selection widget has to offer
6576 us. The widget comes in two flavours: gtk_color_selection and
6577 gtk_color_selection_dialog.</para>
6579 <programlisting role="C">
6580 GtkWidget *gtk_color_selection_new( void );
6583 <para>You'll probably not be using this constructor directly. It creates an
6584 orphan ColorSelection widget which you'll have to parent
6585 yourself. The ColorSelection widget inherits from the VBox
6588 <programlisting role="C">
6589 GtkWidget *gtk_color_selection_dialog_new( const gchar *title );
6592 <para>This is the most common color selection constructor. It creates a
6593 ColorSelectionDialog. It consists of a Frame containing a
6594 ColorSelection widget, an HSeparator and an HBox with three buttons,
6595 "Ok", "Cancel" and "Help". You can reach these buttons by accessing
6596 the "ok_button", "cancel_button" and "help_button" widgets in the
6597 ColorSelectionDialog structure,
6598 (i.e., <literal>GTK_COLOR_SELECTION_DIALOG(colorseldialog)->ok_button</literal>)).</para>
6600 <programlisting role="C">
6601 void gtk_color_selection_set_update_policy( GtkColorSelection *colorsel,
6602 GtkUpdateType policy );
6605 <para>This function sets the update policy. The default policy is
6606 <literal>GTK_UPDATE_CONTINUOUS</literal> which means that the current color is
6607 updated continuously when the user drags the sliders or presses the
6608 mouse and drags in the hue-saturation wheel or value bar. If you
6609 experience performance problems, you may want to set the policy to
6610 <literal>GTK_UPDATE_DISCONTINUOUS</literal> or <literal>GTK_UPDATE_DELAYED</literal>.</para>
6612 <programlisting role="C">
6613 void gtk_color_selection_set_opacity( GtkColorSelection *colorsel,
6617 <para>The color selection widget supports adjusting the opacity of a color
6618 (also known as the alpha channel). This is disabled by
6619 default. Calling this function with use_opacity set to TRUE enables
6620 opacity. Likewise, use_opacity set to FALSE will disable opacity.</para>
6622 <programlisting role="C">
6623 void gtk_color_selection_set_color( GtkColorSelection *colorsel,
6627 <para>You can set the current color explicitly by calling this function with
6628 a pointer to an array of colors (gdouble). The length of the array
6629 depends on whether opacity is enabled or not. Position 0 contains the
6630 red component, 1 is green, 2 is blue and opacity is at position 3
6631 (only if opacity is enabled, see
6632 gtk_color_selection_set_opacity()). All values are between 0.0 and
6635 <programlisting role="C">
6636 void gtk_color_selection_get_color( GtkColorSelection *colorsel,
6640 <para>When you need to query the current color, typically when you've
6641 received a "color_changed" signal, you use this function. Color is a
6642 pointer to the array of colors to fill in. See the
6643 gtk_color_selection_set_color() function for the description of this
6646 <para><!-- Need to do a whole section on DnD - TRG
6648 -------------</para>
6650 <para>The color sample areas (right under the hue-saturation wheel) supports
6651 drag and drop. The type of drag and drop is "application/x-color". The
6652 message data consists of an array of 4 (or 5 if opacity is enabled)
6653 gdouble values, where the value at position 0 is 0.0 (opacity on) or
6654 1.0 (opacity off) followed by the red, green and blue values at
6655 positions 1,2 and 3 respectively. If opacity is enabled, the opacity
6656 is passed in the value at position 4.
6659 <para>Here's a simple example demonstrating the use of the
6660 ColorSelectionDialog. The program displays a window containing a
6661 drawing area. Clicking on it opens a color selection dialog, and
6662 changing the color in the color selection dialog changes the
6663 background color.</para>
6668 <imagedata fileref="colorsel.png" format="png">
6670 </inlinemediaobject>
6673 <programlisting role="C">
6674 <!-- example-start colorsel colorsel.c -->
6676 #include <glib.h>
6677 #include <gdk/gdk.h>
6678 #include <gtk/gtk.h>
6680 GtkWidget *colorseldlg = NULL;
6681 GtkWidget *drawingarea = NULL;
6683 /* Color changed handler */
6685 void color_changed_cb( GtkWidget *widget,
6686 GtkColorSelection *colorsel )
6690 GdkColormap *colormap;
6692 /* Get drawingarea colormap */
6694 colormap = gdk_window_get_colormap (drawingarea->window);
6696 /* Get current color */
6698 gtk_color_selection_get_color (colorsel,color);
6700 /* Fit to a unsigned 16 bit integer (0..65535) and
6701 * insert into the GdkColor structure */
6703 gdk_color.red = (guint16)(color[0]*65535.0);
6704 gdk_color.green = (guint16)(color[1]*65535.0);
6705 gdk_color.blue = (guint16)(color[2]*65535.0);
6707 /* Allocate color */
6709 gdk_color_alloc (colormap, &gdk_color);
6711 /* Set window background color */
6713 gdk_window_set_background (drawingarea->window, &gdk_color);
6717 gdk_window_clear (drawingarea->window);
6720 /* Drawingarea event handler */
6722 gint area_event( GtkWidget *widget,
6724 gpointer client_data )
6726 gint handled = FALSE;
6727 GtkWidget *colorsel;
6729 /* Check if we've received a button pressed event */
6731 if (event->type == GDK_BUTTON_PRESS && colorseldlg == NULL)
6733 /* Yes, we have an event and there's no colorseldlg yet! */
6737 /* Create color selection dialog */
6739 colorseldlg = gtk_color_selection_dialog_new ("Select background color");
6741 /* Get the ColorSelection widget */
6743 colorsel = GTK_COLOR_SELECTION_DIALOG (colorseldlg)->colorsel;
6745 /* Connect to the "color_changed" signal, set the client-data
6746 * to the colorsel widget */
6748 g_signal_connect (GTK_OBJECT (colorsel), "color_changed",
6749 GTK_SIGNAL_FUNC (color_changed_cb), (gpointer)colorsel);
6751 /* Show the dialog */
6753 gtk_widget_show (colorseldlg);
6759 /* Close down and exit handler */
6761 gint destroy_window( GtkWidget *widget,
6763 gpointer client_data )
6771 gint main( gint argc,
6776 /* Initialize the toolkit, remove gtk-related commandline stuff */
6778 gtk_init (&argc, &argv);
6780 /* Create toplevel window, set title and policies */
6782 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6783 gtk_window_set_title (GTK_WINDOW (window), "Color selection test");
6784 gtk_window_set_policy (GTK_WINDOW (window), TRUE, TRUE, TRUE);
6786 /* Attach to the "delete" and "destroy" events so we can exit */
6788 g_signal_connect (GTK_OBJECT (window), "delete_event",
6789 GTK_SIGNAL_FUNC (destroy_window), (gpointer)window);
6791 /* Create drawingarea, set size and catch button events */
6793 drawingarea = gtk_drawing_area_new ();
6795 gtk_widget_set_size_request (GTK_WIDGET (drawingarea), 200, 200);
6797 gtk_widget_set_events (drawingarea, GDK_BUTTON_PRESS_MASK);
6799 g_signal_connect (GTK_OBJECT (drawingarea), "event",
6800 GTK_SIGNAL_FUNC (area_event), (gpointer)drawingarea);
6802 /* Add drawingarea to window, then show them both */
6804 gtk_container_add (GTK_CONTAINER (window), drawingarea);
6806 gtk_widget_show (drawingarea);
6807 gtk_widget_show (window);
6809 /* Enter the gtk main loop (this never returns) */
6813 /* Satisfy grumpy compilers */
6817 <!-- example-end -->
6822 <!-- ----------------------------------------------------------------- -->
6823 <sect1 id="sec-FileSelections">
6824 <title>File Selections</title>
6826 <para>The file selection widget is a quick and simple way to display a File
6827 dialog box. It comes complete with Ok, Cancel, and Help buttons, a
6828 great way to cut down on programming time.</para>
6830 <para>To create a new file selection box use:</para>
6832 <programlisting role="C">
6833 GtkWidget *gtk_file_selection_new( gchar *title );
6836 <para>To set the filename, for example to bring up a specific directory, or
6837 give a default filename, use this function:</para>
6839 <programlisting role="C">
6840 void gtk_file_selection_set_filename( GtkFileSelection *filesel,
6844 <para>To grab the text that the user has entered or clicked on, use this
6847 <programlisting role="C">
6848 gchar *gtk_file_selection_get_filename( GtkFileSelection *filesel );
6851 <para>There are also pointers to the widgets contained within the file
6852 selection widget. These are:</para>
6854 <programlisting role="C">
6865 <para>Most likely you will want to use the ok_button, cancel_button, and
6866 help_button pointers in signaling their use.</para>
6868 <para>Included here is an example stolen from testgtk.c, modified to run on
6869 its own. As you will see, there is nothing much to creating a file
6870 selection widget. While in this example the Help button appears on the
6871 screen, it does nothing as there is not a signal attached to it.</para>
6876 <imagedata fileref="filesel.png" format="png">
6878 </inlinemediaobject>
6881 <programlisting role="C">
6882 <!-- example-start filesel filesel.c -->
6884 #include <gtk/gtk.h>
6886 /* Get the selected filename and print it to the console */
6887 void file_ok_sel( GtkWidget *w,
6888 GtkFileSelection *fs )
6890 g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
6898 gtk_init (&argc, &argv);
6900 /* Create a new file selection widget */
6901 filew = gtk_file_selection_new ("File selection");
6903 g_signal_connect (G_OBJECT (filew), "destroy",
6904 G_CALLBACK (gtk_main_quit), NULL);
6905 /* Connect the ok_button to file_ok_sel function */
6906 g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
6908 G_CALLBACK (file_ok_sel), filew);
6910 /* Connect the cancel_button to destroy the widget */
6911 g_signal_connect_swapped (G_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button),
6913 G_CALLBACK (gtk_widget_destroy), filew);
6915 /* Lets set the filename, as if this were a save dialog, and we are giving
6916 a default filename */
6917 gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew),
6920 gtk_widget_show (filew);
6924 <!-- example-end -->
6930 <!-- ***************************************************************** -->
6931 <chapter id="ch-ContainerWidgets">
6932 <title>Container Widgets</title>
6934 <!-- ----------------------------------------------------------------- -->
6935 <sect1 id="sec-EventBox">
6936 <title>The EventBox</title>
6938 <para>Some GTK widgets don't have associated X windows, so they just draw on
6939 their parents. Because of this, they cannot receive events and if they
6940 are incorrectly sized, they don't clip so you can get messy
6941 overwriting, etc. If you require more from these widgets, the EventBox
6944 <para>At first glance, the EventBox widget might appear to be totally
6945 useless. It draws nothing on the screen and responds to no
6946 events. However, it does serve a function - it provides an X window
6947 for its child widget. This is important as many GTK widgets do not
6948 have an associated X window. Not having an X window saves memory and
6949 improves performance, but also has some drawbacks. A widget without an
6950 X window cannot receive events, and does not perform any clipping on
6951 its contents. Although the name <emphasis>EventBox</emphasis> emphasizes the
6952 event-handling function, the widget can also be used for clipping.
6953 (and more, see the example below).</para>
6955 <para>To create a new EventBox widget, use:</para>
6957 <programlisting role="C">
6958 GtkWidget *gtk_event_box_new( void );
6961 <para>A child widget can then be added to this EventBox:</para>
6963 <programlisting role="C">
6964 gtk_container_add( GTK_CONTAINER(event_box), child_widget );
6967 <para>The following example demonstrates both uses of an EventBox - a label
6968 is created that is clipped to a small box, and set up so that a
6969 mouse-click on the label causes the program to exit. Resizing the
6970 window reveals varying amounts of the label.</para>
6975 <imagedata fileref="eventbox.png" format="png">
6977 </inlinemediaobject>
6980 <programlisting role="C">
6981 <!-- example-start eventbox eventbox.c -->
6983 #include <stdlib.h>
6984 #include <gtk/gtk.h>
6990 GtkWidget *event_box;
6993 gtk_init (&argc, &argv);
6995 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6997 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
6999 g_signal_connect (G_OBJECT (window), "destroy",
7000 G_CALLBACK (exit), NULL);
7002 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
7004 /* Create an EventBox and add it to our toplevel window */
7006 event_box = gtk_event_box_new ();
7007 gtk_container_add (GTK_CONTAINER (window), event_box);
7008 gtk_widget_show (event_box);
7010 /* Create a long label */
7012 label = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
7013 gtk_container_add (GTK_CONTAINER (event_box), label);
7014 gtk_widget_show (label);
7016 /* Clip it short. */
7017 gtk_widget_set_size_request (label, 110, 20);
7019 /* And bind an action to it */
7020 gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
7021 g_signal_connect (G_OBJECT (event_box), "button_press_event",
7022 G_CALLBACK (exit), NULL);
7024 /* Yet one more thing you need an X window for ... */
7026 gtk_widget_realize (event_box);
7027 gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1));
7029 gtk_widget_show (window);
7035 <!-- example-end -->
7040 <!-- ----------------------------------------------------------------- -->
7041 <sect1 id="sec-TheAlignmentWidget">
7042 <title>The Alignment widget</title>
7044 <para>The alignment widget allows you to place a widget within its window at
7045 a position and size relative to the size of the Alignment widget
7046 itself. For example, it can be very useful for centering a widget
7047 within the window.</para>
7049 <para>There are only two functions associated with the Alignment widget:</para>
7051 <programlisting role="C">
7052 GtkWidget* gtk_alignment_new( gfloat xalign,
7057 void gtk_alignment_set( GtkAlignment *alignment,
7064 <para>The first function creates a new Alignment widget with the specified
7065 parameters. The second function allows the alignment paramters of an
7066 exisiting Alignment widget to be altered.</para>
7068 <para>All four alignment parameters are floating point numbers which can
7069 range from 0.0 to 1.0. The <literal>xalign</literal> and <literal>yalign</literal> arguments
7070 affect the position of the widget placed within the Alignment
7071 widget. The <literal>xscale</literal> and <literal>yscale</literal> arguments effect the amount of
7072 space allocated to the widget.</para>
7074 <para>A child widget can be added to this Alignment widget using:</para>
7076 <programlisting role="C">
7077 gtk_container_add( GTK_CONTAINER(alignment), child_widget );
7080 <para>For an example of using an Alignment widget, refer to the example for
7081 the <link linkend="sec-ProgressBars">Progress Bar</link> widget.</para>
7085 <!-- ----------------------------------------------------------------- -->
7086 <sect1 id="sec-FixedContainer">
7087 <title>Fixed Container</title>
7089 <para>The Fixed container allows you to place widgets at a fixed position
7090 within it's window, relative to it's upper left hand corner. The
7091 position of the widgets can be changed dynamically.</para>
7093 <para>There are only three functions associated with the fixed widget:</para>
7095 <programlisting role="C">
7096 GtkWidget* gtk_fixed_new( void );
7098 void gtk_fixed_put( GtkFixed *fixed,
7103 void gtk_fixed_move( GtkFixed *fixed,
7109 <para>The function <literal>gtk_fixed_new</literal> allows you to create a new Fixed
7112 <para><literal>gtk_fixed_put</literal> places <literal>widget</literal> in the container <literal>fixed</literal> at
7113 the position specified by <literal>x</literal> and <literal>y</literal>.</para>
7115 <para><literal>gtk_fixed_move</literal> allows the specified widget to be moved to a new
7118 <para>The following example illustrates how to use the Fixed Container.</para>
7123 <imagedata fileref="fixed.png" format="png">
7125 </inlinemediaobject>
7128 <programlisting role="C">
7129 <!-- example-start fixed fixed.c -->
7131 #include <gtk/gtk.h>
7133 /* I'm going to be lazy and use some global variables to
7134 * store the position of the widget within the fixed
7139 /* This callback function moves the button to a new position
7140 * in the Fixed container. */
7141 void move_button( GtkWidget *widget,
7146 gtk_fixed_move (GTK_FIXED (fixed), widget, x, y);
7152 /* GtkWidget is the storage type for widgets */
7158 /* Initialise GTK */
7159 gtk_init (&argc, &argv);
7161 /* Create a new window */
7162 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
7163 gtk_window_set_title (GTK_WINDOW (window), "Fixed Container");
7165 /* Here we connect the "destroy" event to a signal handler */
7166 g_signal_connect (G_OBJECT (window), "destroy",
7167 G_CALLBACK (gtk_main_quit), NULL);
7169 /* Sets the border width of the window. */
7170 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
7172 /* Create a Fixed Container */
7173 fixed = gtk_fixed_new ();
7174 gtk_container_add (GTK_CONTAINER (window), fixed);
7175 gtk_widget_show (fixed);
7177 for (i = 1 ; i <= 3 ; i++) {
7178 /* Creates a new button with the label "Press me" */
7179 button = gtk_button_new_with_label ("Press me");
7181 /* When the button receives the "clicked" signal, it will call the
7182 * function move_button() passing it the Fixed Container as its
7184 g_signal_connect (G_OBJECT (button), "clicked",
7185 G_CALLBACK (move_button), fixed);
7187 /* This packs the button into the fixed containers window. */
7188 gtk_fixed_put (GTK_FIXED (fixed), button, i*50, i*50);
7190 /* The final step is to display this newly created widget. */
7191 gtk_widget_show (button);
7194 /* Display the window */
7195 gtk_widget_show (window);
7197 /* Enter the event loop */
7202 <!-- example-end -->
7207 <!-- ----------------------------------------------------------------- -->
7208 <sect1 id="sec-LayoutContainer">
7209 <title>Layout Container</title>
7211 <para>The Layout container is similar to the Fixed container except that it
7212 implements an infinite (where infinity is less than 2^32) scrolling
7213 area. The X window system has a limitation where windows can be at
7214 most 32767 pixels wide or tall. The Layout container gets around this
7215 limitation by doing some exotic stuff using window and bit gravities,
7216 so that you can have smooth scrolling even when you have many child
7217 widgets in your scrolling area.</para>
7219 <para>A Layout container is created using:</para>
7221 <programlisting role="C">
7222 GtkWidget *gtk_layout_new( GtkAdjustment *hadjustment,
7223 GtkAdjustment *vadjustment );
7226 <para>As you can see, you can optionally specify the Adjustment objects that
7227 the Layout widget will use for its scrolling.</para>
7229 <para>You can add and move widgets in the Layout container using the
7230 following two functions:</para>
7232 <programlisting role="C">
7233 void gtk_layout_put( GtkLayout *layout,
7238 void gtk_layout_move( GtkLayout *layout,
7244 <para>The size of the Layout container can be set using the next function:</para>
7246 <programlisting role="C">
7247 void gtk_layout_set_size( GtkLayout *layout,
7252 <para>Layout containers are one of the very few widgets in the GTK widget
7253 set that actively repaint themselves on screen as they are changed
7254 using the above functions (the vast majority of widgets queue
7255 requests which are then processed when control returns to the
7256 <literal>gtk_main()</literal> function).</para>
7258 <para>When you want to make a large number of changes to a Layout container,
7259 you can use the following two functions to disable and re-enable this
7260 repainting functionality:</para>
7262 <programlisting role="C">
7263 void gtk_layout_freeze( GtkLayout *layout );
7265 void gtk_layout_thaw( GtkLayout *layout );
7268 <para>The final four functions for use with Layout widgets are for
7269 manipulating the horizontal and vertical adjustment widgets:</para>
7271 <programlisting role="C">
7272 GtkAdjustment* gtk_layout_get_hadjustment( GtkLayout *layout );
7274 GtkAdjustment* gtk_layout_get_vadjustment( GtkLayout *layout );
7276 void gtk_layout_set_hadjustment( GtkLayout *layout,
7277 GtkAdjustment *adjustment );
7279 void gtk_layout_set_vadjustment( GtkLayout *layout,
7280 GtkAdjustment *adjustment);
7285 <!-- ----------------------------------------------------------------- -->
7286 <sect1 id="sec-Frames">
7287 <title>Frames</title>
7289 <para>Frames can be used to enclose one or a group of widgets with a box
7290 which can optionally be labelled. The position of the label and the
7291 style of the box can be altered to suit.</para>
7293 <para>A Frame can be created with the following function:</para>
7295 <programlisting role="C">
7296 GtkWidget *gtk_frame_new( const gchar *label );
7299 <para>The label is by default placed in the upper left hand corner of the
7300 frame. A value of NULL for the <literal>label</literal> argument will result in no
7301 label being displayed. The text of the label can be changed using the
7302 next function.</para>
7304 <programlisting role="C">
7305 void gtk_frame_set_label( GtkFrame *frame,
7306 const gchar *label );
7309 <para>The position of the label can be changed using this function:</para>
7311 <programlisting role="C">
7312 void gtk_frame_set_label_align( GtkFrame *frame,
7317 <para><literal>xalign</literal> and <literal>yalign</literal> take values between 0.0 and 1.0. <literal>xalign</literal>
7318 indicates the position of the label along the top horizontal of the
7319 frame. <literal>yalign</literal> is not currently used. The default value of xalign
7320 is 0.0 which places the label at the left hand end of the frame.</para>
7322 <para>The next function alters the style of the box that is used to outline
7325 <programlisting role="C">
7326 void gtk_frame_set_shadow_type( GtkFrame *frame,
7327 GtkShadowType type);
7330 <para>The <literal>type</literal> argument can take one of the following values:</para>
7331 <programlisting role="C">
7335 GTK_SHADOW_ETCHED_IN (the default)
7336 GTK_SHADOW_ETCHED_OUT
7339 <para>The following code example illustrates the use of the Frame widget.</para>
7344 <imagedata fileref="frame.png" format="png">
7346 </inlinemediaobject>
7349 <programlisting role="C">
7350 <!-- example-start frame frame.c -->
7352 #include <gtk/gtk.h>
7357 /* GtkWidget is the storage type for widgets */
7361 /* Initialise GTK */
7362 gtk_init (&argc, &argv);
7364 /* Create a new window */
7365 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
7366 gtk_window_set_title (GTK_WINDOW (window), "Frame Example");
7368 /* Here we connect the "destroy" event to a signal handler */
7369 g_signal_connect (G_OBJECT (window), "destroy",
7370 G_CALLBACK (gtk_main_quit), NULL);
7372 gtk_widget_set_size_request (window, 300, 300);
7373 /* Sets the border width of the window. */
7374 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
7376 /* Create a Frame */
7377 frame = gtk_frame_new (NULL);
7378 gtk_container_add (GTK_CONTAINER (window), frame);
7380 /* Set the frame's label */
7381 gtk_frame_set_label (GTK_FRAME (frame), "GTK Frame Widget");
7383 /* Align the label at the right of the frame */
7384 gtk_frame_set_label_align (GTK_FRAME (frame), 1.0, 0.0);
7386 /* Set the style of the frame */
7387 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
7389 gtk_widget_show (frame);
7391 /* Display the window */
7392 gtk_widget_show (window);
7394 /* Enter the event loop */
7399 <!-- example-end -->
7403 <!-- ----------------------------------------------------------------- -->
7404 <sect1 id="sec-AspectFrames">
7405 <title>Aspect Frames</title>
7407 <para>The aspect frame widget is like a frame widget, except that it also
7408 enforces the aspect ratio (that is, the ratio of the width to the
7409 height) of the child widget to have a certain value, adding extra
7410 space if necessary. This is useful, for instance, if you want to
7411 preview a larger image. The size of the preview should vary when the
7412 user resizes the window, but the aspect ratio needs to always match
7413 the original image.</para>
7415 <para>To create a new aspect frame use:</para>
7417 <programlisting role="C">
7418 GtkWidget *gtk_aspect_frame_new( const gchar *label,
7425 <para><literal>xalign</literal> and <literal>yalign</literal> specify alignment as with Alignment
7426 widgets. If <literal>obey_child</literal> is true, the aspect ratio of a child
7427 widget will match the aspect ratio of the ideal size it requests.
7428 Otherwise, it is given by <literal>ratio</literal>.</para>
7430 <para>To change the options of an existing aspect frame, you can use:</para>
7432 <programlisting role="C">
7433 void gtk_aspect_frame_set( GtkAspectFrame *aspect_frame,
7440 <para>As an example, the following program uses an AspectFrame to present a
7441 drawing area whose aspect ratio will always be 2:1, no matter how the
7442 user resizes the top-level window.</para>
7447 <imagedata fileref="aspectframe.png" format="png">
7449 </inlinemediaobject>
7452 <programlisting role="C">
7453 <!-- example-start aspectframe aspectframe.c -->
7455 #include <gtk/gtk.h>
7461 GtkWidget *aspect_frame;
7462 GtkWidget *drawing_area;
7463 gtk_init (&argc, &argv);
7465 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
7466 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
7467 g_signal_connect (G_OBJECT (window), "destroy",
7468 G_CALLBACK (gtk_main_quit), NULL);
7469 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
7471 /* Create an aspect_frame and add it to our toplevel window */
7473 aspect_frame = gtk_aspect_frame_new ("2x1", /* label */
7476 2, /* xsize/ysize = 2 */
7477 FALSE /* ignore child's aspect */);
7479 gtk_container_add (GTK_CONTAINER (window), aspect_frame);
7480 gtk_widget_show (aspect_frame);
7482 /* Now add a child widget to the aspect frame */
7484 drawing_area = gtk_drawing_area_new ();
7486 /* Ask for a 200x200 window, but the AspectFrame will give us a 200x100
7487 * window since we are forcing a 2x1 aspect ratio */
7488 gtk_widget_set_size_request (drawing_area, 200, 200);
7489 gtk_container_add (GTK_CONTAINER (aspect_frame), drawing_area);
7490 gtk_widget_show (drawing_area);
7492 gtk_widget_show (window);
7496 <!-- example-end -->
7501 <!-- ----------------------------------------------------------------- -->
7502 <sect1 id="sec-PanedWindowWidgets">
7503 <title>Paned Window Widgets</title>
7505 <para>The paned window widgets are useful when you want to divide an area
7506 into two parts, with the relative size of the two parts controlled by
7507 the user. A groove is drawn between the two portions with a handle
7508 that the user can drag to change the ratio. The division can either be
7509 horizontal (HPaned) or vertical (VPaned).</para>
7511 <para>To create a new paned window, call one of:</para>
7513 <programlisting role="C">
7514 GtkWidget *gtk_hpaned_new (void);
7516 GtkWidget *gtk_vpaned_new (void);
7519 <para>After creating the paned window widget, you need to add child widgets
7520 to its two halves. To do this, use the functions:</para>
7522 <programlisting role="C">
7523 void gtk_paned_add1 (GtkPaned *paned, GtkWidget *child);
7525 void gtk_paned_add2 (GtkPaned *paned, GtkWidget *child);
7528 <para><literal>gtk_paned_add1()</literal> adds the child widget to the left or top half of
7529 the paned window. <literal>gtk_paned_add2()</literal> adds the child widget to the
7530 right or bottom half of the paned window.</para>
7532 <para>As an example, we will create part of the user interface of an
7533 imaginary email program. A window is divided into two portions
7534 vertically, with the top portion being a list of email messages and
7535 the bottom portion the text of the email message. Most of the program
7536 is pretty straightforward. A couple of points to note: text can't be
7537 added to a Text widget until it is realized. This could be done by
7538 calling <literal>gtk_widget_realize()</literal>, but as a demonstration of an
7539 alternate technique, we connect a handler to the "realize" signal to
7540 add the text. Also, we need to add the <literal>GTK_SHRINK</literal> option to some
7541 of the items in the table containing the text window and its
7542 scrollbars, so that when the bottom portion is made smaller, the
7543 correct portions shrink instead of being pushed off the bottom of the
7549 <imagedata fileref="paned.png" format="png">
7551 </inlinemediaobject>
7554 <programlisting role="C">
7555 <!-- example-start paned paned.c -->
7557 #include <stdio.h>
7558 #include <gtk/gtk.h>
7560 /* Create the list of "messages" */
7561 GtkWidget *create_list( void )
7564 GtkWidget *scrolled_window;
7565 GtkWidget *tree_view;
7566 GtkListStore *model;
7568 GtkCellRenderer *cell;
7569 GtkTreeViewColumn *column;
7573 /* Create a new scrolled window, with scrollbars only if needed */
7574 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
7575 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
7576 GTK_POLICY_AUTOMATIC,
7577 GTK_POLICY_AUTOMATIC);
7579 model = gtk_list_store_new (1, G_TYPE_STRING);
7580 tree_view = gtk_tree_view_new ();
7581 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window),
7583 gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (model));
7584 gtk_widget_show (tree_view);
7586 /* Add some messages to the window */
7587 for (i = 0; i < 10; i++) {
7588 gchar *msg = g_strdup_printf ("Message #%d", i);
7589 gtk_list_store_append (GTK_LIST_STORE (model), &iter);
7590 gtk_list_store_set (GTK_LIST_STORE (model),
7597 cell = gtk_cell_renderer_text_new ();
7599 column = gtk_tree_view_column_new_with_attributes ("Messages",
7604 gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
7605 GTK_TREE_VIEW_COLUMN (column));
7607 return scrolled_window;
7610 /* Add some text to our text widget - this is a callback that is invoked
7611 when our window is realized. We could also force our window to be
7612 realized with gtk_widget_realize, but it would have to be part of
7613 a hierarchy first */
7615 void insert_text (GtkTextBuffer *buffer)
7619 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
7621 gtk_text_buffer_insert (buffer, &iter,
7622 "From: pathfinder@nasa.gov\n"
7623 "To: mom@nasa.gov\n"
7624 "Subject: Made it!\n"
7626 "We just got in this morning. The weather has been\n"
7627 "great - clear but cold, and there are lots of fun sights.\n"
7628 "Sojourner says hi. See you soon.\n"
7632 /* Create a scrolled text area that displays a "message" */
7633 GtkWidget *create_text( void )
7635 GtkWidget *scrolled_window;
7637 GtkTextBuffer *buffer;
7639 view = gtk_text_view_new ();
7640 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
7642 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
7643 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
7644 GTK_POLICY_AUTOMATIC,
7645 GTK_POLICY_AUTOMATIC);
7647 gtk_container_add (GTK_CONTAINER (scrolled_window), view);
7648 insert_text (buffer);
7650 gtk_widget_show_all (scrolled_window);
7652 return scrolled_window;
7663 gtk_init (&argc, &argv);
7665 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
7666 gtk_window_set_title (GTK_WINDOW (window), "Paned Windows");
7667 g_signal_connect (G_OBJECT (window), "destroy",
7668 G_CALLBACK (gtk_main_quit), NULL);
7669 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
7670 gtk_widget_set_size_request (GTK_WIDGET (window), 450, 400);
7672 /* create a vpaned widget and add it to our toplevel window */
7674 vpaned = gtk_vpaned_new ();
7675 gtk_container_add (GTK_CONTAINER (window), vpaned);
7676 gtk_widget_show (vpaned);
7678 /* Now create the contents of the two halves of the window */
7680 list = create_list ();
7681 gtk_paned_add1 (GTK_PANED (vpaned), list);
7682 gtk_widget_show (list);
7684 text = create_text ();
7685 gtk_paned_add2 (GTK_PANED (vpaned), text);
7686 gtk_widget_show (text);
7687 gtk_widget_show (window);
7693 <!-- example-end -->
7698 <!-- ----------------------------------------------------------------- -->
7699 <sect1 id="sec-Viewports">
7700 <title>Viewports</title>
7702 <para>It is unlikely that you will ever need to use the Viewport widget
7703 directly. You are much more likely to use the
7704 <link linkend="sec-ScrolledWindows">Scrolled Window</link> widget which
7705 itself uses the Viewport.</para>
7707 <para>A viewport widget allows you to place a larger widget within it such
7708 that you can view a part of it at a time. It uses
7709 <link linkend="ch-Adjustments">Adjustments</link> to define the area that
7710 is currently in view.</para>
7712 <para>A Viewport is created with the function</para>
7714 <programlisting role="C">
7715 GtkWidget *gtk_viewport_new( GtkAdjustment *hadjustment,
7716 GtkAdjustment *vadjustment );
7719 <para>As you can see you can specify the horizontal and vertical Adjustments
7720 that the widget is to use when you create the widget. It will create
7721 its own if you pass NULL as the value of the arguments.</para>
7723 <para>You can get and set the adjustments after the widget has been created
7724 using the following four functions:</para>
7726 <programlisting role="C">
7727 GtkAdjustment *gtk_viewport_get_hadjustment (GtkViewport *viewport );
7729 GtkAdjustment *gtk_viewport_get_vadjustment (GtkViewport *viewport );
7731 void gtk_viewport_set_hadjustment( GtkViewport *viewport,
7732 GtkAdjustment *adjustment );
7734 void gtk_viewport_set_vadjustment( GtkViewport *viewport,
7735 GtkAdjustment *adjustment );
7738 <para>The only other viewport function is used to alter its appearance:</para>
7740 <programlisting role="C">
7741 void gtk_viewport_set_shadow_type( GtkViewport *viewport,
7742 GtkShadowType type );
7745 <para>Possible values for the <literal>type</literal> parameter are:</para>
7746 <programlisting role="C">
7750 GTK_SHADOW_ETCHED_IN,
7751 GTK_SHADOW_ETCHED_OUT
7756 <!-- ----------------------------------------------------------------- -->
7757 <sect1 id="sec-ScrolledWindows"
7758 <title>Scrolled Windows</title>
7760 <para>Scrolled windows are used to create a scrollable area with another
7761 widget inside it. You may insert any type of widget into a scrolled
7762 window, and it will be accessible regardless of the size by using the
7765 <para>The following function is used to create a new scrolled window.</para>
7767 <programlisting role="C">
7768 GtkWidget *gtk_scrolled_window_new( GtkAdjustment *hadjustment,
7769 GtkAdjustment *vadjustment );
7772 <para>Where the first argument is the adjustment for the horizontal
7773 direction, and the second, the adjustment for the vertical direction.
7774 These are almost always set to NULL.</para>
7776 <programlisting role="C">
7777 void gtk_scrolled_window_set_policy( GtkScrolledWindow *scrolled_window,
7778 GtkPolicyType hscrollbar_policy,
7779 GtkPolicyType vscrollbar_policy );
7782 <para>This sets the policy to be used with respect to the scrollbars.
7783 The first argument is the scrolled window you wish to change. The second
7784 sets the policy for the horizontal scrollbar, and the third the policy for
7785 the vertical scrollbar.</para>
7787 <para>The policy may be one of <literal>GTK_POLICY_AUTOMATIC</literal> or
7788 <literal>GTK_POLICY_ALWAYS</literal>. <literal>GTK_POLICY_AUTOMATIC</literal> will automatically
7789 decide whether you need scrollbars, whereas <literal>GTK_POLICY_ALWAYS</literal>
7790 will always leave the scrollbars there.</para>
7792 <para>You can then place your object into the scrolled window using the
7793 following function.</para>
7795 <programlisting role="C">
7796 void gtk_scrolled_window_add_with_viewport( GtkScrolledWindow *scrolled_window,
7800 <para>Here is a simple example that packs a table eith 100 toggle buttons
7801 into a scrolled window. I've only commented on the parts that may be
7807 <imagedata fileref="scrolledwin.png" format="png">
7809 </inlinemediaobject>
7812 <programlisting role="C">
7813 <!-- example-start scrolledwin scrolledwin.c -->
7815 #include <stdio.h>
7816 #include <gtk/gtk.h>
7818 void destroy( GtkWidget *widget,
7827 static GtkWidget *window;
7828 GtkWidget *scrolled_window;
7834 gtk_init (&argc, &argv);
7836 /* Create a new dialog window for the scrolled window to be
7838 window = gtk_dialog_new ();
7839 g_signal_connect (G_OBJECT (window), "destroy",
7840 G_CALLBACK (destroy), NULL);
7841 gtk_window_set_title (GTK_WINDOW (window), "GtkScrolledWindow example");
7842 gtk_container_set_border_width (GTK_CONTAINER (window), 0);
7843 gtk_widget_set_size_request (window, 300, 300);
7845 /* create a new scrolled window. */
7846 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
7848 gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 10);
7850 /* the policy is one of GTK_POLICY AUTOMATIC, or GTK_POLICY_ALWAYS.
7851 * GTK_POLICY_AUTOMATIC will automatically decide whether you need
7852 * scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars
7853 * there. The first one is the horizontal scrollbar, the second,
7855 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
7856 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
7857 /* The dialog window is created with a vbox packed into it. */
7858 gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)->vbox), scrolled_window,
7860 gtk_widget_show (scrolled_window);
7862 /* create a table of 10 by 10 squares. */
7863 table = gtk_table_new (10, 10, FALSE);
7865 /* set the spacing to 10 on x and 10 on y */
7866 gtk_table_set_row_spacings (GTK_TABLE (table), 10);
7867 gtk_table_set_col_spacings (GTK_TABLE (table), 10);
7869 /* pack the table into the scrolled window */
7870 gtk_scrolled_window_add_with_viewport (
7871 GTK_SCROLLED_WINDOW (scrolled_window), table);
7872 gtk_widget_show (table);
7874 /* this simply creates a grid of toggle buttons on the table
7875 * to demonstrate the scrolled window. */
7876 for (i = 0; i < 10; i++)
7877 for (j = 0; j < 10; j++) {
7878 sprintf (buffer, "button (%d,%d)\n", i, j);
7879 button = gtk_toggle_button_new_with_label (buffer);
7880 gtk_table_attach_defaults (GTK_TABLE (table), button,
7882 gtk_widget_show (button);
7885 /* Add a "close" button to the bottom of the dialog */
7886 button = gtk_button_new_with_label ("close");
7887 g_signal_connect_swapped (G_OBJECT (button), "clicked",
7888 G_CALLBACK (gtk_widget_destroy),
7891 /* this makes it so the button is the default. */
7893 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
7894 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0);
7896 /* This grabs this button to be the default button. Simply hitting
7897 * the "Enter" key will cause this button to activate. */
7898 gtk_widget_grab_default (button);
7899 gtk_widget_show (button);
7901 gtk_widget_show (window);
7907 <!-- example-end -->
7910 <para>Try playing with resizing the window. You'll notice how the scrollbars
7911 react. You may also wish to use the gtk_widget_set_size_request() call to set
7912 the default size of the window or other widgets.</para>
7916 <!-- ----------------------------------------------------------------- -->
7917 <sect1 id="sec-ButtonBoxes">
7918 <title>Button Boxes</title>
7920 <para>Button Boxes are a convenient way to quickly layout a group of
7921 buttons. They come in both horizontal and vertical flavours. You
7922 create a new Button Box with one of the following calls, which create
7923 a horizontal or vertical box, respectively:</para>
7925 <programlisting role="C">
7926 GtkWidget *gtk_hbutton_box_new( void );
7928 GtkWidget *gtk_vbutton_box_new( void );
7931 <para>The only attributes pertaining to button boxes effect how the buttons
7932 are laid out. You can change the spacing between the buttons with:</para>
7934 <programlisting role="C">
7935 void gtk_hbutton_box_set_spacing_default( gint spacing );
7937 void gtk_vbutton_box_set_spacing_default( gint spacing );
7940 <para>Similarly, the current spacing values can be queried using:</para>
7942 <programlisting role="C">
7943 gint gtk_hbutton_box_get_spacing_default( void );
7945 gint gtk_vbutton_box_get_spacing_default( void );
7948 <para>The second attribute that we can access effects the layout of the
7949 buttons within the box. It is set using one of:</para>
7951 <programlisting role="C">
7952 void gtk_hbutton_box_set_layout_default( GtkButtonBoxStyle layout );
7954 void gtk_vbutton_box_set_layout_default( GtkButtonBoxStyle layout );
7957 <para>The <literal>layout</literal> argument can take one of the following values:</para>
7959 <programlisting role="C">
7960 GTK_BUTTONBOX_DEFAULT_STYLE
7961 GTK_BUTTONBOX_SPREAD
7967 <para>The current layout setting can be retrieved using:</para>
7969 <programlisting role="C">
7970 GtkButtonBoxStyle gtk_hbutton_box_get_layout_default( void );
7972 GtkButtonBoxStyle gtk_vbutton_box_get_layout_default( void );
7975 <para>Buttons are added to a Button Box using the usual function:</para>
7977 <programlisting role="C">
7978 gtk_container_add( GTK_CONTAINER(button_box), child_widget );
7981 <para>Here's an example that illustrates all the different layout settings
7982 for Button Boxes.</para>
7987 <imagedata fileref="buttonbox.png" format="png">
7989 </inlinemediaobject>
7992 <programlisting role="C">
7993 <!-- example-start buttonbox buttonbox.c -->
7995 #include <gtk/gtk.h>
7997 /* Create a Button Box with the specified parameters */
7998 GtkWidget *create_bbox( gint horizontal,
8009 frame = gtk_frame_new (title);
8012 bbox = gtk_hbutton_box_new ();
8014 bbox = gtk_vbutton_box_new ();
8016 gtk_container_set_border_width (GTK_CONTAINER (bbox), 5);
8017 gtk_container_add (GTK_CONTAINER (frame), bbox);
8019 /* Set the appearance of the Button Box */
8020 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), layout);
8021 gtk_box_set_spacing (GTK_BOX (bbox), spacing);
8022 /*gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), child_w, child_h);*/
8024 button = gtk_button_new_from_stock (GTK_STOCK_OK);
8025 gtk_container_add (GTK_CONTAINER (bbox), button);
8027 button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
8028 gtk_container_add (GTK_CONTAINER (bbox), button);
8030 button = gtk_button_new_from_stock (GTK_STOCK_HELP);
8031 gtk_container_add (GTK_CONTAINER (bbox), button);
8039 static GtkWidget* window = NULL;
8040 GtkWidget *main_vbox;
8043 GtkWidget *frame_horz;
8044 GtkWidget *frame_vert;
8046 /* Initialize GTK */
8047 gtk_init (&argc, &argv);
8049 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
8050 gtk_window_set_title (GTK_WINDOW (window), "Button Boxes");
8052 g_signal_connect (G_OBJECT (window), "destroy",
8053 G_CALLBACK (gtk_main_quit),
8056 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
8058 main_vbox = gtk_vbox_new (FALSE, 0);
8059 gtk_container_add (GTK_CONTAINER (window), main_vbox);
8061 frame_horz = gtk_frame_new ("Horizontal Button Boxes");
8062 gtk_box_pack_start (GTK_BOX (main_vbox), frame_horz, TRUE, TRUE, 10);
8064 vbox = gtk_vbox_new (FALSE, 0);
8065 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
8066 gtk_container_add (GTK_CONTAINER (frame_horz), vbox);
8068 gtk_box_pack_start (GTK_BOX (vbox),
8069 create_bbox (TRUE, "Spread (spacing 40)", 40, 85, 20, GTK_BUTTONBOX_SPREAD),
8072 gtk_box_pack_start (GTK_BOX (vbox),
8073 create_bbox (TRUE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
8076 gtk_box_pack_start (GTK_BOX (vbox),
8077 create_bbox (TRUE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
8080 gtk_box_pack_start (GTK_BOX (vbox),
8081 create_bbox (TRUE, "End (spacing 10)", 10, 85, 20, GTK_BUTTONBOX_END),
8084 frame_vert = gtk_frame_new ("Vertical Button Boxes");
8085 gtk_box_pack_start (GTK_BOX (main_vbox), frame_vert, TRUE, TRUE, 10);
8087 hbox = gtk_hbox_new (FALSE, 0);
8088 gtk_container_set_border_width (GTK_CONTAINER (hbox), 10);
8089 gtk_container_add (GTK_CONTAINER (frame_vert), hbox);
8091 gtk_box_pack_start (GTK_BOX (hbox),
8092 create_bbox (FALSE, "Spread (spacing 5)", 5, 85, 20, GTK_BUTTONBOX_SPREAD),
8095 gtk_box_pack_start (GTK_BOX (hbox),
8096 create_bbox (FALSE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
8099 gtk_box_pack_start (GTK_BOX (hbox),
8100 create_bbox (FALSE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
8103 gtk_box_pack_start (GTK_BOX (hbox),
8104 create_bbox (FALSE, "End (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_END),
8107 gtk_widget_show_all (window);
8109 /* Enter the event loop */
8114 <!-- example-end -->
8119 <!-- ----------------------------------------------------------------- -->
8120 <sect1 id="sec-Toolbar">
8121 <title>Toolbar</title>
8123 <para>Toolbars are usually used to group some number of widgets in order to
8124 simplify customization of their look and layout. Typically a toolbar
8125 consists of buttons with icons, labels and tooltips, but any other
8126 widget can also be put inside a toolbar. Finally, items can be
8127 arranged horizontally or vertically and buttons can be displayed with
8128 icons, labels, or both.</para>
8130 <para>Creating a toolbar is (as one may already suspect) done with the
8131 following function:</para>
8133 <programlisting role="C">
8134 GtkWidget *gtk_toolbar_new( GtkOrientation orientation,
8135 GtkToolbarStyle style );
8138 <para>where orientation may be one of:</para>
8140 <programlisting role="C">
8141 GTK_ORIENTATION_HORIZONTAL
8142 GTK_ORIENTATION_VERTICAL
8145 <para>and style one of:</para>
8147 <programlisting role="C">
8153 <para>The style applies to all the buttons created with the `item' functions
8154 (not to buttons inserted into toolbar as separate widgets).</para>
8156 <para>After creating a toolbar one can append, prepend and insert items
8157 (that means simple text strings) or elements (that means any widget
8158 types) into the toolbar. To describe an item we need a label text, a
8159 tooltip text, a private tooltip text, an icon for the button and a
8160 callback function for it. For example, to append or prepend an item
8161 you may use the following functions:</para>
8163 <programlisting role="C">
8164 GtkWidget *gtk_toolbar_append_item( GtkToolbar *toolbar,
8166 const char *tooltip_text,
8167 const char *tooltip_private_text,
8169 GtkSignalFunc callback,
8170 gpointer user_data );
8172 GtkWidget *gtk_toolbar_prepend_item( GtkToolbar *toolbar,
8174 const char *tooltip_text,
8175 const char *tooltip_private_text,
8177 GtkSignalFunc callback,
8178 gpointer user_data );
8181 <para>If you want to use gtk_toolbar_insert_item, the only additional
8182 parameter which must be specified is the position in which the item
8183 should be inserted, thus:</para>
8185 <programlisting role="C">
8186 GtkWidget *gtk_toolbar_insert_item( GtkToolbar *toolbar,
8188 const char *tooltip_text,
8189 const char *tooltip_private_text,
8191 GtkSignalFunc callback,
8196 <para>To simplify adding spaces between toolbar items, you may use the
8197 following functions:</para>
8199 <programlisting role="C">
8200 void gtk_toolbar_append_space( GtkToolbar *toolbar );
8202 void gtk_toolbar_prepend_space( GtkToolbar *toolbar );
8204 void gtk_toolbar_insert_space( GtkToolbar *toolbar,
8208 <para>While the size of the added space can be set globally for a
8209 whole toolbar with the function:</para>
8211 <programlisting role="C">
8212 void gtk_toolbar_set_space_size( GtkToolbar *toolbar,
8216 <para>If it's required, the orientation of a toolbar and its style can be
8217 changed "on the fly" using the following functions:</para>
8219 <programlisting role="C">
8220 void gtk_toolbar_set_orientation( GtkToolbar *toolbar,
8221 GtkOrientation orientation );
8223 void gtk_toolbar_set_style( GtkToolbar *toolbar,
8224 GtkToolbarStyle style );
8226 void gtk_toolbar_set_tooltips( GtkToolbar *toolbar,
8230 <para>Where <literal>orientation</literal> is one of <literal>GTK_ORIENTATION_HORIZONTAL</literal> or
8231 <literal>GTK_ORIENTATION_VERTICAL</literal>. The <literal>style</literal> is used to set
8232 appearance of the toolbar items by using one of
8233 <literal>GTK_TOOLBAR_ICONS</literal>, <literal>GTK_TOOLBAR_TEXT</literal>, or
8234 <literal>GTK_TOOLBAR_BOTH</literal>.</para>
8236 <para>To show some other things that can be done with a toolbar, let's take
8237 the following program (we'll interrupt the listing with some
8238 additional explanations):</para>
8240 <programlisting role="C">
8241 #include <gtk/gtk.h>
8245 /* This function is connected to the Close button or
8246 * closing the window from the WM */
8247 gint delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
8254 <para>The above beginning seems for sure familiar to you if it's not your first
8255 GTK program. There is one additional thing though, we include a nice XPM
8256 picture to serve as an icon for all of the buttons.</para>
8258 <programlisting role="C">
8259 GtkWidget* close_button; /* This button will emit signal to close
8261 GtkWidget* tooltips_button; /* to enable/disable tooltips */
8262 GtkWidget* text_button,
8264 * both_button; /* radio buttons for toolbar style */
8265 GtkWidget* entry; /* a text entry to show packing any widget into
8269 <para>In fact not all of the above widgets are needed here, but to make things
8270 clearer I put them all together.</para>
8272 <programlisting role="C">
8273 /* that's easy... when one of the buttons is toggled, we just
8274 * check which one is active and set the style of the toolbar
8276 * ATTENTION: our toolbar is passed as data to callback ! */
8277 void radio_event (GtkWidget *widget, gpointer data)
8279 if (GTK_TOGGLE_BUTTON (text_button)->active)
8280 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_TEXT);
8281 else if (GTK_TOGGLE_BUTTON (icon_button)->active)
8282 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_ICONS);
8283 else if (GTK_TOGGLE_BUTTON (both_button)->active)
8284 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_BOTH);
8287 /* even easier, just check given toggle button and enable/disable
8289 void toggle_event (GtkWidget *widget, gpointer data)
8291 gtk_toolbar_set_tooltips (GTK_TOOLBAR ( data ),
8292 GTK_TOGGLE_BUTTON (widget)->active );
8296 <para>The above are just two callback functions that will be called when
8297 one of the buttons on a toolbar is pressed. You should already be
8298 familiar with things like this if you've already used toggle buttons (and
8299 radio buttons).</para>
8301 <programlisting role="C">
8302 int main (int argc, char *argv[])
8304 /* Here is our main window (a dialog) and a handle for the handlebox */
8306 GtkWidget* handlebox;
8308 /* Ok, we need a toolbar, an icon with a mask (one for all of
8309 the buttons) and an icon widget to put this icon in (but
8310 we'll create a separate widget for each button) */
8311 GtkWidget * toolbar;
8316 /* this is called in all GTK application. */
8317 gtk_init (&argc, &argv);
8319 /* create a new window with a given title, and nice size */
8320 dialog = gtk_dialog_new ();
8321 gtk_window_set_title ( GTK_WINDOW ( dialog ) , "GTKToolbar Tutorial");
8322 gtk_widget_set_size_request (GTK_WIDGET (dialog), 600, 300);
8323 GTK_WINDOW ( dialog ) ->allow_shrink = TRUE;
8325 /* typically we quit if someone tries to close us */
8326 g_signal_connect ( GTK_OBJECT ( dialog ), "delete_event",
8327 GTK_SIGNAL_FUNC ( delete_event ), NULL);
8329 /* we need to realize the window because we use pixmaps for
8330 * items on the toolbar in the context of it */
8331 gtk_widget_realize ( dialog );
8333 /* to make it nice we'll put the toolbar into the handle box,
8334 * so that it can be detached from the main window */
8335 handlebox = gtk_handle_box_new ();
8336 gtk_box_pack_start ( GTK_BOX ( GTK_DIALOG(dialog)->vbox ),
8337 handlebox, FALSE, FALSE, 5 );
8340 <para>The above should be similar to any other GTK application. Just
8341 initialization of GTK, creating the window, etc. There is only one
8342 thing that probably needs some explanation: a handle box. A handle box
8343 is just another box that can be used to pack widgets in to. The
8344 difference between it and typical boxes is that it can be detached
8345 from a parent window (or, in fact, the handle box remains in the
8346 parent, but it is reduced to a very small rectangle, while all of its
8347 contents are reparented to a new freely floating window). It is
8348 usually nice to have a detachable toolbar, so these two widgets occur
8349 together quite often.</para>
8351 <programlisting role="C">
8352 /* toolbar will be horizontal, with both icons and text, and
8353 * with 5pxl spaces between items and finally,
8354 * we'll also put it into our handlebox */
8355 toolbar = gtk_toolbar_new ( GTK_ORIENTATION_HORIZONTAL,
8357 gtk_container_set_border_width ( GTK_CONTAINER ( toolbar ) , 5 );
8358 gtk_toolbar_set_space_size ( GTK_TOOLBAR ( toolbar ), 5 );
8359 gtk_container_add ( GTK_CONTAINER ( handlebox ) , toolbar );
8361 /* now we create icon with mask: we'll reuse it to create
8362 * icon widgets for toolbar items */
8363 icon = gdk_pixmap_create_from_xpm_d ( dialog->window, &mask,
8364 &dialog->style->white, gtk_xpm );
8367 <para>Well, what we do above is just a straightforward initialization of
8368 the toolbar widget and creation of a GDK pixmap with its mask. If you
8369 want to know something more about using pixmaps, refer to GDK
8370 documentation or to the <link linkend="sec-Pixmaps">Pixmaps</link> section
8371 earlier in this tutorial.</para>
8373 <programlisting role="C">
8374 /* our first item is <close> button */
8375 iconw = gtk_pixmap_new ( icon, mask ); /* icon widget */
8377 gtk_toolbar_append_item ( GTK_TOOLBAR (toolbar), /* our toolbar */
8378 "Close", /* button label */
8379 "Closes this app", /* this button's tooltip */
8380 "Private", /* tooltip private info */
8381 iconw, /* icon widget */
8382 GTK_SIGNAL_FUNC (delete_event), /* a signal */
8384 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) ); /* space after item */
8387 <para>In the above code you see the simplest case: adding a button to
8388 toolbar. Just before appending a new item, we have to construct a
8389 pixmap widget to serve as an icon for this item; this step will have
8390 to be repeated for each new item. Just after the item we also add a
8391 space, so the following items will not touch each other. As you see
8392 gtk_toolbar_append_item returns a pointer to our newly created button
8393 widget, so that we can work with it in the normal way.</para>
8395 <programlisting role="C">
8396 /* now, let's make our radio buttons group... */
8397 iconw = gtk_pixmap_new ( icon, mask );
8398 icon_button = gtk_toolbar_append_element(
8399 GTK_TOOLBAR(toolbar),
8400 GTK_TOOLBAR_CHILD_RADIOBUTTON, /* a type of element */
8401 NULL, /* pointer to widget */
8403 "Only icons in toolbar", /* tooltip */
8404 "Private", /* tooltip private string */
8406 GTK_SIGNAL_FUNC (radio_event), /* signal */
8407 toolbar); /* data for signal */
8408 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
8411 <para>Here we begin creating a radio buttons group. To do this we use
8412 gtk_toolbar_append_element. In fact, using this function one can also
8413 +add simple items or even spaces (type = <literal>GTK_TOOLBAR_CHILD_SPACE</literal>
8414 or +<literal>GTK_TOOLBAR_CHILD_BUTTON</literal>). In the above case we start
8415 creating a radio group. In creating other radio buttons for this group
8416 a pointer to the previous button in the group is required, so that a
8417 list of buttons can be easily constructed (see the section on <link
8418 linkend="sec-RadioButtons"> Radio Buttons </link> earlier in this
8421 <programlisting role="C">
8422 /* following radio buttons refer to previous ones */
8423 iconw = gtk_pixmap_new ( icon, mask );
8425 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
8426 GTK_TOOLBAR_CHILD_RADIOBUTTON,
8429 "Only texts in toolbar",
8432 GTK_SIGNAL_FUNC (radio_event),
8434 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
8436 iconw = gtk_pixmap_new ( icon, mask );
8438 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
8439 GTK_TOOLBAR_CHILD_RADIOBUTTON,
8442 "Icons and text in toolbar",
8445 GTK_SIGNAL_FUNC (radio_event),
8447 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
8448 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(both_button),TRUE);
8451 <para>In the end we have to set the state of one of the buttons manually
8452 (otherwise they all stay in active state, preventing us from switching
8453 between them).</para>
8455 <programlisting role="C">
8456 /* here we have just a simple toggle button */
8457 iconw = gtk_pixmap_new ( icon, mask );
8459 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
8460 GTK_TOOLBAR_CHILD_TOGGLEBUTTON,
8463 "Toolbar with or without tips",
8466 GTK_SIGNAL_FUNC (toggle_event),
8468 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
8469 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tooltips_button),TRUE);
8472 <para>A toggle button can be created in the obvious way (if one knows how to create
8473 radio buttons already).</para>
8475 <programlisting role="C">
8476 /* to pack a widget into toolbar, we only have to
8477 * create it and append it with an appropriate tooltip */
8478 entry = gtk_entry_new ();
8479 gtk_toolbar_append_widget( GTK_TOOLBAR (toolbar),
8481 "This is just an entry",
8484 /* well, it isn't created within thetoolbar, so we must still show it */
8485 gtk_widget_show ( entry );
8488 <para>As you see, adding any kind of widget to a toolbar is simple. The
8489 one thing you have to remember is that this widget must be shown manually
8490 (contrary to other items which will be shown together with the toolbar).</para>
8492 <programlisting role="C">
8493 /* that's it ! let's show everything. */
8494 gtk_widget_show ( toolbar );
8495 gtk_widget_show (handlebox);
8496 gtk_widget_show ( dialog );
8498 /* rest in gtk_main and wait for the fun to begin! */
8505 <para>So, here we are at the end of toolbar tutorial. Of course, to appreciate
8506 it in full you need also this nice XPM icon, so here it is:</para>
8508 <programlisting role="C">
8510 static char * gtk_xpm[] = {
8517 "................+...............",
8518 "..............+++++.............",
8519 "............+++++@@++...........",
8520 "..........+++++@@@@@@++.........",
8521 "........++++@@@@@@@@@@++........",
8522 "......++++@@++++++++@@@++.......",
8523 ".....+++@@@+++++++++++@@@++.....",
8524 "...+++@@@@+++@@@@@@++++@@@@+....",
8525 "..+++@@@@+++@@@@@@@@+++@@@@@++..",
8526 ".++@@@@@@+++@@@@@@@@@@@@@@@@@@++",
8527 ".+#+@@@@@@++@@@@+++@@@@@@@@@@@@+",
8528 ".+##++@@@@+++@@@+++++@@@@@@@@$@.",
8529 ".+###++@@@@+++@@@+++@@@@@++$$$@.",
8530 ".+####+++@@@+++++++@@@@@+@$$$$@.",
8531 ".+#####+++@@@@+++@@@@++@$$$$$$+.",
8532 ".+######++++@@@@@@@++@$$$$$$$$+.",
8533 ".+#######+##+@@@@+++$$$$$$@@$$+.",
8534 ".+###+++##+##+@@++@$$$$$$++$$$+.",
8535 ".+###++++##+##+@@$$$$$$$@+@$$@+.",
8536 ".+###++++++#+++@$$@+@$$@++$$$@+.",
8537 ".+####+++++++#++$$@+@$$++$$$$+..",
8538 ".++####++++++#++$$@+@$++@$$$$+..",
8539 ".+#####+++++##++$$++@+++$$$$$+..",
8540 ".++####+++##+#++$$+++++@$$$$$+..",
8541 ".++####+++####++$$++++++@$$$@+..",
8542 ".+#####++#####++$$+++@++++@$@+..",
8543 ".+#####++#####++$$++@$$@+++$@@..",
8544 ".++####++#####++$$++$$$$$+@$@++.",
8545 ".++####++#####++$$++$$$$$$$$+++.",
8546 ".+++####+#####++$$++$$$$$$$@+++.",
8547 "..+++#########+@$$+@$$$$$$+++...",
8548 "...+++########+@$$$$$$$$@+++....",
8549 ".....+++######+@$$$$$$$+++......",
8550 "......+++#####+@$$$$$@++........",
8551 ".......+++####+@$$$$+++.........",
8552 ".........++###+$$$@++...........",
8553 "..........++##+$@+++............",
8554 "...........+++++++..............",
8555 ".............++++..............."};
8560 <!-- ----------------------------------------------------------------- -->
8561 <sect1 id="sec-Notebooks">
8562 <title>Notebooks</title>
8564 <para>The NoteBook Widget is a collection of "pages" that overlap each
8565 other, each page contains different information with only one page
8566 visible at a time. This widget has become more common lately in GUI
8567 programming, and it is a good way to show blocks of similar
8568 information that warrant separation in their display.</para>
8570 <para>The first function call you will need to know, as you can probably
8571 guess by now, is used to create a new notebook widget.</para>
8573 <programlisting role="C">
8574 GtkWidget *gtk_notebook_new( void );
8577 <para>Once the notebook has been created, there are a number of functions
8578 that operate on the notebook widget. Let's look at them individually.</para>
8580 <para>The first one we will look at is how to position the page indicators.
8581 These page indicators or "tabs" as they are referred to, can be
8582 positioned in four ways: top, bottom, left, or right.</para>
8584 <programlisting role="C">
8585 void gtk_notebook_set_tab_pos( GtkNotebook *notebook,
8586 GtkPositionType pos );
8589 <para>GtkPositionType will be one of the following, which are pretty self
8591 <programlisting role="C">
8598 <para><literal>GTK_POS_TOP</literal> is the default.</para>
8600 <para>Next we will look at how to add pages to the notebook. There are three
8601 ways to add pages to the NoteBook. Let's look at the first two
8602 together as they are quite similar.</para>
8604 <programlisting role="C">
8605 void gtk_notebook_append_page( GtkNotebook *notebook,
8607 GtkWidget *tab_label );
8609 void gtk_notebook_prepend_page( GtkNotebook *notebook,
8611 GtkWidget *tab_label );
8614 <para>These functions add pages to the notebook by inserting them from the
8615 back of the notebook (append), or the front of the notebook (prepend).
8616 <literal>child</literal> is the widget that is placed within the notebook page, and
8617 <literal>tab_label</literal> is the label for the page being added. The <literal>child</literal>
8618 widget must be created separately, and is typically a set of options
8619 setup witin one of the other container widgets, such as a table.</para>
8621 <para>The final function for adding a page to the notebook contains all of
8622 the properties of the previous two, but it allows you to specify what
8623 position you want the page to be in the notebook.</para>
8625 <programlisting role="C">
8626 void gtk_notebook_insert_page( GtkNotebook *notebook,
8628 GtkWidget *tab_label,
8632 <para>The parameters are the same as _append_ and _prepend_ except it
8633 contains an extra parameter, <literal>position</literal>. This parameter is used to
8634 specify what place this page will be inserted into the first page
8635 having position zero.</para>
8637 <para>Now that we know how to add a page, lets see how we can remove a page
8638 from the notebook.</para>
8640 <programlisting role="C">
8641 void gtk_notebook_remove_page( GtkNotebook *notebook,
8645 <para>This function takes the page specified by <literal>page_num</literal> and removes it
8646 from the widget pointed to by <literal>notebook</literal>.</para>
8648 <para>To find out what the current page is in a notebook use the function:</para>
8650 <programlisting role="C">
8651 gint gtk_notebook_get_current_page( GtkNotebook *notebook );
8654 <para>These next two functions are simple calls to move the notebook page
8655 forward or backward. Simply provide the respective function call with
8656 the notebook widget you wish to operate on. Note: When the NoteBook is
8657 currently on the last page, and gtk_notebook_next_page is called, the
8658 notebook will wrap back to the first page. Likewise, if the NoteBook
8659 is on the first page, and gtk_notebook_prev_page is called, the
8660 notebook will wrap to the last page.</para>
8662 <programlisting role="C">
8663 void gtk_notebook_next_page( GtkNoteBook *notebook );
8665 void gtk_notebook_prev_page( GtkNoteBook *notebook );
8668 <para>This next function sets the "active" page. If you wish the notebook to
8669 be opened to page 5 for example, you would use this function. Without
8670 using this function, the notebook defaults to the first page.</para>
8672 <programlisting role="C">
8673 void gtk_notebook_set_page( GtkNotebook *notebook,
8677 <para>The next two functions add or remove the notebook page tabs and the
8678 notebook border respectively.</para>
8680 <programlisting role="C">
8681 void gtk_notebook_set_show_tabs( GtkNotebook *notebook,
8682 gboolean show_tabs);
8684 void gtk_notebook_set_show_border( GtkNotebook *notebook,
8685 gboolean show_border );
8688 <para>The next function is useful when the you have a large number of pages,
8689 and the tabs don't fit on the page. It allows the tabs to be scrolled
8690 through using two arrow buttons.</para>
8692 <programlisting role="C">
8693 void gtk_notebook_set_scrollable( GtkNotebook *notebook,
8694 gboolean scrollable );
8697 <para><literal>show_tabs</literal>, <literal>show_border</literal> and <literal>scrollable</literal> can be either
8698 TRUE or FALSE.</para>
8700 <para>Now let's look at an example, it is expanded from the testgtk.c code
8701 that comes with the GTK distribution. This small program creates a
8702 window with a notebook and six buttons. The notebook contains 11
8703 pages, added in three different ways, appended, inserted, and
8704 prepended. The buttons allow you rotate the tab positions, add/remove
8705 the tabs and border, remove a page, change pages in both a forward and
8706 backward manner, and exit the program.</para>
8711 <imagedata fileref="notebook.png" format="png">
8713 </inlinemediaobject>
8716 <programlisting role="C">
8717 <!-- example-start notebook notebook.c -->
8719 #include <stdio.h>
8720 #include <gtk/gtk.h>
8722 /* This function rotates the position of the tabs */
8723 void rotate_book( GtkButton *button,
8724 GtkNotebook *notebook )
8726 gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos + 1) % 4);
8729 /* Add/Remove the page tabs and the borders */
8730 void tabsborder_book( GtkButton *button,
8731 GtkNotebook *notebook )
8735 if (notebook->show_tabs == 0)
8737 if (notebook->show_border == 0)
8740 gtk_notebook_set_show_tabs (notebook, tval);
8741 gtk_notebook_set_show_border (notebook, bval);
8744 /* Remove a page from the notebook */
8745 void remove_book( GtkButton *button,
8746 GtkNotebook *notebook )
8750 page = gtk_notebook_get_current_page (notebook);
8751 gtk_notebook_remove_page (notebook, page);
8752 /* Need to refresh the widget --
8753 This forces the widget to redraw itself. */
8754 gtk_widget_queue_draw (GTK_WIDGET (notebook));
8757 gint delete( GtkWidget *widget,
8771 GtkWidget *notebook;
8774 GtkWidget *checkbutton;
8779 gtk_init (&argc, &argv);
8781 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
8783 g_signal_connect (G_OBJECT (window), "delete_event",
8784 G_CALLBACK (delete), NULL);
8786 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
8788 table = gtk_table_new (3, 6, FALSE);
8789 gtk_container_add (GTK_CONTAINER (window), table);
8791 /* Create a new notebook, place the position of the tabs */
8792 notebook = gtk_notebook_new ();
8793 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
8794 gtk_table_attach_defaults (GTK_TABLE (table), notebook, 0, 6, 0, 1);
8795 gtk_widget_show (notebook);
8797 /* Let's append a bunch of pages to the notebook */
8798 for (i = 0; i < 5; i++) {
8799 sprintf(bufferf, "Append Frame %d", i + 1);
8800 sprintf(bufferl, "Page %d", i + 1);
8802 frame = gtk_frame_new (bufferf);
8803 gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
8804 gtk_widget_set_size_request (frame, 100, 75);
8805 gtk_widget_show (frame);
8807 label = gtk_label_new (bufferf);
8808 gtk_container_add (GTK_CONTAINER (frame), label);
8809 gtk_widget_show (label);
8811 label = gtk_label_new (bufferl);
8812 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
8815 /* Now let's add a page to a specific spot */
8816 checkbutton = gtk_check_button_new_with_label ("Check me please!");
8817 gtk_widget_set_size_request (checkbutton, 100, 75);
8818 gtk_widget_show (checkbutton);
8820 label = gtk_label_new ("Add page");
8821 gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, label, 2);
8823 /* Now finally let's prepend pages to the notebook */
8824 for (i = 0; i < 5; i++) {
8825 sprintf (bufferf, "Prepend Frame %d", i + 1);
8826 sprintf (bufferl, "PPage %d", i + 1);
8828 frame = gtk_frame_new (bufferf);
8829 gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
8830 gtk_widget_set_size_request (frame, 100, 75);
8831 gtk_widget_show (frame);
8833 label = gtk_label_new (bufferf);
8834 gtk_container_add (GTK_CONTAINER (frame), label);
8835 gtk_widget_show (label);
8837 label = gtk_label_new (bufferl);
8838 gtk_notebook_prepend_page (GTK_NOTEBOOK (notebook), frame, label);
8841 /* Set what page to start at (page 4) */
8842 gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 3);
8844 /* Create a bunch of buttons */
8845 button = gtk_button_new_with_label ("close");
8846 g_signal_connect_swapped (G_OBJECT (button), "clicked",
8847 G_CALLBACK (delete), NULL);
8848 gtk_table_attach_defaults (GTK_TABLE (table), button, 0, 1, 1, 2);
8849 gtk_widget_show (button);
8851 button = gtk_button_new_with_label ("next page");
8852 g_signal_connect_swapped (G_OBJECT (button), "clicked",
8853 G_CALLBACK (gtk_notebook_next_page),
8855 gtk_table_attach_defaults (GTK_TABLE (table), button, 1, 2, 1, 2);
8856 gtk_widget_show (button);
8858 button = gtk_button_new_with_label ("prev page");
8859 g_signal_connect_swapped (G_OBJECT (button), "clicked",
8860 G_CALLBACK (gtk_notebook_prev_page),
8862 gtk_table_attach_defaults (GTK_TABLE (table), button, 2, 3, 1, 2);
8863 gtk_widget_show (button);
8865 button = gtk_button_new_with_label ("tab position");
8866 g_signal_connect (G_OBJECT (button), "clicked",
8867 G_CALLBACK (rotate_book),
8869 gtk_table_attach_defaults (GTK_TABLE (table), button, 3, 4, 1, 2);
8870 gtk_widget_show (button);
8872 button = gtk_button_new_with_label ("tabs/border on/off");
8873 g_signal_connect (G_OBJECT (button), "clicked",
8874 G_CALLBACK (tabsborder_book),
8876 gtk_table_attach_defaults (GTK_TABLE (table), button, 4, 5, 1, 2);
8877 gtk_widget_show (button);
8879 button = gtk_button_new_with_label ("remove page");
8880 g_signal_connect (G_OBJECT (button), "clicked",
8881 G_CALLBACK (remove_book),
8883 gtk_table_attach_defaults (GTK_TABLE (table), button, 5, 6, 1, 2);
8884 gtk_widget_show (button);
8886 gtk_widget_show (table);
8887 gtk_widget_show (window);
8893 <!-- example-end -->
8896 <para>I hope this helps you on your way with creating notebooks for your
8897 GTK applications.</para>
8902 <!-- ***************************************************************** -->
8903 <chapter id="ch-MenuWidget">
8904 <title>Menu Widget</title>
8906 <para>There are two ways to create menus: there's the easy way, and there's
8907 the hard way. Both have their uses, but you can usually use the
8908 Itemfactory (the easy way). The "hard" way is to create all the menus
8909 using the calls directly. The easy way is to use the gtk_item_factory
8910 calls. This is much simpler, but there are advantages and
8911 disadvantages to each approach.</para>
8913 <para>The Itemfactory is much easier to use, and to add new menus to,
8914 although writing a few wrapper functions to create menus using the
8915 manual method could go a long way towards usability. With the
8916 Itemfactory, it is not possible to add images or the character '/' to
8919 <!-- ----------------------------------------------------------------- -->
8920 <sect1 id="sec-ManualMenuCreation">
8921 <title>Manual Menu Creation</title>
8923 <para>In the true tradition of teaching, we'll show you the hard way
8924 first. <literal>:)</></para>
8926 <para>There are three widgets that go into making a menubar and submenus:</para>
8929 <listitem><simpara>a menu item, which is what the user wants to select, e.g.,
8932 <listitem><simpara>a menu, which acts as a container for the menu items, and</simpara>
8934 <listitem><simpara>a menubar, which is a container for each of the individual
8939 <para>This is slightly complicated by the fact that menu item widgets are
8940 used for two different things. They are both the widgets that are
8941 packed into the menu, and the widget that is packed into the menubar,
8942 which, when selected, activates the menu.</para>
8944 <para>Let's look at the functions that are used to create menus and
8945 menubars. This first function is used to create a new menubar.</para>
8947 <programlisting role="C">
8948 GtkWidget *gtk_menu_bar_new( void );
8951 <para>This rather self explanatory function creates a new menubar. You use
8952 gtk_container_add to pack this into a window, or the box_pack
8953 functions to pack it into a box - the same as buttons.</para>
8955 <programlisting role="C">
8956 GtkWidget *gtk_menu_new( void );
8959 <para>This function returns a pointer to a new menu; it is never actually
8960 shown (with gtk_widget_show), it is just a container for the menu
8961 items. I hope this will become more clear when you look at the
8962 example below.</para>
8964 <para>The next two calls are used to create menu items that are packed into
8965 the menu (and menubar).</para>
8967 <programlisting role="C">
8968 GtkWidget *gtk_menu_item_new( void );
8973 <programlisting role="C">
8974 GtkWidget *gtk_menu_item_new_with_label( const char *label );
8977 <para>These calls are used to create the menu items that are to be
8978 displayed. Remember to differentiate between a "menu" as created with
8979 gtk_menu_new and a "menu item" as created by the gtk_menu_item_new
8980 functions. The menu item will be an actual button with an associated
8981 action, whereas a menu will be a container holding menu items.</para>
8983 <para>The gtk_menu_new_with_label and gtk_menu_new functions are just as
8984 you'd expect after reading about the buttons. One creates a new menu
8985 item with a label already packed into it, and the other just creates a
8986 blank menu item.</para>
8988 <para>Once you've created a menu item you have to put it into a menu. This
8989 is done using the function gtk_menu_append. In order to capture when
8990 the item is selected by the user, we need to connect to the
8991 <literal>activate</literal> signal in the usual way. So, if we wanted to create a
8992 standard <literal>File</literal> menu, with the options <literal>Open</literal>, <literal>Save</literal>, and
8993 <literal>Quit</literal>, the code would look something like:</para>
8995 <programlisting role="C">
8996 file_menu = gtk_menu_new (); /* Don't need to show menus */
8998 /* Create the menu items */
8999 open_item = gtk_menu_item_new_with_label ("Open");
9000 save_item = gtk_menu_item_new_with_label ("Save");
9001 quit_item = gtk_menu_item_new_with_label ("Quit");
9003 /* Add them to the menu */
9004 gtk_menu_append (GTK_MENU (file_menu), open_item);
9005 gtk_menu_append (GTK_MENU (file_menu), save_item);
9006 gtk_menu_append (GTK_MENU (file_menu), quit_item);
9008 /* Attach the callback functions to the activate signal */
9009 gtk_signal_connect_object (GTK_OBJECT (open_item), "activate",
9010 GTK_SIGNAL_FUNC (menuitem_response),
9011 (gpointer) "file.open");
9012 gtk_signal_connect_object (GTK_OBJECT (save_item), "activate",
9013 GTK_SIGNAL_FUNC (menuitem_response),
9014 (gpointer) "file.save");
9016 /* We can attach the Quit menu item to our exit function */
9017 gtk_signal_connect_object (GTK_OBJECT (quit_item), "activate",
9018 GTK_SIGNAL_FUNC (destroy),
9019 (gpointer) "file.quit");
9021 /* We do need to show menu items */
9022 gtk_widget_show (open_item);
9023 gtk_widget_show (save_item);
9024 gtk_widget_show (quit_item);
9027 <para>At this point we have our menu. Now we need to create a menubar and a
9028 menu item for the <literal>File</literal> entry, to which we add our menu. The code
9029 looks like this:</para>
9031 <programlisting role="C">
9032 menu_bar = gtk_menu_bar_new ();
9033 gtk_container_add (GTK_CONTAINER (window), menu_bar);
9034 gtk_widget_show (menu_bar);
9036 file_item = gtk_menu_item_new_with_label ("File");
9037 gtk_widget_show (file_item);
9040 <para>Now we need to associate the menu with <literal>file_item</literal>. This is done
9041 with the function</para>
9043 <programlisting role="C">
9044 void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
9045 GtkWidget *submenu );
9048 <para>So, our example would continue with</para>
9050 <programlisting role="C">
9051 gtk_menu_item_set_submenu (GTK_MENU_ITEM (file_item), file_menu);
9054 <para>All that is left to do is to add the menu to the menubar, which is
9055 accomplished using the function</para>
9057 <programlisting role="C">
9058 void gtk_menu_bar_append( GtkMenuBar *menu_bar,
9059 GtkWidget *menu_item );
9062 <para>which in our case looks like this:</para>
9064 <programlisting role="C">
9065 gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), file_item);
9068 <para>If we wanted the menu right justified on the menubar, such as help
9069 menus often are, we can use the following function (again on
9070 <literal>file_item</literal> in the current example) before attaching it to the
9073 <programlisting role="C">
9074 void gtk_menu_item_right_justify( GtkMenuItem *menu_item );
9077 <para>Here is a summary of the steps needed to create a menu bar with menus
9081 <listitem><simpara> Create a new menu using gtk_menu_new()</simpara>
9084 <listitem><simpara> Use multiple calls to gtk_menu_item_new() for each item you
9085 wish to have on your menu. And use gtk_menu_append() to put each of
9086 these new items on to the menu.</simpara>
9089 <listitem><simpara> Create a menu item using gtk_menu_item_new(). This will be the
9090 root of the menu, the text appearing here will be on the menubar
9094 <listitem><simpara>Use gtk_menu_item_set_submenu() to attach the menu to the root
9095 menu item (the one created in the above step).</simpara>
9098 <listitem><simpara> Create a new menubar using gtk_menu_bar_new. This step only
9099 needs to be done once when creating a series of menus on one menu bar.</simpara>
9102 <listitem><simpara> Use gtk_menu_bar_append() to put the root menu onto the menubar.</simpara>
9106 <para>Creating a popup menu is nearly the same. The difference is that the
9107 menu is not posted "automatically" by a menubar, but explicitly by
9108 calling the function gtk_menu_popup() from a button-press event, for
9109 example. Take these steps:</para>
9112 <listitem><simpara>Create an event handling function. It needs to have the
9114 <programlisting role="C">
9115 static gint handler (GtkWidget *widget,
9118 <simpara>and it will use the event to find out where to pop up the menu.</simpara>
9121 <listitem><simpara>In the event handler, if the event is a mouse button press,
9122 treat <literal>event</literal> as a button event (which it is) and use it as
9123 shown in the sample code to pass information to gtk_menu_popup().</simpara>
9126 <listitem><simpara>Bind that event handler to a widget with</simpara>
9127 <programlisting role="C">
9128 gtk_signal_connect_object (GTK_OBJECT (widget), "event",
9129 GTK_SIGNAL_FUNC (handler),
9132 <simpara>where <literal>widget</literal> is the widget you are binding to,
9133 <literal>handler</literal> is the handling function, and <literal>menu</literal> is a menu
9134 created with gtk_menu_new(). This can be a menu which is also posted
9135 by a menu bar, as shown in the sample code.</simpara>
9141 <!-- ----------------------------------------------------------------- -->
9142 <sect1 id="sec-ManualMenuExample">
9143 <title>Manual Menu Example</title>
9145 <para>That should about do it. Let's take a look at an example to help clarify.</para>
9150 <imagedata fileref="menu.png" format="png">
9152 </inlinemediaobject>
9155 <programlisting role="C">
9156 <!-- example-start menu menu.c -->
9158 #include <stdio.h>
9159 #include <gtk/gtk.h>
9161 static gint button_press (GtkWidget *, GdkEvent *);
9162 static void menuitem_response (gchar *);
9170 GtkWidget *menu_bar;
9171 GtkWidget *root_menu;
9172 GtkWidget *menu_items;
9178 gtk_init (&argc, &argv);
9180 /* create a new window */
9181 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9182 gtk_widget_set_size_request (GTK_WIDGET (window), 200, 100);
9183 gtk_window_set_title (GTK_WINDOW (window), "GTK Menu Test");
9184 g_signal_connect (G_OBJECT (window), "delete_event",
9185 G_CALLBACK (gtk_main_quit), NULL);
9187 /* Init the menu-widget, and remember -- never
9188 * gtk_show_widget() the menu widget!!
9189 * This is the menu that holds the menu items, the one that
9190 * will pop up when you click on the "Root Menu" in the app */
9191 menu = gtk_menu_new ();
9193 /* Next we make a little loop that makes three menu-entries for "test-menu".
9194 * Notice the call to gtk_menu_append. Here we are adding a list of
9195 * menu items to our menu. Normally, we'd also catch the "clicked"
9196 * signal on each of the menu items and setup a callback for it,
9197 * but it's omitted here to save space. */
9199 for (i = 0; i < 3; i++)
9201 /* Copy the names to the buf. */
9202 sprintf (buf, "Test-undermenu - %d", i);
9204 /* Create a new menu-item with a name... */
9205 menu_items = gtk_menu_item_new_with_label (buf);
9207 /* ...and add it to the menu. */
9208 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_items);
9210 /* Do something interesting when the menuitem is selected */
9211 g_signal_connect_swapped (G_OBJECT (menu_items), "activate",
9212 G_CALLBACK (menuitem_response),
9215 /* Show the widget */
9216 gtk_widget_show (menu_items);
9219 /* This is the root menu, and will be the label
9220 * displayed on the menu bar. There won't be a signal handler attached,
9221 * as it only pops up the rest of the menu when pressed. */
9222 root_menu = gtk_menu_item_new_with_label ("Root Menu");
9224 gtk_widget_show (root_menu);
9226 /* Now we specify that we want our newly created "menu" to be the menu
9227 * for the "root menu" */
9228 gtk_menu_item_set_submenu (GTK_MENU_ITEM (root_menu), menu);
9230 /* A vbox to put a menu and a button in: */
9231 vbox = gtk_vbox_new (FALSE, 0);
9232 gtk_container_add (GTK_CONTAINER (window), vbox);
9233 gtk_widget_show (vbox);
9235 /* Create a menu-bar to hold the menus and add it to our main window */
9236 menu_bar = gtk_menu_bar_new ();
9237 gtk_box_pack_start (GTK_BOX (vbox), menu_bar, FALSE, FALSE, 2);
9238 gtk_widget_show (menu_bar);
9240 /* Create a button to which to attach menu as a popup */
9241 button = gtk_button_new_with_label ("press me");
9242 g_signal_connect_swapped (G_OBJECT (button), "event",
9243 G_CALLBACK (button_press),
9245 gtk_box_pack_end (GTK_BOX (vbox), button, TRUE, TRUE, 2);
9246 gtk_widget_show (button);
9248 /* And finally we append the menu-item to the menu-bar -- this is the
9249 * "root" menu-item I have been raving about =) */
9250 gtk_menu_shell_append (GTK_MENU_SHELL (menu_bar), root_menu);
9252 /* always display the window as the last step so it all splashes on
9253 * the screen at once. */
9254 gtk_widget_show (window);
9261 /* Respond to a button-press by posting a menu passed in as widget.
9263 * Note that the "widget" argument is the menu being posted, NOT
9264 * the button that was pressed.
9267 static gint button_press( GtkWidget *widget,
9271 if (event->type == GDK_BUTTON_PRESS) {
9272 GdkEventButton *bevent = (GdkEventButton *) event;
9273 gtk_menu_popup (GTK_MENU (widget), NULL, NULL, NULL, NULL,
9274 bevent->button, bevent->time);
9275 /* Tell calling code that we have handled this event; the buck
9280 /* Tell calling code that we have not handled this event; pass it on. */
9285 /* Print a string when a menu item is selected */
9287 static void menuitem_response( gchar *string )
9289 printf ("%s\n", string);
9291 <!-- example-end -->
9294 <para>You may also set a menu item to be insensitive and, using an accelerator
9295 table, bind keys to menu functions.</para>
9299 <!-- ----------------------------------------------------------------- -->
9300 <sect1 id="sec-UsingItemFactory">
9301 <title>Using ItemFactory</title>
9303 <para>Now that we've shown you the hard way, here's how you do it using the
9304 gtk_item_factory calls.</para>
9308 <!-- ----------------------------------------------------------------- -->
9309 <sect1 id="sec-ItemFactoryExample">
9310 <title>Item Factory Example</title>
9312 <para>Here is an example using the GTK item factory.</para>
9314 <programlisting role="C">
9315 <!-- example-start menu itemfactory.c -->
9317 #include <gtk/gtk.h>
9318 #include <strings.h>
9320 /* Obligatory basic callback */
9321 static void print_hello( GtkWidget *w,
9324 g_message ("Hello, World!\n");
9327 /* This is the GtkItemFactoryEntry structure used to generate new menus.
9328 Item 1: The menu path. The letter after the underscore indicates an
9329 accelerator key once the menu is open.
9330 Item 2: The accelerator key for the entry
9331 Item 3: The callback function.
9332 Item 4: The callback action. This changes the parameters with
9333 which the function is called. The default is 0.
9334 Item 5: The item type, used to define what kind of an item it is.
9335 Here are the possible values:
9337 NULL -> "<Item>"
9338 "" -> "<Item>"
9339 "<Title>" -> create a title item
9340 "<Item>" -> create a simple item
9341 "<CheckItem>" -> create a check item
9342 "<ToggleItem>" -> create a toggle item
9343 "<RadioItem>" -> create a radio item
9344 <path> -> path of a radio item to link against
9345 "<Separator>" -> create a separator
9346 "<Branch>" -> create an item to hold sub items (optional)
9347 "<LastBranch>" -> create a right justified branch
9350 static GtkItemFactoryEntry menu_items[] = {
9351 { "/_File", NULL, NULL, 0, "<Branch>" },
9352 { "/File/_New", "<control>N", print_hello, 0, NULL },
9353 { "/File/_Open", "<control>O", print_hello, 0, NULL },
9354 { "/File/_Save", "<control>S", print_hello, 0, NULL },
9355 { "/File/Save _As", NULL, NULL, 0, NULL },
9356 { "/File/sep1", NULL, NULL, 0, "<Separator>" },
9357 { "/File/Quit", "<control>Q", gtk_main_quit, 0, NULL },
9358 { "/_Options", NULL, NULL, 0, "<Branch>" },
9359 { "/Options/Test", NULL, NULL, 0, NULL },
9360 { "/_Help", NULL, NULL, 0, "<LastBranch>" },
9361 { "/_Help/About", NULL, NULL, 0, NULL },
9365 void get_main_menu( GtkWidget *window,
9366 GtkWidget **menubar )
9368 GtkItemFactory *item_factory;
9369 GtkAccelGroup *accel_group;
9370 gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
9372 accel_group = gtk_accel_group_new ();
9374 /* This function initializes the item factory.
9375 Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
9376 or GTK_TYPE_OPTION_MENU.
9377 Param 2: The path of the menu.
9378 Param 3: A pointer to a gtk_accel_group. The item factory sets up
9379 the accelerator table while generating menus.
9382 item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>",
9385 /* This function generates the menu items. Pass the item factory,
9386 the number of items in the array, the array itself, and any
9387 callback data for the the menu items. */
9388 gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
9390 /* Attach the new accelerator group to the window. */
9391 gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
9394 /* Finally, return the actual menu bar created by the item factory. */
9395 *menubar = gtk_item_factory_get_widget (item_factory, "<main>");
9402 GtkWidget *main_vbox;
9405 gtk_init (&argc, &argv);
9407 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9408 g_signal_connect (G_OBJECT (window), "destroy",
9409 G_CALLBACK (gtk_main_quit),
9411 gtk_window_set_title (GTK_WINDOW (window), "Item Factory");
9412 gtk_widget_set_size_request (GTK_WIDGET (window), 300, 200);
9414 main_vbox = gtk_vbox_new (FALSE, 1);
9415 gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 1);
9416 gtk_container_add (GTK_CONTAINER (window), main_vbox);
9417 gtk_widget_show (main_vbox);
9419 get_main_menu (window, &menubar);
9420 gtk_box_pack_start (GTK_BOX (main_vbox), menubar, FALSE, TRUE, 0);
9421 gtk_widget_show (menubar);
9423 gtk_widget_show (window);
9429 <!-- example-end -->
9432 <para>For now, there's only this example. An explanation and lots 'o' comments
9433 will follow later.</para>
9438 <!-- ***************************************************************** -->
9439 <chapter id="ch-UndocWidgets">
9440 <title>Undocumented Widgets</title>
9442 <para>These all require authors! :) Please consider contributing to our
9445 <para>If you must use one of these widgets that are undocumented, I strongly
9446 suggest you take a look at their respective header files in the GTK
9447 distribution. GTK's function names are very descriptive. Once you
9448 have an understanding of how things work, it's not difficult to figure
9449 out how to use a widget simply by looking at its function
9450 declarations. This, along with a few examples from others' code, and
9451 it should be no problem.</para>
9453 <para>When you do come to understand all the functions of a new undocumented
9454 widget, please consider writing a tutorial on it so others may benefit
9455 from your time.</para>
9457 <!-- ----------------------------------------------------------------- -->
9458 <sect1 id="sec-AccelLabel">
9459 <title>Accel Label</title>
9465 <!-- ----------------------------------------------------------------- -->
9466 <sect1 id="sec-OptionMenu">
9467 <title>Option Menu</title>
9473 <!-- ----------------------------------------------------------------- -->
9474 <sect1 id="sec-MenuItems">
9475 <title>Menu Items</title>
9479 <sect2 id="sec-CheckMenuItem">
9480 <title>Check Menu Item</title>
9485 <sect2 id="sec-RadioMenuItem">
9486 <title>Radio Menu Item</title>
9491 <sect2 id="sec-SeparatorMenuItem">
9492 <title>Separator Menu Item</title>
9497 <sect2 id="sec-TearoffMenuItem">
9498 <title>Tearoff Menu Item</title>
9504 <!-- ----------------------------------------------------------------- -->
9505 <sect1 id="sec-Curves">
9506 <title>Curves</title>
9512 <!-- ----------------------------------------------------------------- -->
9513 <sect1 id="sec-DrawingArea">
9514 <title>Drawing Area</title>
9520 <!-- ----------------------------------------------------------------- -->
9521 <sect1 id="sec-FontSelectionDialog">
9522 <title>Font Selection Dialog</title>
9528 <!-- ----------------------------------------------------------------- -->
9529 <sect1 id="sec-MessageDialog">
9530 <title>Message Dialog</title>
9536 <!-- ----------------------------------------------------------------- -->
9537 <sect1 id="sec-GammaCurve">
9538 <title>Gamma Curve</title>
9544 <!-- ----------------------------------------------------------------- -->
9545 <sect1 id="sec-Image">
9546 <title>Image</title>
9552 <!-- ----------------------------------------------------------------- -->
9553 <sect1 id="sec-PlugsAndSockets">
9554 <title>Plugs and Sockets</title>
9560 <!-- ----------------------------------------------------------------- -->
9561 <sect1 id="sec-TreeView">
9562 <title>Tree View</title>
9568 <!-- ----------------------------------------------------------------- -->
9569 <sect1 id="sec-TextView">
9570 <title>Text View</title>
9577 <!-- ***************************************************************** -->
9578 <chapter id="ch-SettingWidgetAttributes">
9579 <title>Setting Widget Attributes</title>
9581 <para>This describes the functions used to operate on widgets. These can be
9582 used to set style, padding, size, etc.</para>
9584 <para>(Maybe I should make a whole section on accelerators.)</para>
9586 <programlisting role="C">
9587 void gtk_widget_install_accelerator( GtkWidget *widget,
9588 GtkAcceleratorTable *table,
9593 void gtk_widget_remove_accelerator ( GtkWidget *widget,
9594 GtkAcceleratorTable *table,
9595 gchar *signal_name);
9597 void gtk_widget_activate( GtkWidget *widget );
9599 void gtk_widget_set_name( GtkWidget *widget,
9602 gchar *gtk_widget_get_name( GtkWidget *widget );
9604 void gtk_widget_set_sensitive( GtkWidget *widget,
9607 void gtk_widget_set_style( GtkWidget *widget,
9610 GtkStyle *gtk_widget_get_style( GtkWidget *widget );
9612 GtkStyle *gtk_widget_get_default_style( void );
9614 void gtk_widget_set_uposition( GtkWidget *widget,
9618 void gtk_widget_set_size_request ( GtkWidget *widget,
9622 void gtk_widget_grab_focus( GtkWidget *widget );
9624 void gtk_widget_show( GtkWidget *widget );
9626 void gtk_widget_hide( GtkWidget *widget );
9631 <!-- ***************************************************************** -->
9632 <chapter id="ch-Timeouts">
9633 <title>Timeouts, IO and Idle Functions</title>
9635 <!-- ----------------------------------------------------------------- -->
9636 <sect1 id="sec-Timeouts">
9637 <title>Timeouts</title>
9639 <para>You may be wondering how you make GTK do useful work when in gtk_main.
9640 Well, you have several options. Using the following function you can
9641 create a timeout function that will be called every "interval"
9642 milliseconds.</para>
9644 <programlisting role="C">
9645 gint gtk_timeout_add( guint32 interval,
9646 GtkFunction function,
9650 <para>The first argument is the number of milliseconds between calls to your
9651 function. The second argument is the function you wish to have called,
9652 and the third, the data passed to this callback function. The return
9653 value is an integer "tag" which may be used to stop the timeout by
9656 <programlisting role="C">
9657 void gtk_timeout_remove( gint tag );
9660 <para>You may also stop the timeout function by returning zero or FALSE from
9661 your callback function. Obviously this means if you want your function
9662 to continue to be called, it should return a non-zero value,
9665 <para>The declaration of your callback should look something like this:</para>
9667 <programlisting role="C">
9668 gint timeout_callback( gpointer data );
9673 <!-- ----------------------------------------------------------------- -->
9674 <sect1 id="sec-MonitoringIO">
9675 <title>Monitoring IO</title>
9677 <para>A nifty feature of GDK (the library that underlies GTK), is the
9678 ability to have it check for data on a file descriptor for you (as
9679 returned by open(2) or socket(2)). This is especially useful for
9680 networking applications. The function:</para>
9682 <programlisting role="C">
9683 gint gdk_input_add( gint source,
9684 GdkInputCondition condition,
9685 GdkInputFunction function,
9689 <para>Where the first argument is the file descriptor you wish to have
9690 watched, and the second specifies what you want GDK to look for. This
9691 may be one of:</para>
9694 <listitem><simpara><literal>GDK_INPUT_READ</literal> - Call your function when there is data
9695 ready for reading on your file descriptor.</simpara>
9698 <listitem><simpara>><literal>GDK_INPUT_WRITE</literal> - Call your function when the file
9699 descriptor is ready for writing.</simpara>
9703 <para>As I'm sure you've figured out already, the third argument is the
9704 function you wish to have called when the above conditions are
9705 satisfied, and the fourth is the data to pass to this function.</para>
9707 <para>The return value is a tag that may be used to stop GDK from monitoring
9708 this file descriptor using the following function.</para>
9710 <programlisting role="C">
9711 void gdk_input_remove( gint tag );
9714 <para>The callback function should be declared as:</para>
9716 <programlisting role="C">
9717 void input_callback( gpointer data,
9719 GdkInputCondition condition );
9722 <para>Where <literal>source</literal> and <literal>condition</literal> are as specified above.</para>
9726 <!-- ----------------------------------------------------------------- -->
9727 <sect1 id="sec-IdleFunctions">
9728 <title>Idle Functions</title>
9730 <para><!-- TODO: Need to check on idle priorities - TRG -->
9731 What if you have a function which you want to be called when nothing
9732 else is happening ?</para>
9734 <programlisting role="C">
9735 gint gtk_idle_add( GtkFunction function,
9739 <para>This causes GTK to call the specified function whenever nothing else
9740 is happening.</para>
9742 <programlisting role="C">
9743 void gtk_idle_remove( gint tag );
9746 <para>I won't explain the meaning of the arguments as they follow very much
9747 like the ones above. The function pointed to by the first argument to
9748 gtk_idle_add will be called whenever the opportunity arises. As with
9749 the others, returning FALSE will stop the idle function from being
9755 <!-- ***************************************************************** -->
9756 <chapter id="ch-AdvancedEventsAndSignals">
9757 <title>Advanced Event and Signal Handling</title>
9759 <!-- ----------------------------------------------------------------- -->
9760 <sect1 id="sec-SignalFunctions">
9761 <title>Signal Functions</title>
9763 <!-- ----------------------------------------------------------------- -->
9765 <title>Connecting and Disconnecting Signal Handlers</title>
9767 <programlisting role="C">
9768 guint gtk_signal_connect( GtkObject *object,
9771 gpointer func_data );
9773 guint gtk_signal_connect_after( GtkObject *object,
9776 gpointer func_data );
9778 guint gtk_signal_connect_object( GtkObject *object,
9781 GtkObject *slot_object );
9783 guint gtk_signal_connect_object_after( GtkObject *object,
9786 GtkObject *slot_object );
9788 guint gtk_signal_connect_full( GtkObject *object,
9791 GtkCallbackMarshal marshal,
9793 GtkDestroyNotify destroy_func,
9797 guint gtk_signal_connect_interp( GtkObject *object,
9799 GtkCallbackMarshal func,
9801 GtkDestroyNotify destroy_func,
9804 void gtk_signal_connect_object_while_alive( GtkObject *object,
9805 const gchar *signal,
9807 GtkObject *alive_object );
9809 void gtk_signal_connect_while_alive( GtkObject *object,
9810 const gchar *signal,
9813 GtkObject *alive_object );
9815 void gtk_signal_disconnect( GtkObject *object,
9818 void gtk_signal_disconnect_by_func( GtkObject *object,
9825 <!-- ----------------------------------------------------------------- -->
9827 <title>Blocking and Unblocking Signal Handlers</title>
9829 <programlisting role="C">
9830 void gtk_signal_handler_block( GtkObject *object,
9833 void gtk_signal_handler_block_by_func( GtkObject *object,
9837 void gtk_signal_handler_block_by_data( GtkObject *object,
9840 void gtk_signal_handler_unblock( GtkObject *object,
9843 void gtk_signal_handler_unblock_by_func( GtkObject *object,
9847 void gtk_signal_handler_unblock_by_data( GtkObject *object,
9853 <!-- ----------------------------------------------------------------- -->
9855 <title>Emitting and Stopping Signals</title>
9857 <programlisting role="C">
9858 void gtk_signal_emit( GtkObject *object,
9862 void gtk_signal_emit_by_name( GtkObject *object,
9866 void gtk_signal_emitv( GtkObject *object,
9870 void gtk_signal_emitv_by_name( GtkObject *object,
9874 guint gtk_signal_n_emissions( GtkObject *object,
9877 guint gtk_signal_n_emissions_by_name( GtkObject *object,
9878 const gchar *name );
9880 void gtk_signal_emit_stop( GtkObject *object,
9883 void gtk_signal_emit_stop_by_name( GtkObject *object,
9884 const gchar *name );
9890 <!-- ----------------------------------------------------------------- -->
9891 <sect1 id="sec-SignalEmissionAndPropagation">
9892 <title>Signal Emission and Propagation</title>
9894 <para>Signal emission is the process whereby GTK runs all handlers for a
9895 specific object and signal.</para>
9897 <para>First, note that the return value from a signal emission is the return
9898 value of the <emphasis>last</emphasis> handler executed. Since event signals are
9899 all of type <literal>GTK_RUN_LAST</literal>, this will be the default (GTK supplied)
9900 handler, unless you connect with gtk_signal_connect_after().</para>
9902 <para>The way an event (say "button_press_event") is handled, is:</para>
9905 <listitem><simpara>Start with the widget where the event occured.</simpara>
9908 <listitem><simpara>Emit the generic "event" signal. If that signal handler returns
9909 a value of TRUE, stop all processing.</simpara>
9912 <listitem><simpara>Otherwise, emit a specific, "button_press_event" signal. If that
9913 returns TRUE, stop all processing.</simpara>
9916 <listitem><simpara>Otherwise, go to the widget's parent, and repeat the above two
9920 <listitem><simpara>Continue until some signal handler returns TRUE, or until the
9921 top-level widget is reached.</simpara>
9925 <para>Some consequences of the above are:</para>
9928 <listitem><simpara>Your handler's return value will have no effect if there is a
9929 default handler, unless you connect with gtk_signal_connect_after().</simpara>
9932 <listitem><simpara>To prevent the default handler from being run, you need to
9933 connect with gtk_signal_connect() and use
9934 gtk_signal_emit_stop_by_name() - the return value only affects whether
9935 the signal is propagated, not the current emission.</simpara>
9942 <!-- ***************************************************************** -->
9943 <chapter id="ch-ManagingSelections">
9944 <title>Managing Selections</title>
9946 <!-- ----------------------------------------------------------------- -->
9947 <sect1 id="sec-SelectionsOverview">
9948 <title>Overview</title>
9950 <para>One type of interprocess communication supported by X and GTK is
9951 <emphasis>selections</emphasis>. A selection identifies a chunk of data, for
9952 instance, a portion of text, selected by the user in some fashion, for
9953 instance, by dragging with the mouse. Only one application on a
9954 display (the <emphasis>owner</emphasis>) can own a particular selection at one
9955 time, so when a selection is claimed by one application, the previous
9956 owner must indicate to the user that selection has been
9957 relinquished. Other applications can request the contents of a
9958 selection in different forms, called <emphasis>targets</emphasis>. There can be
9959 any number of selections, but most X applications only handle one, the
9960 <emphasis>primary selection</emphasis>.</para>
9962 <para>In most cases, it isn't necessary for a GTK application to deal with
9963 selections itself. The standard widgets, such as the Entry widget,
9964 already have the capability to claim the selection when appropriate
9965 (e.g., when the user drags over text), and to retrieve the contents of
9966 the selection owned by another widget or another application (e.g.,
9967 when the user clicks the second mouse button). However, there may be
9968 cases in which you want to give other widgets the ability to supply
9969 the selection, or you wish to retrieve targets not supported by
9972 <para>A fundamental concept needed to understand selection handling is that
9973 of the <emphasis>atom</emphasis>. An atom is an integer that uniquely identifies a
9974 string (on a certain display). Certain atoms are predefined by the X
9975 server, and in some cases there are constants in <literal>gtk.h</literal>
9976 corresponding to these atoms. For instance the constant
9977 <literal>GDK_PRIMARY_SELECTION</literal> corresponds to the string "PRIMARY".
9978 In other cases, you should use the functions
9979 <literal>gdk_atom_intern()</literal>, to get the atom corresponding to a string,
9980 and <literal>gdk_atom_name()</literal>, to get the name of an atom. Both
9981 selections and targets are identified by atoms.</para>
9984 <!-- ----------------------------------------------------------------- -->
9985 <sect1 id="sec-RetrievingTheSelection">
9986 <title>Retrieving the selection</title>
9988 <para>Retrieving the selection is an asynchronous process. To start the
9989 process, you call:</para>
9991 <programlisting role="C">
9992 gint gtk_selection_convert( GtkWidget *widget,
9998 <para>This <emphasis>converts</emphasis> the selection into the form specified by
9999 <literal>target</literal>. If at all possible, the time field should be the time
10000 from the event that triggered the selection. This helps make sure that
10001 events occur in the order that the user requested them. However, if it
10002 is not available (for instance, if the conversion was triggered by a
10003 "clicked" signal), then you can use the constant
10004 <literal>GDK_CURRENT_TIME</literal>.</para>
10006 <para>When the selection owner responds to the request, a
10007 "selection_received" signal is sent to your application. The handler
10008 for this signal receives a pointer to a <literal>GtkSelectionData</literal>
10009 structure, which is defined as:</para>
10011 <programlisting role="C">
10012 struct _GtkSelectionData
10023 <para><literal>selection</literal> and <literal>target</literal> are the values you gave in your
10024 <literal>gtk_selection_convert()</literal> call. <literal>type</literal> is an atom that
10025 identifies the type of data returned by the selection owner. Some
10026 possible values are "STRING", a string of latin-1 characters, "ATOM",
10027 a series of atoms, "INTEGER", an integer, etc. Most targets can only
10028 return one type. <literal>format</literal> gives the length of the units (for
10029 instance characters) in bits. Usually, you don't care about this when
10030 receiving data. <literal>data</literal> is a pointer to the returned data, and
10031 <literal>length</literal> gives the length of the returned data, in bytes. If
10032 <literal>length</literal> is negative, then an error occurred and the selection
10033 could not be retrieved. This might happen if no application owned the
10034 selection, or if you requested a target that the application didn't
10035 support. The buffer is actually guaranteed to be one byte longer than
10036 <literal>length</literal>; the extra byte will always be zero, so it isn't
10037 necessary to make a copy of strings just to null terminate them.</para>
10039 <para>In the following example, we retrieve the special target "TARGETS",
10040 which is a list of all targets into which the selection can be
10043 <programlisting role="C">
10044 <!-- example-start selection gettargets.c -->
10046 #include <stdlib.h>
10047 #include <gtk/gtk.h>
10049 void selection_received( GtkWidget *widget,
10050 GtkSelectionData *selection_data,
10053 /* Signal handler invoked when user clicks on the "Get Targets" button */
10054 void get_targets( GtkWidget *widget,
10057 static GdkAtom targets_atom = GDK_NONE;
10059 /* Get the atom corresponding to the string "TARGETS" */
10060 if (targets_atom == GDK_NONE)
10061 targets_atom = gdk_atom_intern ("TARGETS", FALSE);
10063 /* And request the "TARGETS" target for the primary selection */
10064 gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
10068 /* Signal handler called when the selections owner returns the data */
10069 void selection_received( GtkWidget *widget,
10070 GtkSelectionData *selection_data,
10077 /* **** IMPORTANT **** Check to see if retrieval succeeded */
10078 if (selection_data->length < 0)
10080 g_print ("Selection retrieval failed\n");
10083 /* Make sure we got the data in the expected form */
10084 if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
10086 g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
10090 /* Print out the atoms we received */
10091 atoms = (GdkAtom *)selection_data->data;
10094 for (i = 0; i < selection_data->length / sizeof(GdkAtom); i++)
10097 name = gdk_atom_name (atoms[i]);
10099 g_print ("%s\n",name);
10101 g_print ("(bad atom)\n");
10107 int main( int argc,
10113 gtk_init (&argc, &argv);
10115 /* Create the toplevel window */
10117 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
10118 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
10119 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
10121 g_signal_connect (G_OBJECT (window), "destroy",
10122 G_CALLBACK (exit), NULL);
10124 /* Create a button the user can click to get targets */
10126 button = gtk_button_new_with_label ("Get Targets");
10127 gtk_container_add (GTK_CONTAINER (window), button);
10129 g_signal_connect (G_OBJECT(button), "clicked",
10130 G_CALLBACK (get_targets), NULL);
10131 g_signal_connect (G_OBJECT(button), "selection_received",
10132 G_CALLBACK (selection_received), NULL);
10134 gtk_widget_show (button);
10135 gtk_widget_show (window);
10141 <!-- example-end -->
10145 <!-- ----------------------------------------------------------------- -->
10146 <sect1 id="sec-SupplyingTheSelection">
10147 <title>Supplying the selection</title>
10149 <para>Supplying the selection is a bit more complicated. You must register
10150 handlers that will be called when your selection is requested. For
10151 each selection/target pair you will handle, you make a call to:</para>
10153 <programlisting role="C">
10154 void gtk_selection_add_target (GtkWidget *widget,
10160 <para><literal>widget</literal>, <literal>selection</literal>, and <literal>target</literal> identify the requests
10161 this handler will manage. When a request for a selection is received,
10162 the "selection_get" signal will be called. <literal>info</literal> can be used as an
10163 enumerator to identify the specific target within the callback function.</para>
10165 <para>The callback function has the signature:</para>
10167 <programlisting role="C">
10168 void "selection_get" (GtkWidget *widget,
10169 GtkSelectionData *selection_data,
10174 <para>The GtkSelectionData is the same as above, but this time, we're
10175 responsible for filling in the fields <literal>type</literal>, <literal>format</literal>,
10176 <literal>data</literal>, and <literal>length</literal>. (The <literal>format</literal> field is actually
10177 important here - the X server uses it to figure out whether the data
10178 needs to be byte-swapped or not. Usually it will be 8 - <emphasis>i.e.</emphasis> a
10179 character - or 32 - <emphasis>i.e.</emphasis> a. integer.) This is done by calling the
10182 <programlisting role="C">
10183 void gtk_selection_data_set( GtkSelectionData *selection_data,
10190 <para>This function takes care of properly making a copy of the data so that
10191 you don't have to worry about keeping it around. (You should not fill
10192 in the fields of the GtkSelectionData structure by hand.)</para>
10194 <para>When prompted by the user, you claim ownership of the selection by
10197 <programlisting role="C">
10198 gint gtk_selection_owner_set( GtkWidget *widget,
10203 <para>If another application claims ownership of the selection, you will
10204 receive a "selection_clear_event".</para>
10206 <para>As an example of supplying the selection, the following program adds
10207 selection functionality to a toggle button. When the toggle button is
10208 depressed, the program claims the primary selection. The only target
10209 supported (aside from certain targets like "TARGETS" supplied by GTK
10210 itself), is the "STRING" target. When this target is requested, a
10211 string representation of the time is returned.</para>
10213 <programlisting role="C">
10214 <!-- example-start selection setselection.c -->
10216 #include <stdlib.h>
10217 #include <gtk/gtk.h>
10218 #include <time.h>
10220 /* Callback when the user toggles the selection */
10221 void selection_toggled( GtkWidget *widget,
10222 gint *have_selection )
10224 if (GTK_TOGGLE_BUTTON (widget)->active)
10226 *have_selection = gtk_selection_owner_set (widget,
10227 GDK_SELECTION_PRIMARY,
10229 /* if claiming the selection failed, we return the button to
10231 if (!*have_selection)
10232 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
10236 if (*have_selection)
10238 /* Before clearing the selection by setting the owner to NULL,
10239 we check if we are the actual owner */
10240 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
10241 gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
10243 *have_selection = FALSE;
10248 /* Called when another application claims the selection */
10249 gint selection_clear( GtkWidget *widget,
10250 GdkEventSelection *event,
10251 gint *have_selection )
10253 *have_selection = FALSE;
10254 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
10259 /* Supplies the current time as the selection. */
10260 void selection_handle( GtkWidget *widget,
10261 GtkSelectionData *selection_data,
10267 time_t current_time;
10269 current_time = time (NULL);
10270 timestr = asctime (localtime (&current_time));
10271 /* When we return a single string, it should not be null terminated.
10272 That will be done for us */
10274 gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
10275 8, timestr, strlen (timestr));
10278 int main( int argc,
10282 GtkWidget *selection_button;
10284 static int have_selection = FALSE;
10286 gtk_init (&argc, &argv);
10288 /* Create the toplevel window */
10290 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
10291 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
10292 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
10294 g_signal_connect (G_OBJECT (window), "destroy",
10295 G_CALLBACK (exit), NULL);
10297 /* Create a toggle button to act as the selection */
10299 selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
10300 gtk_container_add (GTK_CONTAINER (window), selection_button);
10301 gtk_widget_show (selection_button);
10303 g_signal_connect (G_OBJECT (selection_button), "toggled",
10304 G_CALLBACK (selection_toggled), &have_selection);
10305 g_signal_connect (G_OBJECT (selection_button), "selection_clear_event",
10306 G_CALLBACK (selection_clear), &have_selection);
10308 gtk_selection_add_target (selection_button,
10309 GDK_SELECTION_PRIMARY,
10310 GDK_SELECTION_TYPE_STRING,
10312 g_signal_connect (G_OBJECT (selection_button), "selection_get",
10313 G_CALLBACK (selection_handle), &have_selection);
10315 gtk_widget_show (selection_button);
10316 gtk_widget_show (window);
10322 <!-- example-end -->
10328 <!-- ***************************************************************** -->
10329 <chapter id="ch-DragAngDrop">
10330 <title>Drag-and-drop (DND)</title>
10332 <para>GTK+ has a high level set of functions for doing inter-process
10333 communication via the drag-and-drop system. GTK+ can perform
10334 drag-and-drop on top of the low level Xdnd and Motif drag-and-drop
10337 <!-- ----------------------------------------------------------------- -->
10338 <sect1 id="sec-DragAndDropOverview">
10339 <title>Overview</title>
10341 <para>An application capable of GTK+ drag-and-drop first defines and sets up
10342 the GTK+ widget(s) for drag-and-drop. Each widget can be a source
10343 and/or destination for drag-and-drop. Note that these GTK+ widgets must have
10344 an associated X Window, check using GTK_WIDGET_NO_WINDOW(widget)).</para>
10346 <para>Source widgets can send out drag data, thus allowing the user to drag
10347 things off of them, while destination widgets can receive drag data.
10348 Drag-and-drop destinations can limit who they accept drag data from,
10349 e.g. the same application or any application (including itself).</para>
10351 <para>Sending and receiving drop data makes use of GTK+ signals.
10352 Dropping an item to a destination widget requires both a data
10353 request (for the source widget) and data received signal handler (for
10354 the target widget). Additional signal handers can be connected if you
10355 want to know when a drag begins (at the very instant it starts), to
10356 when a drop is made, and when the entire drag-and-drop procedure has
10357 ended (successfully or not).</para>
10359 <para>Your application will need to provide data for source widgets when
10360 requested, that involves having a drag data request signal handler. For
10361 destination widgets they will need a drop data received signal
10364 <para>So a typical drag-and-drop cycle would look as follows:</para>
10366 <listitem><simpara> Drag begins.</simpara>
10368 <listitem><simpara> Drag data request (when a drop occurs).</simpara>
10370 <listitem><simpara> Drop data received (may be on same or different
10371 application).</simpara>
10373 <listitem><simpara> Drag data delete (if the drag was a move).</simpara>
10375 <listitem><simpara> Drag-and-drop procedure done.</simpara>
10379 <para>There are a few minor steps that go in between here and there, but we
10380 will get into detail about that later.</para>
10384 <!-- ----------------------------------------------------------------- -->
10385 <sect1 id="sec-DragAndDropProperties">
10386 <title>Properties</title>
10388 <para>Drag data has the following properties:</para>
10391 <listitem><simpara> Drag action type (ie GDK_ACTION_COPY, GDK_ACTION_MOVE).</simpara>
10394 <listitem><simpara> Client specified arbitrary drag-and-drop type (a name and number pair).</simpara>
10397 <listitem><simpara> Sent and received data format type.</simpara>
10401 <para>Drag actions are quite obvious, they specify if the widget can
10402 drag with the specified action(s), e.g. GDK_ACTION_COPY and/or
10403 GDK_ACTION_MOVE. A GDK_ACTION_COPY would be a typical drag-and-drop
10404 without the source data being deleted while GDK_ACTION_MOVE would be
10405 just like GDK_ACTION_COPY but the source data will be 'suggested' to be
10406 deleted after the received signal handler is called. There are
10407 additional drag actions including GDK_ACTION_LINK which you may want to
10408 look into when you get to more advanced levels of drag-and-drop.</para>
10410 <para>The client specified arbitrary drag-and-drop type is much more
10411 flexible, because your application will be defining and checking for
10412 that specifically. You will need to set up your destination widgets to
10413 receive certain drag-and-drop types by specifying a name and/or number.
10414 It would be more reliable to use a name since another application may
10415 just happen to use the same number for an entirely different
10418 <para>Sent and received data format types (<emphasis>selection
10419 target</emphasis>) come into play only in your request and received
10420 data handler functions. The term <emphasis>selection target</emphasis>
10421 is somewhat misleading. It is a term adapted from GTK+ selection
10422 (cut/copy and paste). What <emphasis>selection target</emphasis>
10423 actually means is the data's format type (i.e. GdkAtom, integer, or
10424 string) that being sent or received. Your request data handler function
10425 needs to specify the type (<emphasis>selection target</emphasis>) of
10426 data that it sends out and your received data handler needs to handle
10427 the type (<emphasis>selection target</emphasis>) of data
10432 <!-- ----------------------------------------------------------------- -->
10433 <sect1 id="sec-DragAndDropFunctions">
10434 <title>Functions</title>
10436 <!-- ----------------------------------------------------------------- -->
10437 <sect2 id="sec-DNDSourceWidgets">
10438 <title>Setting up the source widget</title>
10440 <para>The function <literal>gtk_drag_source_set()</literal> specifies a
10441 set of target types for a drag operation on a widget.</para>
10443 <programlisting role="C">
10444 void gtk_drag_source_set( GtkWidget *widget,
10445 GdkModifierType start_button_mask,
10446 const GtkTargetEntry *targets,
10448 GdkDragAction actions );
10451 <para>The parameters signify the following:</para>
10453 <listitem><simpara><literal>widget</literal> specifies the drag source
10456 <listitem><simpara><literal>start_button_mask</literal> specifies a
10457 bitmask of buttons that can start the drag (e.g. GDK_BUTTON1_MASK)</simpara>
10459 <listitem><simpara><literal>targets</literal> specifies a table of
10460 target data types the drag will support</simpara>
10462 <listitem><simpara><literal>n_targets</literal> specifies the number of
10463 targets above</simpara>
10465 <listitem><simpara><literal>actions</literal> specifies a bitmask of
10466 possible actions for a drag from this window</simpara>
10470 <para>The <literal>targets</literal> parameter is an array of the
10471 following structure:</para>
10473 <programlisting role="C">
10474 struct GtkTargetEntry {
10481 <para>The fields specify a string representing the drag type, optional
10482 flags and application assigned integer identifier.</para>
10484 <para>If a widget is no longer required to act as a source for
10485 drag-and-drop operations, the function
10486 <literal>gtk_drag_source_unset()</literal> can be used to remove a set
10487 of drag-and-drop target types.</para>
10489 <programlisting role="C">
10490 void gtk_drag_source_unset( GtkWidget *widget );
10495 <!-- ----------------------------------------------------------------- -->
10496 <sect2 id="sec-SignalsOnSourceWidgets">
10497 <title>Signals on the source widget:</title>
10499 <para>The source widget is sent the following signals during a
10500 drag-and-drop operation.</para>
10503 <title>Source widget signals</title>
10505 <colspec colname="Name" colwidth="150">
10506 <colspec colname="Prototype">
10509 <entry align="left" valign="middle">drag_begin</entry>
10510 <entry align="left" valign="middle"><literal>void (*drag_begin)(GtkWidget *widget,
10511 GdkDragContext *dc, gpointer data)</literal></entry>
10514 <entry align="left" valign="middle">drag_motion</entry>
10515 <entry align="left" valign="middle"><literal>gboolean (*drag_motion)(GtkWidget *widget,
10516 GdkDragContext *dc, gint x, gint y, guint t, gpointer data)</literal></entry>
10519 <entry align="left" valign="middle">drag_data_get</entry>
10520 <entry align="left" valign="middle"><literal>void (*drag_data_get)(GtkWidget *widget,
10521 GdkDragContext *dc, GtkSelectionData *selection_data, guint info, guint t, gpointer data)</literal></entry>
10524 <entry align="left" valign="middle">drag_data_delete</entry>
10525 <entry align="left" valign="middle"><literal>void (*drag_data_delete)(GtkWidget *widget,
10526 GdkDragContext *dc, gpointer data)</literal></entry>
10529 <entry align="left" valign="middle">drag_drop</entry>
10530 <entry align="left" valign="middle"><literal>gboolean (*drag_drop)(GtkWidget *widget,
10531 GdkDragContext *dc, gint x, gint y, guint t, gpointer data)</literal></entry>
10534 <entry align="left" valign="middle">drag_end</entry>
10535 <entry align="left" valign="middle"><literal>void (*drag_end)(GtkWidget *widget,
10536 GdkDragContext *dc, gpointer data)</literal></entry>
10544 <!-- ----------------------------------------------------------------- -->
10545 <sect2 id="sec-DNDDestWidgets">
10546 <title>Setting up a destination widget:</title>
10548 <para> <literal> gtk_drag_dest_set()</literal> specifies
10549 that this widget can receive drops and specifies what types of drops it
10550 can receive.</para>
10552 <para> <literal> gtk_drag_dest_unset()</literal> specifies
10553 that the widget can no longer receive drops.</para>
10555 <programlisting role="C">
10556 void gtk_drag_dest_set( GtkWidget *widget,
10557 GtkDestDefaults flags,
10558 const GtkTargetEntry *targets,
10560 GdkDragAction actions );
10562 void gtk_drag_dest_unset( GtkWidget *widget );
10567 <!-- ----------------------------------------------------------------- -->
10568 <sect2 id="sec-SignalsOnDestWidgets">
10569 <title>Signals on the destination widget:</title>
10571 <para>The destination widget is sent the following signals during a
10572 drag-and-drop operation.</para>
10575 <title>Destination widget signals</title>
10577 <colspec colname="Name" colwidth="150">
10578 <colspec colname="Prototype">
10581 <entry align="left" valign="middle">drag_data_received</entry>
10582 <entry align="left" valign="middle"><literal>void (*drag_data_received)(GtkWidget *widget,
10583 GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint info, guint t,
10584 gpointer data)</literal></entry>
10594 <!-- ***************************************************************** -->
10595 <chapter id="ch-GLib">
10596 <title>GLib</title>
10598 <para>GLib is a lower-level library that provides many useful definitions
10599 and functions available for use when creating GDK and GTK
10600 applications. These include definitions for basic types and their
10601 limits, standard macros, type conversions, byte order, memory
10602 allocation, warnings and assertions, message logging, timers, string
10603 utilities, hook functions, a lexical scanner, dynamic loading of
10604 modules, and automatic string completion. A number of data structures
10605 (and their related operations) are also defined, including memory
10606 chunks, doubly-linked lists, singly-linked lists, hash tables, strings
10607 (which can grow dynamically), string chunks (groups of strings),
10608 arrays (which can grow in size as elements are added), balanced binary
10609 trees, N-ary trees, quarks (a two-way association of a string and a
10610 unique integer identifier), keyed data lists (lists of data elements
10611 accessible by a string or integer id), relations and tuples (tables of
10612 data which can be indexed on any number of fields), and caches.</para>
10614 <para>A summary of some of GLib's capabilities follows; not every function,
10615 data structure, or operation is covered here. For more complete
10616 information about the GLib routines, see the GLib documentation. One
10617 source of GLib documentation is <ulink url="http://www.gtk.org/">http://www.gtk.org/</ulink>.</para>
10619 <para>If you are using a language other than C, you should consult your
10620 language's binding documentation. In some cases your language may
10621 have equivalent functionality built-in, while in other cases it may
10624 <!-- ----------------------------------------------------------------- -->
10625 <sect1 id="sec-Definitions">
10626 <title>Definitions</title>
10628 <para>Definitions for the extremes of many of the standard types are:</para>
10630 <programlisting role="C">
10643 <para>Also, the following typedefs. The ones left unspecified are dynamically set
10644 depending on the architecture. Remember to avoid counting on the size of a
10645 pointer if you want to be portable! E.g., a pointer on an Alpha is 8
10646 bytes, but 4 on Intel 80x86 family CPUs.</para>
10648 <programlisting role="C">
10655 unsigned char guchar;
10656 unsigned short gushort;
10657 unsigned long gulong;
10658 unsigned int guint;
10662 long double gldouble;
10676 <!-- ----------------------------------------------------------------- -->
10677 <sect1 id="sec-DoublyLinkedLists">
10678 <title>Doubly Linked Lists</title>
10680 <para>The following functions are used to create, manage, and destroy
10681 standard doubly linked lists. Each element in the list contains a
10682 piece of data, together with pointers which link to the previous and
10683 next elements in the list. This enables easy movement in either
10684 direction through the list. The data item is of type "gpointer",
10685 which means the data can be a pointer to your real data or (through
10686 casting) a numeric value (but do not assume that int and gpointer have
10687 the same size!). These routines internally allocate list elements in
10688 blocks, which is more efficient than allocating elements individually.</para>
10690 <para>There is no function to specifically create a list. Instead, simply
10691 create a variable of type GList* and set its value to NULL; NULL is
10692 considered to be the empty list.</para>
10694 <para>To add elements to a list, use the g_list_append(), g_list_prepend(),
10695 g_list_insert(), or g_list_insert_sorted() routines. In all cases
10696 they accept a pointer to the beginning of the list, and return the
10697 (possibly changed) pointer to the beginning of the list. Thus, for
10698 all of the operations that add or remove elements, be sure to save the
10699 returned value!</para>
10701 <programlisting role="C">
10702 GList *g_list_append( GList *list,
10706 <para>This adds a new element (with value <literal>data</literal>) onto the end of the
10709 <programlisting role="C">
10710 GList *g_list_prepend( GList *list,
10714 <para>This adds a new element (with value <literal>data</literal>) to the beginning of the
10717 <programlisting role="C">
10718 GList *g_list_insert( GList *list,
10723 <para>This inserts a new element (with value data) into the list at the
10724 given position. If position is 0, this is just like g_list_prepend();
10725 if position is less than 0, this is just like g_list_append().</para>
10727 <programlisting role="C">
10728 GList *g_list_remove( GList *list,
10732 <para>This removes the element in the list with the value <literal>data</literal>;
10733 if the element isn't there, the list is unchanged.</para>
10735 <programlisting role="C">
10736 void g_list_free( GList *list );
10739 <para>This frees all of the memory used by a GList. If the list elements
10740 refer to dynamically-allocated memory, then they should be freed
10743 <para>There are many other GLib functions that support doubly linked lists;
10744 see the glib documentation for more information. Here are a few of
10745 the more useful functions' signatures:</para>
10747 <programlisting role="C">
10748 GList *g_list_remove_link( GList *list,
10751 GList *g_list_reverse( GList *list );
10753 GList *g_list_nth( GList *list,
10756 GList *g_list_find( GList *list,
10759 GList *g_list_last( GList *list );
10761 GList *g_list_first( GList *list );
10763 gint g_list_length( GList *list );
10765 void g_list_foreach( GList *list,
10767 gpointer user_data );
10772 <!-- ----------------------------------------------------------------- -->
10773 <sect1 id="sec-SinglyLinkedLists">
10774 <title>Singly Linked Lists</title>
10776 <para>Many of the above functions for singly linked lists are identical to the
10777 above. Here is a list of some of their operations:</para>
10779 <programlisting role="C">
10780 GSList *g_slist_append( GSList *list,
10783 GSList *g_slist_prepend( GSList *list,
10786 GSList *g_slist_insert( GSList *list,
10790 GSList *g_slist_remove( GSList *list,
10793 GSList *g_slist_remove_link( GSList *list,
10796 GSList *g_slist_reverse( GSList *list );
10798 GSList *g_slist_nth( GSList *list,
10801 GSList *g_slist_find( GSList *list,
10804 GSList *g_slist_last( GSList *list );
10806 gint g_slist_length( GSList *list );
10808 void g_slist_foreach( GSList *list,
10810 gpointer user_data );
10816 <!-- ----------------------------------------------------------------- -->
10817 <sect1 id="sec-MemoryManagement">
10818 <title>Memory Management</title>
10820 <programlisting role="C">
10821 gpointer g_malloc( gulong size );
10824 <para>This is a replacement for malloc(). You do not need to check the return
10825 value as it is done for you in this function. If the memory allocation
10826 fails for whatever reasons, your applications will be terminated.</para>
10828 <programlisting role="C">
10829 gpointer g_malloc0( gulong size );
10832 <para>Same as above, but zeroes the memory before returning a pointer to it.</para>
10834 <programlisting role="C">
10835 gpointer g_realloc( gpointer mem,
10839 <para>Relocates "size" bytes of memory starting at "mem". Obviously, the
10840 memory should have been previously allocated.</para>
10842 <programlisting role="C">
10843 void g_free( gpointer mem );
10846 <para>Frees memory. Easy one. If <literal>mem</literal> is NULL it simply returns.</para>
10848 <programlisting role="C">
10849 void g_mem_profile( void );
10852 <para>Dumps a profile of used memory, but requires that you add <literal>#define
10853 MEM_PROFILE</literal> to the top of glib/gmem.c and re-make and make install.</para>
10855 <programlisting role="C">
10856 void g_mem_check( gpointer mem );
10859 <para>Checks that a memory location is valid. Requires you add <literal>#define
10860 MEM_CHECK</literal> to the top of gmem.c and re-make and make install.</para>
10864 <!-- ----------------------------------------------------------------- -->
10865 <sect1 id="sec-Timers">
10866 <title>Timers</title>
10868 <para>Timer functions can be used to time operations (e.g., to see how much
10869 time has elapsed). First, you create a new timer with g_timer_new().
10870 You can then use g_timer_start() to start timing an operation,
10871 g_timer_stop() to stop timing an operation, and g_timer_elapsed() to
10872 determine the elapsed time.</para>
10874 <programlisting role="C">
10875 GTimer *g_timer_new( void );
10877 void g_timer_destroy( GTimer *timer );
10879 void g_timer_start( GTimer *timer );
10881 void g_timer_stop( GTimer *timer );
10883 void g_timer_reset( GTimer *timer );
10885 gdouble g_timer_elapsed( GTimer *timer,
10886 gulong *microseconds );
10891 <!-- ----------------------------------------------------------------- -->
10892 <sect1 id="sec-StringHandling">
10893 <title>String Handling</title>
10895 <para>GLib defines a new type called a GString, which is similar to a
10896 standard C string but one that grows automatically. Its string data
10897 is null-terminated. What this gives you is protection from buffer
10898 overflow programming errors within your program. This is a very
10899 important feature, and hence I recommend that you make use of
10900 GStrings. GString itself has a simple public definition:</para>
10902 <programlisting role="C">
10905 gchar *str; /* Points to the string's current \0-terminated value. */
10906 gint len; /* Current length */
10910 <para>As you might expect, there are a number of operations you can do with
10913 <programlisting role="C">
10914 GString *g_string_new( gchar *init );
10917 <para>This constructs a GString, copying the string value of <literal>init</literal>
10918 into the GString and returning a pointer to it. NULL may be given as
10919 the argument for an initially empty GString.</para>
10921 <programlisting role="C">
10922 void g_string_free( GString *string,
10923 gint free_segment );
10926 <para>This frees the memory for the given GString. If <literal>free_segment</literal> is
10927 TRUE, then this also frees its character data.</para>
10929 <programlisting role="C">
10930 GString *g_string_assign( GString *lval,
10931 const gchar *rval );
10934 <para>This copies the characters from rval into lval, destroying the
10935 previous contents of lval. Note that lval will be lengthened as
10936 necessary to hold the string's contents, unlike the standard strcpy()
10939 <para>The rest of these functions should be relatively obvious (the _c
10940 versions accept a character instead of a string):</para>
10942 <programlisting role="C">
10943 GString *g_string_truncate( GString *string,
10946 GString *g_string_append( GString *string,
10949 GString *g_string_append_c( GString *string,
10952 GString *g_string_prepend( GString *string,
10955 GString *g_string_prepend_c( GString *string,
10958 void g_string_sprintf( GString *string,
10962 void g_string_sprintfa ( GString *string,
10969 <!-- ----------------------------------------------------------------- -->
10970 <sect1 id="sec-UtilityAndErrorFunctions">
10971 <title>Utility and Error Functions</title>
10973 <programlisting role="C">
10974 gchar *g_strdup( const gchar *str );
10977 <para>Replacement strdup function. Copies the original strings contents to
10978 newly allocated memory, and returns a pointer to it.</para>
10980 <programlisting role="C">
10981 gchar *g_strerror( gint errnum );
10984 <para>I recommend using this for all error messages. It's much nicer, and more
10985 portable than perror() or others. The output is usually of the form:</para>
10987 <programlisting role="C">
10988 program name:function that failed:file or further description:strerror
10991 <para>Here's an example of one such call used in our hello_world program:</para>
10993 <programlisting role="C">
10994 g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
10997 <programlisting role="C">
10998 void g_error( gchar *format, ... );
11001 <para>Prints an error message. The format is just like printf, but it
11002 prepends "** ERROR **: " to your message, and exits the program.
11003 Use only for fatal errors.</para>
11005 <programlisting role="C">
11006 void g_warning( gchar *format, ... );
11009 <para>Same as above, but prepends "** WARNING **: ", and does not exit the
11012 <programlisting role="C">
11013 void g_message( gchar *format, ... );
11016 <para>Prints "message: " prepended to the string you pass in.</para>
11018 <programlisting role="C">
11019 void g_print( gchar *format, ... );
11022 <para>Replacement for printf().</para>
11024 <para>And our last function:</para>
11026 <programlisting role="C">
11027 gchar *g_strsignal( gint signum );
11030 <para>Prints out the name of the Unix system signal given the signal number.
11031 Useful in generic signal handling functions.</para>
11033 <para>All of the above are more or less just stolen from glib.h. If anyone cares
11034 to document any function, just send me an email!</para>
11039 <!-- ***************************************************************** -->
11040 <chapter id="ch-GTKRCFiles">
11041 <title>GTK's rc Files</title>
11043 <para>GTK has its own way of dealing with application defaults, by using rc
11044 files. These can be used to set the colors of just about any widget, and
11045 can also be used to tile pixmaps onto the background of some widgets. </para>
11047 <!-- ----------------------------------------------------------------- -->
11048 <sect1 id="sec-FunctionsForRCFiles">
11049 <title>Functions For rc Files</title>
11051 <para>When your application starts, you should include a call to:</para>
11053 <programlisting role="C">
11054 void gtk_rc_parse( char *filename );
11057 <para>Passing in the filename of your rc file. This will cause GTK to parse
11058 this file, and use the style settings for the widget types defined
11061 <para>If you wish to have a special set of widgets that can take on a
11062 different style from others, or any other logical division of widgets,
11063 use a call to:</para>
11065 <programlisting role="C">
11066 void gtk_widget_set_name( GtkWidget *widget,
11070 <para>Passing your newly created widget as the first argument, and the name
11071 you wish to give it as the second. This will allow you to change the
11072 attributes of this widget by name through the rc file.</para>
11074 <para>If we use a call something like this:</para>
11076 <programlisting role="C">
11077 button = gtk_button_new_with_label ("Special Button");
11078 gtk_widget_set_name (button, "special button");
11081 <para>Then this button is given the name "special button" and may be addressed by
11082 name in the rc file as "special button.GtkButton". [<--- Verify ME!]</para>
11084 <para>The example rc file below, sets the properties of the main window, and lets
11085 all children of that main window inherit the style described by the "main
11086 button" style. The code used in the application is:</para>
11088 <programlisting role="C">
11089 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11090 gtk_widget_set_name (window, "main window");
11093 <para>And then the style is defined in the rc file using:</para>
11095 <programlisting role="C">
11096 widget "main window.*GtkButton*" style "main_button"
11099 <para>Which sets all the Button widgets in the "main window" to the
11100 "main_buttons" style as defined in the rc file.</para>
11102 <para>As you can see, this is a fairly powerful and flexible system. Use your
11103 imagination as to how best to take advantage of this.</para>
11107 <!-- ----------------------------------------------------------------- -->
11108 <sect1 id="sec-GTKsRCFileFormat">
11109 <title>GTK's rc File Format</title>
11111 <para>The format of the GTK file is illustrated in the example below. This is
11112 the testgtkrc file from the GTK distribution, but I've added a
11113 few comments and things. You may wish to include this explanation in
11114 your application to allow the user to fine tune his application.</para>
11116 <para>There are several directives to change the attributes of a widget.</para>
11119 <listitem><simpara>fg - Sets the foreground color of a widget.</simpara>
11121 <listitem><simpara>bg - Sets the background color of a widget.</simpara>
11123 <listitem><simpara>bg_pixmap - Sets the background of a widget to a tiled pixmap.</simpara>
11125 <listitem><simpara>font - Sets the font to be used with the given widget.</simpara>
11129 <para>In addition to this, there are several states a widget can be in, and you
11130 can set different colors, pixmaps and fonts for each state. These states are:</para>
11133 <listitem><simpara>NORMAL - The normal state of a widget, without the mouse over top of
11134 it, and not being pressed, etc.</simpara>
11136 <listitem><simpara>PRELIGHT - When the mouse is over top of the widget, colors defined
11137 using this state will be in effect.</simpara>
11139 <listitem><simpara>ACTIVE - When the widget is pressed or clicked it will be active, and
11140 the attributes assigned by this tag will be in effect.</simpara>
11142 <listitem><simpara>INSENSITIVE - When a widget is set insensitive, and cannot be
11143 activated, it will take these attributes.</simpara>
11145 <listitem><simpara>SELECTED - When an object is selected, it takes these attributes.</simpara>
11149 <para>When using the "fg" and "bg" keywords to set the colors of widgets, the
11152 <programlisting role="C">
11153 fg[<STATE>] = { Red, Green, Blue }
11156 <para>Where STATE is one of the above states (PRELIGHT, ACTIVE, etc), and the Red,
11157 Green and Blue are values in the range of 0 - 1.0, { 1.0, 1.0, 1.0 } being
11158 white. They must be in float form, or they will register as 0, so a straight
11159 "1" will not work, it must be "1.0". A straight "0" is fine because it
11160 doesn't matter if it's not recognized. Unrecognized values are set to 0.</para>
11162 <para>bg_pixmap is very similar to the above, except the colors are replaced by a
11165 <para>pixmap_path is a list of paths separated by ":"'s. These paths will be
11166 searched for any pixmap you specify.</para>
11168 <para>The font directive is simply:</para>
11170 <programlisting role="C">
11171 font = "<font name>"
11174 <para>The only hard part is figuring out the font string. Using xfontsel or
11175 a similar utility should help.</para>
11177 <para>The "widget_class" sets the style of a class of widgets. These classes are
11178 listed in the widget overview on the class hierarchy.</para>
11180 <para>The "widget" directive sets a specifically named set of widgets to a
11181 given style, overriding any style set for the given widget class.
11182 These widgets are registered inside the application using the
11183 gtk_widget_set_name() call. This allows you to specify the attributes of a
11184 widget on a per widget basis, rather than setting the attributes of an
11185 entire widget class. I urge you to document any of these special widgets so
11186 users may customize them.</para>
11188 <para>When the keyword <literal>parent</> is used as an attribute, the widget will take on
11189 the attributes of its parent in the application.</para>
11191 <para>When defining a style, you may assign the attributes of a previously defined
11192 style to this new one.</para>
11194 <programlisting role="C">
11195 style "main_button" = "button"
11197 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
11198 bg[PRELIGHT] = { 0.75, 0, 0 }
11202 <para>This example takes the "button" style, and creates a new "main_button" style
11203 simply by changing the font and prelight background color of the "button"
11206 <para>Of course, many of these attributes don't apply to all widgets. It's a
11207 simple matter of common sense really. Anything that could apply, should.</para>
11211 <!-- ----------------------------------------------------------------- -->
11212 <sect1 id="sec-ExampleRCFile">
11213 <title>Example rc file</title>
11215 <programlisting role="C">
11216 # pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
11218 pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
11220 # style <name> [= <name>]
11225 # widget <widget_set> style <style_name>
11226 # widget_class <widget_class_set> style <style_name>
11228 # Here is a list of all the possible states. Note that some do not apply to
11231 # NORMAL - The normal state of a widget, without the mouse over top of
11232 # it, and not being pressed, etc.
11234 # PRELIGHT - When the mouse is over top of the widget, colors defined
11235 # using this state will be in effect.
11237 # ACTIVE - When the widget is pressed or clicked it will be active, and
11238 # the attributes assigned by this tag will be in effect.
11240 # INSENSITIVE - When a widget is set insensitive, and cannot be
11241 # activated, it will take these attributes.
11243 # SELECTED - When an object is selected, it takes these attributes.
11245 # Given these states, we can set the attributes of the widgets in each of
11246 # these states using the following directives.
11248 # fg - Sets the foreground color of a widget.
11249 # fg - Sets the background color of a widget.
11250 # bg_pixmap - Sets the background of a widget to a tiled pixmap.
11251 # font - Sets the font to be used with the given widget.
11254 # This sets a style called "button". The name is not really important, as
11255 # it is assigned to the actual widgets at the bottom of the file.
11259 #This sets the padding around the window to the pixmap specified.
11260 #bg_pixmap[<STATE>] = "<pixmap filename>"
11261 bg_pixmap[NORMAL] = "warning.xpm"
11266 #Sets the foreground color (font color) to red when in the "NORMAL"
11269 fg[NORMAL] = { 1.0, 0, 0 }
11271 #Sets the background pixmap of this widget to that of its parent.
11272 bg_pixmap[NORMAL] = "<parent>"
11277 # This shows all the possible states for a button. The only one that
11278 # doesn't apply is the SELECTED state.
11280 fg[PRELIGHT] = { 0, 1.0, 1.0 }
11281 bg[PRELIGHT] = { 0, 0, 1.0 }
11282 bg[ACTIVE] = { 1.0, 0, 0 }
11283 fg[ACTIVE] = { 0, 1.0, 0 }
11284 bg[NORMAL] = { 1.0, 1.0, 0 }
11285 fg[NORMAL] = { .99, 0, .99 }
11286 bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
11287 fg[INSENSITIVE] = { 1.0, 0, 1.0 }
11290 # In this example, we inherit the attributes of the "button" style and then
11291 # override the font and background color when prelit to create a new
11292 # "main_button" style.
11294 style "main_button" = "button"
11296 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
11297 bg[PRELIGHT] = { 0.75, 0, 0 }
11300 style "toggle_button" = "button"
11302 fg[NORMAL] = { 1.0, 0, 0 }
11303 fg[ACTIVE] = { 1.0, 0, 0 }
11305 # This sets the background pixmap of the toggle_button to that of its
11306 # parent widget (as defined in the application).
11307 bg_pixmap[NORMAL] = "<parent>"
11312 bg_pixmap[NORMAL] = "marble.xpm"
11313 fg[NORMAL] = { 1.0, 1.0, 1.0 }
11318 font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
11321 # pixmap_path "~/.pixmaps"
11323 # These set the widget types to use the styles defined above.
11324 # The widget types are listed in the class hierarchy, but could probably be
11325 # just listed in this document for the users reference.
11327 widget_class "GtkWindow" style "window"
11328 widget_class "GtkDialog" style "window"
11329 widget_class "GtkFileSelection" style "window"
11330 widget_class "*Gtk*Scale" style "scale"
11331 widget_class "*GtkCheckButton*" style "toggle_button"
11332 widget_class "*GtkRadioButton*" style "toggle_button"
11333 widget_class "*GtkButton*" style "button"
11334 widget_class "*Ruler" style "ruler"
11335 widget_class "*GtkText" style "text"
11337 # This sets all the buttons that are children of the "main window" to
11338 # the main_button style. These must be documented to be taken advantage of.
11339 widget "main window.*GtkButton*" style "main_button"
11345 <!-- ***************************************************************** -->
11346 <chapter id="ch-WritingYourOwnWidgets">
11347 <title>Writing Your Own Widgets</title>
11349 <!-- ----------------------------------------------------------------- -->
11350 <sect1 id="sec-WidgetsOverview">
11351 <title>Overview</title>
11353 <para>Although the GTK distribution comes with many types of widgets that
11354 should cover most basic needs, there may come a time when you need to
11355 create your own new widget type. Since GTK uses widget inheritance
11356 extensively, and there is already a widget that is close to what you want,
11357 it is often possible to make a useful new widget type in
11358 just a few lines of code. But before starting work on a new widget, check
11359 around first to make sure that someone has not already written
11360 it. This will prevent duplication of effort and keep the number of
11361 GTK widgets out there to a minimum, which will help keep both the code
11362 and the interface of different applications consistent. As a flip side
11363 to this, once you finish your widget, announce it to the world so
11364 other people can benefit. The best place to do this is probably the
11365 <literal>gtk-list</literal>.</para>
11367 <para>Complete sources for the example widgets are available at the place you
11368 got this tutorial, or from:</para>
11370 <para><ulink url="http://www.gtk.org/~otaylor/gtk/tutorial/">http://www.gtk.org/~otaylor/gtk/tutorial/</ulink></para>
11375 <!-- ----------------------------------------------------------------- -->
11376 <sect1 id="sec-TheAnatomyOfAWidget">
11377 <title>The Anatomy Of A Widget</title>
11379 <para>In order to create a new widget, it is important to have an
11380 understanding of how GTK objects work. This section is just meant as a
11381 brief overview. See the reference documentation for the details. </para>
11383 <para>GTK widgets are implemented in an object oriented fashion. However,
11384 they are implemented in standard C. This greatly improves portability
11385 and stability over using current generation C++ compilers; however,
11386 it does mean that the widget writer has to pay attention to some of
11387 the implementation details. The information common to all instances of
11388 one class of widgets (e.g., to all Button widgets) is stored in the
11389 <emphasis>class structure</emphasis>. There is only one copy of this in
11390 which is stored information about the class's signals
11391 (which act like virtual functions in C). To support inheritance, the
11392 first field in the class structure must be a copy of the parent's
11393 class structure. The declaration of the class structure of GtkButtton
11396 <programlisting role="C">
11397 struct _GtkButtonClass
11399 GtkContainerClass parent_class;
11401 void (* pressed) (GtkButton *button);
11402 void (* released) (GtkButton *button);
11403 void (* clicked) (GtkButton *button);
11404 void (* enter) (GtkButton *button);
11405 void (* leave) (GtkButton *button);
11409 <para>When a button is treated as a container (for instance, when it is
11410 resized), its class structure can be cast to GtkContainerClass, and
11411 the relevant fields used to handle the signals.</para>
11413 <para>There is also a structure for each widget that is created on a
11414 per-instance basis. This structure has fields to store information that
11415 is different for each instance of the widget. We'll call this
11416 structure the <emphasis>object structure</emphasis>. For the Button class, it looks
11419 <programlisting role="C">
11422 GtkContainer container;
11426 guint in_button : 1;
11427 guint button_down : 1;
11431 <para>Note that, similar to the class structure, the first field is the
11432 object structure of the parent class, so that this structure can be
11433 cast to the parent class' object structure as needed.</para>
11437 <!-- ----------------------------------------------------------------- -->
11438 <sect1 id="sec-CreatingACompositeWidget">
11439 <title>Creating a Composite widget</title>
11441 <!-- ----------------------------------------------------------------- -->
11443 <title>Introduction</title>
11445 <para>One type of widget that you may be interested in creating is a
11446 widget that is merely an aggregate of other GTK widgets. This type of
11447 widget does nothing that couldn't be done without creating new
11448 widgets, but provides a convenient way of packaging user interface
11449 elements for reuse. The FileSelection and ColorSelection widgets in
11450 the standard distribution are examples of this type of widget.</para>
11452 <para>The example widget that we'll create in this section is the Tictactoe
11453 widget, a 3x3 array of toggle buttons which triggers a signal when all
11454 three buttons in a row, column, or on one of the diagonals are
11458 <inlinemediaobject>
11460 <imagedata fileref="tictactoe.png" format="png">
11462 </inlinemediaobject>
11467 <!-- ----------------------------------------------------------------- -->
11469 <title>Choosing a parent class</title>
11471 <para>The parent class for a composite widget is typically the container
11472 class that holds all of the elements of the composite widget. For
11473 example, the parent class of the FileSelection widget is the
11474 Dialog class. Since our buttons will be arranged in a table, it
11475 might seem natural to make our parent class the Table
11476 class. Unfortunately, this turns out not to work. The creation of a
11477 widget is divided among two functions - a <literal>WIDGETNAME_new()</literal>
11478 function that the user calls, and a <literal>WIDGETNAME_init()</literal> function
11479 which does the basic work of initializing the widget which is
11480 independent of the arguments passed to the <literal>_new()</literal>
11481 function. Descendant widgets only call the <literal>_init</literal> function of
11482 their parent widget. But this division of labor doesn't work well for
11483 tables, which when created need to know the number of rows and
11484 columns in the table. Unless we want to duplicate most of the
11485 functionality of <literal>gtk_table_new()</literal> in our Tictactoe widget, we had
11486 best avoid deriving it from Table. For that reason, we derive it
11487 from VBox instead, and stick our table inside the VBox.</para>
11491 <!-- ----------------------------------------------------------------- -->
11493 <title>The header file</title>
11495 <para>Each widget class has a header file which declares the object and
11496 class structures for that widget, along with public functions.
11497 A couple of features are worth pointing out. To prevent duplicate
11498 definitions, we wrap the entire header file in:</para>
11500 <programlisting role="C">
11501 #ifndef __TICTACTOE_H__
11502 #define __TICTACTOE_H__
11506 #endif /* __TICTACTOE_H__ */
11509 <para>And to keep C++ programs that include the header file happy, in:</para>
11511 <programlisting role="C">
11514 #endif /* __cplusplus */
11520 #endif /* __cplusplus */
11523 <para>Along with the functions and structures, we declare three standard
11524 macros in our header file, <literal>TICTACTOE(obj)</literal>,
11525 <literal>TICTACTOE_CLASS(klass)</literal>, and <literal>IS_TICTACTOE(obj)</literal>, which cast a
11526 pointer into a pointer to the object or class structure, and check
11527 if an object is a Tictactoe widget respectively.</para>
11529 <para>Here is the complete header file:</para>
11531 <programlisting role="C">
11532 <!-- example-start tictactoe tictactoe.h -->
11534 /* GTK - The GIMP Toolkit
11535 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
11537 * This library is free software; you can redistribute it and/or
11538 * modify it under the terms of the GNU Library General Public
11539 * License as published by the Free Software Foundation; either
11540 * version 2 of the License, or (at your option) any later version.
11542 * This library is distributed in the hope that it will be useful,
11543 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11544 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11545 * Library General Public License for more details.
11547 * You should have received a copy of the GNU Library General Public
11548 * License along with this library; if not, write to the
11549 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
11550 * Boston, MA 02111-1307, USA.
11552 #ifndef __TICTACTOE_H__
11553 #define __TICTACTOE_H__
11556 #include <gdk/gdk.h>
11557 #include <gtk/gtkvbox.h>
11562 #endif /* __cplusplus */
11564 #define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
11565 #define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
11566 #define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
11569 typedef struct _Tictactoe Tictactoe;
11570 typedef struct _TictactoeClass TictactoeClass;
11576 GtkWidget *buttons[3][3];
11579 struct _TictactoeClass
11581 GtkVBoxClass parent_class;
11583 void (* tictactoe) (Tictactoe *ttt);
11586 GtkType tictactoe_get_type (void);
11587 GtkWidget* tictactoe_new (void);
11588 void tictactoe_clear (Tictactoe *ttt);
11592 #endif /* __cplusplus */
11594 #endif /* __TICTACTOE_H__ */
11596 <!-- example-end -->
11601 <!-- ----------------------------------------------------------------- -->
11603 <title>The <literal>_get_type()</literal> function</title>
11605 <para>We now continue on to the implementation of our widget. A core
11606 function for every widget is the function
11607 <literal>WIDGETNAME_get_type()</literal>. This function, when first called, tells
11608 GTK about the widget class, and gets an ID that uniquely identifies
11609 the widget class. Upon subsequent calls, it just returns the ID.</para>
11611 <programlisting role="C">
11613 tictactoe_get_type ()
11615 static guint ttt_type = 0;
11619 GtkTypeInfo ttt_info =
11622 sizeof (Tictactoe),
11623 sizeof (TictactoeClass),
11624 (GtkClassInitFunc) tictactoe_class_init,
11625 (GtkObjectInitFunc) tictactoe_init,
11626 (GtkArgSetFunc) NULL,
11627 (GtkArgGetFunc) NULL
11630 ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
11637 <para>The GtkTypeInfo structure has the following definition:</para>
11639 <programlisting role="C">
11640 struct _GtkTypeInfo
11645 GtkClassInitFunc class_init_func;
11646 GtkObjectInitFunc object_init_func;
11647 GtkArgSetFunc arg_set_func;
11648 GtkArgGetFunc arg_get_func;
11652 <para>The fields of this structure are pretty self-explanatory. We'll ignore
11653 the <literal>arg_set_func</literal> and <literal>arg_get_func</literal> fields here: they have an important,
11655 unimplemented, role in allowing widget options to be conveniently set
11656 from interpreted languages. Once GTK has a correctly filled in copy of
11657 this structure, it knows how to create objects of a particular widget
11662 <!-- ----------------------------------------------------------------- -->
11664 <title>The <literal>_class_init()</literal> function</title>
11666 <para>The <literal>WIDGETNAME_class_init()</literal> function initializes the fields of
11667 the widget's class structure, and sets up any signals for the
11668 class. For our Tictactoe widget it looks like:</para>
11670 <programlisting role="C">
11677 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
11680 tictactoe_class_init (TictactoeClass *class)
11682 GtkObjectClass *object_class;
11684 object_class = (GtkObjectClass*) class;
11686 tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
11688 object_class->type,
11689 GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
11690 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
11693 gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
11695 class->tictactoe = NULL;
11699 <para>Our widget has just one signal, the <literal>tictactoe</literal> signal that is
11700 invoked when a row, column, or diagonal is completely filled in. Not
11701 every composite widget needs signals, so if you are reading this for
11702 the first time, you may want to skip to the next section now, as
11703 things are going to get a bit complicated.</para>
11705 <para>The function:</para>
11707 <programlisting role="C">
11708 gint gtk_signal_new( const gchar *name,
11709 GtkSignalRunType run_type,
11710 GtkType object_type,
11711 gint function_offset,
11712 GtkSignalMarshaller marshaller,
11713 GtkType return_val,
11718 <para>Creates a new signal. The parameters are:</para>
11721 <listitem><simpara> <literal>name</literal>: The name of the signal.</simpara>
11724 <listitem><simpara> <literal>run_type</literal>: Whether the default handler runs before or after
11725 user handlers. Usually this will be <literal>GTK_RUN_FIRST</literal>, or <literal>GTK_RUN_LAST</literal>,
11726 although there are other possibilities.</simpara>
11729 <listitem><simpara> <literal>object_type</literal>: The ID of the object that this signal applies
11730 to. (It will also apply to that objects descendants.)</simpara>
11733 <listitem><simpara> <literal>function_offset</literal>: The offset within the class structure of
11734 a pointer to the default handler.</simpara>
11737 <listitem><simpara> <literal>marshaller</literal>: A function that is used to invoke the signal
11738 handler. For signal handlers that have no arguments other than the
11739 object that emitted the signal and user data, we can use the
11740 pre-supplied marshaller function <literal>gtk_signal_default_marshaller</literal>.</simpara>
11743 <listitem><simpara> <literal>return_val</literal>: The type of the return val.</simpara>
11746 <listitem><simpara> <literal>nparams</literal>: The number of parameters of the signal handler
11747 (other than the two default ones mentioned above)</simpara>
11750 <listitem><simpara> <literal>...</literal>: The types of the parameters.</simpara>
11754 <para>When specifying types, the <literal>GtkType</literal> enumeration is used:</para>
11756 <programlisting role="C">
11779 /* it'd be great if the next two could be removed eventually */
11781 GTK_TYPE_C_CALLBACK,
11785 } GtkFundamentalType;
11788 <para><literal>gtk_signal_new()</literal> returns a unique integer identifier for the
11789 signal, that we store in the <literal>tictactoe_signals</literal> array, which we
11790 index using an enumeration. (Conventionally, the enumeration elements
11791 are the signal name, uppercased, but here there would be a conflict
11792 with the <literal>TICTACTOE()</literal> macro, so we called it <literal>TICTACTOE_SIGNAL</literal>
11795 <para>After creating our signals, we need to tell GTK to associate our
11796 signals with the Tictactoe class. We do that by calling
11797 <literal>gtk_object_class_add_signals()</literal>. We then set the pointer which
11798 points to the default handler for the "tictactoe" signal to NULL,
11799 indicating that there is no default action.</para>
11803 <!-- ----------------------------------------------------------------- -->
11805 <title>The <literal>_init()</literal> function</title>
11807 <para>Each widget class also needs a function to initialize the object
11808 structure. Usually, this function has the fairly limited role of
11809 setting the fields of the structure to default values. For composite
11810 widgets, however, this function also creates the component widgets.</para>
11812 <programlisting role="C">
11814 tictactoe_init (Tictactoe *ttt)
11819 table = gtk_table_new (3, 3, TRUE);
11820 gtk_container_add (GTK_CONTAINER(ttt), table);
11821 gtk_widget_show (table);
11826 ttt->buttons[i][j] = gtk_toggle_button_new ();
11827 gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
11829 gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
11830 GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
11831 gtk_widget_set_size_request (ttt->buttons[i][j], 20, 20);
11832 gtk_widget_show (ttt->buttons[i][j]);
11839 <!-- ----------------------------------------------------------------- -->
11841 <title>And the rest...</title>
11843 <para>There is one more function that every widget (except for base widget
11844 types like Bin that cannot be instantiated) needs to have - the
11845 function that the user calls to create an object of that type. This is
11846 conventionally called <literal>WIDGETNAME_new()</literal>. In some
11847 widgets, though not for the Tictactoe widgets, this function takes
11848 arguments, and does some setup based on the arguments. The other two
11849 functions are specific to the Tictactoe widget. </para>
11851 <para><literal>tictactoe_clear()</literal> is a public function that resets all the
11852 buttons in the widget to the up position. Note the use of
11853 <literal>gtk_signal_handler_block_by_data()</literal> to keep our signal handler for
11854 button toggles from being triggered unnecessarily.</para>
11856 <para><literal>tictactoe_toggle()</literal> is the signal handler that is invoked when the
11857 user clicks on a button. It checks to see if there are any winning
11858 combinations that involve the toggled button, and if so, emits
11859 the "tictactoe" signal.</para>
11861 <programlisting role="C">
11865 return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
11869 tictactoe_clear (Tictactoe *ttt)
11876 gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
11877 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
11879 gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
11884 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
11888 static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
11889 { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
11890 { 0, 1, 2 }, { 0, 1, 2 } };
11891 static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
11892 { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
11893 { 0, 1, 2 }, { 2, 1, 0 } };
11895 int success, found;
11897 for (k=0; k<8; k++)
11904 success = success &&
11905 GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
11907 ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
11910 if (success && found)
11912 gtk_signal_emit (GTK_OBJECT (ttt),
11913 tictactoe_signals[TICTACTOE_SIGNAL]);
11920 <para>And finally, an example program using our Tictactoe widget:</para>
11922 <programlisting role="C">
11923 #include <gtk/gtk.h>
11924 #include "tictactoe.h"
11926 /* Invoked when a row, column or diagonal is completed */
11928 win (GtkWidget *widget, gpointer data)
11930 g_print ("Yay!\n");
11931 tictactoe_clear (TICTACTOE (widget));
11935 main (int argc, char *argv[])
11940 gtk_init (&argc, &argv);
11942 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11944 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
11946 gtk_signal_connect (GTK_OBJECT (window), "destroy",
11947 GTK_SIGNAL_FUNC (gtk_exit), NULL);
11949 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
11951 /* Create a new Tictactoe widget */
11952 ttt = tictactoe_new ();
11953 gtk_container_add (GTK_CONTAINER (window), ttt);
11954 gtk_widget_show (ttt);
11956 /* And attach to its "tictactoe" signal */
11957 gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
11958 GTK_SIGNAL_FUNC (win), NULL);
11960 gtk_widget_show (window);
11971 <!-- ----------------------------------------------------------------- -->
11972 <sect1 id="sec-CreatingAWidgetFromScratch">
11973 <title>Creating a widget from scratch</title>
11975 <!-- ----------------------------------------------------------------- -->
11977 <title>Introduction</title>
11979 <para>In this section, we'll learn more about how widgets display themselves
11980 on the screen and interact with events. As an example of this, we'll
11981 create an analog dial widget with a pointer that the user can drag to
11982 set the value.</para>
11985 <inlinemediaobject>
11987 <imagedata fileref="gtkdial.png" format="png">
11989 </inlinemediaobject>
11994 <!-- ----------------------------------------------------------------- -->
11996 <title>Displaying a widget on the screen</title>
11998 <para>There are several steps that are involved in displaying on the screen.
11999 After the widget is created with a call to <literal>WIDGETNAME_new()</literal>,
12000 several more functions are needed:</para>
12003 <listitem><simpara> <literal>WIDGETNAME_realize()</literal> is responsible for creating an X
12004 window for the widget if it has one.</simpara>
12006 <listitem><simpara> <literal>WIDGETNAME_map()</literal> is invoked after the user calls
12007 <literal>gtk_widget_show()</literal>. It is responsible for making sure the widget
12008 is actually drawn on the screen (<emphasis>mapped</emphasis>). For a container class,
12009 it must also make calls to <literal>map()</literal>> functions of any child widgets.</simpara>
12011 <listitem><simpara> <literal>WIDGETNAME_draw()</literal> is invoked when <literal>gtk_widget_draw()</literal>
12012 is called for the widget or one of its ancestors. It makes the actual
12013 calls to the drawing functions to draw the widget on the screen. For
12014 container widgets, this function must make calls to
12015 <literal>gtk_widget_draw()</literal> for its child widgets.</simpara>
12017 <listitem><simpara> <literal>WIDGETNAME_expose()</literal> is a handler for expose events for the
12018 widget. It makes the necessary calls to the drawing functions to draw
12019 the exposed portion on the screen. For container widgets, this
12020 function must generate expose events for its child widgets which don't
12021 have their own windows. (If they have their own windows, then X will
12022 generate the necessary expose events.)</simpara>
12026 <para>You might notice that the last two functions are quite similar - each
12027 is responsible for drawing the widget on the screen. In fact many
12028 types of widgets don't really care about the difference between the
12029 two. The default <literal>draw()</literal> function in the widget class simply
12030 generates a synthetic expose event for the redrawn area. However, some
12031 types of widgets can save work by distinguishing between the two
12032 functions. For instance, if a widget has multiple X windows, then
12033 since expose events identify the exposed window, it can redraw only
12034 the affected window, which is not possible for calls to <literal>draw()</literal>.</para>
12036 <para>Container widgets, even if they don't care about the difference for
12037 themselves, can't simply use the default <literal>draw()</literal> function because
12038 their child widgets might care about the difference. However,
12039 it would be wasteful to duplicate the drawing code between the two
12040 functions. The convention is that such widgets have a function called
12041 <literal>WIDGETNAME_paint()</literal> that does the actual work of drawing the
12042 widget, that is then called by the <literal>draw()</literal> and <literal>expose()</literal>
12045 <para>In our example approach, since the dial widget is not a container
12046 widget, and only has a single window, we can take the simplest
12047 approach and use the default <literal>draw()</literal> function and only implement
12048 an <literal>expose()</literal> function.</para>
12052 <!-- ----------------------------------------------------------------- -->
12054 <title>The origins of the Dial Widget</title>
12056 <para>Just as all land animals are just variants on the first amphibian that
12057 crawled up out of the mud, GTK widgets tend to start off as variants
12058 of some other, previously written widget. Thus, although this section
12059 is entitled "Creating a Widget from Scratch", the Dial widget really
12060 began with the source code for the Range widget. This was picked as a
12061 starting point because it would be nice if our Dial had the same
12062 interface as the Scale widgets which are just specialized descendants
12063 of the Range widget. So, though the source code is presented below in
12064 finished form, it should not be implied that it was written, <emphasis>ab
12065 initio</emphasis> in this fashion. Also, if you aren't yet familiar with
12066 how scale widgets work from the application writer's point of view, it
12067 would be a good idea to look them over before continuing.</para>
12071 <!-- ----------------------------------------------------------------- -->
12073 <title>The Basics</title>
12075 <para>Quite a bit of our widget should look pretty familiar from the
12076 Tictactoe widget. First, we have a header file:</para>
12078 <programlisting role="C">
12079 /* GTK - The GIMP Toolkit
12080 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
12082 * This library is free software; you can redistribute it and/or
12083 * modify it under the terms of the GNU Library General Public
12084 * License as published by the Free Software Foundation; either
12085 * version 2 of the License, or (at your option) any later version.
12087 * This library is distributed in the hope that it will be useful,
12088 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12089 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12090 * Library General Public License for more details.
12092 * You should have received a copy of the GNU Library General Public
12093 * License along with this library; if not, write to the Free
12094 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
12097 #ifndef __GTK_DIAL_H__
12098 #define __GTK_DIAL_H__
12100 #include <gdk/gdk.h>
12101 #include <gtk/gtkadjustment.h>
12102 #include <gtk/gtkwidget.h>
12107 #endif /* __cplusplus */
12110 #define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
12111 #define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
12112 #define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
12115 typedef struct _GtkDial GtkDial;
12116 typedef struct _GtkDialClass GtkDialClass;
12122 /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
12125 /* Button currently pressed or 0 if none */
12128 /* Dimensions of dial components */
12130 gint pointer_width;
12132 /* ID of update timer, or 0 if none */
12135 /* Current angle */
12138 /* Old values from adjustment stored so we know when something changes */
12143 /* The adjustment object that stores the data for this dial */
12144 GtkAdjustment *adjustment;
12147 struct _GtkDialClass
12149 GtkWidgetClass parent_class;
12153 GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
12154 GtkType gtk_dial_get_type (void);
12155 GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
12156 void gtk_dial_set_update_policy (GtkDial *dial,
12157 GtkUpdateType policy);
12159 void gtk_dial_set_adjustment (GtkDial *dial,
12160 GtkAdjustment *adjustment);
12163 #endif /* __cplusplus */
12166 #endif /* __GTK_DIAL_H__ */
12169 <para>Since there is quite a bit more going on in this widget than the last
12170 one, we have more fields in the data structure, but otherwise things
12171 are pretty similar.</para>
12173 <para>Next, after including header files and declaring a few constants,
12174 we have some functions to provide information about the widget
12175 and initialize it:</para>
12177 <programlisting role="C">
12178 #include <math.h>
12179 #include <stdio.h>
12180 #include <gtk/gtkmain.h>
12181 #include <gtk/gtksignal.h>
12183 #include "gtkdial.h"
12185 #define SCROLL_DELAY_LENGTH 300
12186 #define DIAL_DEFAULT_SIZE 100
12188 /* Forward declarations */
12190 [ omitted to save space ]
12194 static GtkWidgetClass *parent_class = NULL;
12197 gtk_dial_get_type ()
12199 static GtkType dial_type = 0;
12203 static const GtkTypeInfo dial_info =
12207 sizeof (GtkDialClass),
12208 (GtkClassInitFunc) gtk_dial_class_init,
12209 (GtkObjectInitFunc) gtk_dial_init,
12210 /* reserved_1 */ NULL,
12211 /* reserved_1 */ NULL,
12212 (GtkClassInitFunc) NULL
12215 dial_type = gtk_type_unique (GTK_TYPE_WIDGET, &dial_info);
12222 gtk_dial_class_init (GtkDialClass *class)
12224 GtkObjectClass *object_class;
12225 GtkWidgetClass *widget_class;
12227 object_class = (GtkObjectClass*) class;
12228 widget_class = (GtkWidgetClass*) class;
12230 parent_class = gtk_type_class (gtk_widget_get_type ());
12232 object_class->destroy = gtk_dial_destroy;
12234 widget_class->realize = gtk_dial_realize;
12235 widget_class->expose_event = gtk_dial_expose;
12236 widget_class->size_request = gtk_dial_size_request;
12237 widget_class->size_allocate = gtk_dial_size_allocate;
12238 widget_class->button_press_event = gtk_dial_button_press;
12239 widget_class->button_release_event = gtk_dial_button_release;
12240 widget_class->motion_notify_event = gtk_dial_motion_notify;
12244 gtk_dial_init (GtkDial *dial)
12247 dial->policy = GTK_UPDATE_CONTINUOUS;
12250 dial->pointer_width = 0;
12252 dial->old_value = 0.0;
12253 dial->old_lower = 0.0;
12254 dial->old_upper = 0.0;
12255 dial->adjustment = NULL;
12259 gtk_dial_new (GtkAdjustment *adjustment)
12263 dial = gtk_type_new (gtk_dial_get_type ());
12266 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
12268 gtk_dial_set_adjustment (dial, adjustment);
12270 return GTK_WIDGET (dial);
12274 gtk_dial_destroy (GtkObject *object)
12278 g_return_if_fail (object != NULL);
12279 g_return_if_fail (GTK_IS_DIAL (object));
12281 dial = GTK_DIAL (object);
12283 if (dial->adjustment)
12284 gtk_object_unref (GTK_OBJECT (dial->adjustment));
12286 if (GTK_OBJECT_CLASS (parent_class)->destroy)
12287 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
12291 <para>Note that this <literal>init()</literal> function does less than for the Tictactoe
12292 widget, since this is not a composite widget, and the <literal>new()</literal>
12293 function does more, since it now has an argument. Also, note that when
12294 we store a pointer to the Adjustment object, we increment its
12295 reference count, (and correspondingly decrement it when we no longer
12296 use it) so that GTK can keep track of when it can be safely destroyed.</para>
12298 <para>Also, there are a few function to manipulate the widget's options:</para>
12300 <programlisting role="C">
12302 gtk_dial_get_adjustment (GtkDial *dial)
12304 g_return_val_if_fail (dial != NULL, NULL);
12305 g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
12307 return dial->adjustment;
12311 gtk_dial_set_update_policy (GtkDial *dial,
12312 GtkUpdateType policy)
12314 g_return_if_fail (dial != NULL);
12315 g_return_if_fail (GTK_IS_DIAL (dial));
12317 dial->policy = policy;
12321 gtk_dial_set_adjustment (GtkDial *dial,
12322 GtkAdjustment *adjustment)
12324 g_return_if_fail (dial != NULL);
12325 g_return_if_fail (GTK_IS_DIAL (dial));
12327 if (dial->adjustment)
12329 gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
12330 gtk_object_unref (GTK_OBJECT (dial->adjustment));
12333 dial->adjustment = adjustment;
12334 gtk_object_ref (GTK_OBJECT (dial->adjustment));
12336 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
12337 (GtkSignalFunc) gtk_dial_adjustment_changed,
12339 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
12340 (GtkSignalFunc) gtk_dial_adjustment_value_changed,
12343 dial->old_value = adjustment->value;
12344 dial->old_lower = adjustment->lower;
12345 dial->old_upper = adjustment->upper;
12347 gtk_dial_update (dial);
12353 <!-- ----------------------------------------------------------------- -->
12355 <title><literal>gtk_dial_realize()</literal></title>
12357 <para>Now we come to some new types of functions. First, we have a function
12358 that does the work of creating the X window. Notice that a mask is
12359 passed to the function <literal>gdk_window_new()</literal> which specifies which fields of
12360 the GdkWindowAttr structure actually have data in them (the remaining
12361 fields will be given default values). Also worth noting is the way the
12362 event mask of the widget is created. We call
12363 <literal>gtk_widget_get_events()</literal> to retrieve the event mask that the user
12364 has specified for this widget (with <literal>gtk_widget_set_events()</literal>), and
12365 add the events that we are interested in ourselves.</para>
12367 <para>After creating the window, we set its style and background, and put a
12368 pointer to the widget in the user data field of the GdkWindow. This
12369 last step allows GTK to dispatch events for this window to the correct
12372 <programlisting role="C">
12374 gtk_dial_realize (GtkWidget *widget)
12377 GdkWindowAttr attributes;
12378 gint attributes_mask;
12380 g_return_if_fail (widget != NULL);
12381 g_return_if_fail (GTK_IS_DIAL (widget));
12383 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
12384 dial = GTK_DIAL (widget);
12386 attributes.x = widget->allocation.x;
12387 attributes.y = widget->allocation.y;
12388 attributes.width = widget->allocation.width;
12389 attributes.height = widget->allocation.height;
12390 attributes.wclass = GDK_INPUT_OUTPUT;
12391 attributes.window_type = GDK_WINDOW_CHILD;
12392 attributes.event_mask = gtk_widget_get_events (widget) |
12393 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
12394 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
12395 GDK_POINTER_MOTION_HINT_MASK;
12396 attributes.visual = gtk_widget_get_visual (widget);
12397 attributes.colormap = gtk_widget_get_colormap (widget);
12399 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
12400 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
12402 widget->style = gtk_style_attach (widget->style, widget->window);
12404 gdk_window_set_user_data (widget->window, widget);
12406 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
12412 <!-- ----------------------------------------------------------------- -->
12414 <title>Size negotiation</title>
12416 <para>Before the first time that the window containing a widget is
12417 displayed, and whenever the layout of the window changes, GTK asks
12418 each child widget for its desired size. This request is handled by the
12419 function <literal>gtk_dial_size_request()</literal>. Since our widget isn't a
12420 container widget, and has no real constraints on its size, we just
12421 return a reasonable default value.</para>
12423 <programlisting role="C">
12425 gtk_dial_size_request (GtkWidget *widget,
12426 GtkRequisition *requisition)
12428 requisition->width = DIAL_DEFAULT_SIZE;
12429 requisition->height = DIAL_DEFAULT_SIZE;
12433 <para>After all the widgets have requested an ideal size, the layout of the
12434 window is computed and each child widget is notified of its actual
12435 size. Usually, this will be at least as large as the requested size,
12436 but if for instance the user has resized the window, it may
12437 occasionally be smaller than the requested size. The size notification
12438 is handled by the function <literal>gtk_dial_size_allocate()</literal>. Notice that
12439 as well as computing the sizes of some component pieces for future
12440 use, this routine also does the grunt work of moving the widget's X
12441 window into the new position and size.</para>
12443 <programlisting role="C">
12445 gtk_dial_size_allocate (GtkWidget *widget,
12446 GtkAllocation *allocation)
12450 g_return_if_fail (widget != NULL);
12451 g_return_if_fail (GTK_IS_DIAL (widget));
12452 g_return_if_fail (allocation != NULL);
12454 widget->allocation = *allocation;
12455 if (GTK_WIDGET_REALIZED (widget))
12457 dial = GTK_DIAL (widget);
12459 gdk_window_move_resize (widget->window,
12460 allocation->x, allocation->y,
12461 allocation->width, allocation->height);
12463 dial->radius = MAX(allocation->width,allocation->height) * 0.45;
12464 dial->pointer_width = dial->radius / 5;
12471 <!-- ----------------------------------------------------------------- -->
12473 <title><literal>gtk_dial_expose()</literal></title>
12475 <para>As mentioned above, all the drawing of this widget is done in the
12476 handler for expose events. There's not much to remark on here except
12477 the use of the function <literal>gtk_draw_polygon</literal> to draw the pointer with
12478 three dimensional shading according to the colors stored in the
12479 widget's style.</para>
12481 <programlisting role="C">
12483 gtk_dial_expose (GtkWidget *widget,
12484 GdkEventExpose *event)
12487 GdkPoint points[3];
12494 g_return_val_if_fail (widget != NULL, FALSE);
12495 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
12496 g_return_val_if_fail (event != NULL, FALSE);
12498 if (event->count > 0)
12501 dial = GTK_DIAL (widget);
12503 gdk_window_clear_area (widget->window,
12505 widget->allocation.width,
12506 widget->allocation.height);
12508 xc = widget->allocation.width/2;
12509 yc = widget->allocation.height/2;
12513 for (i=0; i<25; i++)
12515 theta = (i*M_PI/18. - M_PI/6.);
12519 tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
12521 gdk_draw_line (widget->window,
12522 widget->style->fg_gc[widget->state],
12523 xc + c*(dial->radius - tick_length),
12524 yc - s*(dial->radius - tick_length),
12525 xc + c*dial->radius,
12526 yc - s*dial->radius);
12531 s = sin(dial->angle);
12532 c = cos(dial->angle);
12535 points[0].x = xc + s*dial->pointer_width/2;
12536 points[0].y = yc + c*dial->pointer_width/2;
12537 points[1].x = xc + c*dial->radius;
12538 points[1].y = yc - s*dial->radius;
12539 points[2].x = xc - s*dial->pointer_width/2;
12540 points[2].y = yc - c*dial->pointer_width/2;
12542 gtk_draw_polygon (widget->style,
12555 <!-- ----------------------------------------------------------------- -->
12557 <title>Event handling</title>
12559 <para>The rest of the widget's code handles various types of events, and
12560 isn't too different from what would be found in many GTK
12561 applications. Two types of events can occur - either the user can
12562 click on the widget with the mouse and drag to move the pointer, or
12563 the value of the Adjustment object can change due to some external
12564 circumstance.</para>
12566 <para>When the user clicks on the widget, we check to see if the click was
12567 appropriately near the pointer, and if so, store the button that the
12568 user clicked with in the <literal>button</literal> field of the widget
12569 structure, and grab all mouse events with a call to
12570 <literal>gtk_grab_add()</literal>. Subsequent motion of the mouse causes the
12571 value of the control to be recomputed (by the function
12572 <literal>gtk_dial_update_mouse</literal>). Depending on the policy that has been
12573 set, "value_changed" events are either generated instantly
12574 (<literal>GTK_UPDATE_CONTINUOUS</literal>), after a delay in a timer added with
12575 <literal>gtk_timeout_add()</literal> (<literal>GTK_UPDATE_DELAYED</literal>), or only when the
12576 button is released (<literal>GTK_UPDATE_DISCONTINUOUS</literal>).</para>
12578 <programlisting role="C">
12580 gtk_dial_button_press (GtkWidget *widget,
12581 GdkEventButton *event)
12587 double d_perpendicular;
12589 g_return_val_if_fail (widget != NULL, FALSE);
12590 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
12591 g_return_val_if_fail (event != NULL, FALSE);
12593 dial = GTK_DIAL (widget);
12595 /* Determine if button press was within pointer region - we
12596 do this by computing the parallel and perpendicular distance of
12597 the point where the mouse was pressed from the line passing through
12600 dx = event->x - widget->allocation.width / 2;
12601 dy = widget->allocation.height / 2 - event->y;
12603 s = sin(dial->angle);
12604 c = cos(dial->angle);
12606 d_parallel = s*dy + c*dx;
12607 d_perpendicular = fabs(s*dx - c*dy);
12609 if (!dial->button &&
12610 (d_perpendicular < dial->pointer_width/2) &&
12611 (d_parallel > - dial->pointer_width))
12613 gtk_grab_add (widget);
12615 dial->button = event->button;
12617 gtk_dial_update_mouse (dial, event->x, event->y);
12624 gtk_dial_button_release (GtkWidget *widget,
12625 GdkEventButton *event)
12629 g_return_val_if_fail (widget != NULL, FALSE);
12630 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
12631 g_return_val_if_fail (event != NULL, FALSE);
12633 dial = GTK_DIAL (widget);
12635 if (dial->button == event->button)
12637 gtk_grab_remove (widget);
12641 if (dial->policy == GTK_UPDATE_DELAYED)
12642 gtk_timeout_remove (dial->timer);
12644 if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
12645 (dial->old_value != dial->adjustment->value))
12646 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
12653 gtk_dial_motion_notify (GtkWidget *widget,
12654 GdkEventMotion *event)
12657 GdkModifierType mods;
12660 g_return_val_if_fail (widget != NULL, FALSE);
12661 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
12662 g_return_val_if_fail (event != NULL, FALSE);
12664 dial = GTK_DIAL (widget);
12666 if (dial->button != 0)
12671 if (event->is_hint || (event->window != widget->window))
12672 gdk_window_get_pointer (widget->window, &x, &y, &mods);
12674 switch (dial->button)
12677 mask = GDK_BUTTON1_MASK;
12680 mask = GDK_BUTTON2_MASK;
12683 mask = GDK_BUTTON3_MASK;
12691 gtk_dial_update_mouse (dial, x,y);
12698 gtk_dial_timer (GtkDial *dial)
12700 g_return_val_if_fail (dial != NULL, FALSE);
12701 g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
12703 if (dial->policy == GTK_UPDATE_DELAYED)
12704 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
12710 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
12715 g_return_if_fail (dial != NULL);
12716 g_return_if_fail (GTK_IS_DIAL (dial));
12718 xc = GTK_WIDGET(dial)->allocation.width / 2;
12719 yc = GTK_WIDGET(dial)->allocation.height / 2;
12721 old_value = dial->adjustment->value;
12722 dial->angle = atan2(yc-y, x-xc);
12724 if (dial->angle < -M_PI/2.)
12725 dial->angle += 2*M_PI;
12727 if (dial->angle < -M_PI/6)
12728 dial->angle = -M_PI/6;
12730 if (dial->angle > 7.*M_PI/6.)
12731 dial->angle = 7.*M_PI/6.;
12733 dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
12734 (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
12736 if (dial->adjustment->value != old_value)
12738 if (dial->policy == GTK_UPDATE_CONTINUOUS)
12740 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
12744 gtk_widget_draw (GTK_WIDGET(dial), NULL);
12746 if (dial->policy == GTK_UPDATE_DELAYED)
12749 gtk_timeout_remove (dial->timer);
12751 dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
12752 (GtkFunction) gtk_dial_timer,
12760 <para>Changes to the Adjustment by external means are communicated to our
12761 widget by the "changed" and "value_changed" signals. The handlers
12762 for these functions call <literal>gtk_dial_update()</literal> to validate the
12763 arguments, compute the new pointer angle, and redraw the widget (by
12764 calling <literal>gtk_widget_draw()</literal>).</para>
12766 <programlisting role="C">
12768 gtk_dial_update (GtkDial *dial)
12772 g_return_if_fail (dial != NULL);
12773 g_return_if_fail (GTK_IS_DIAL (dial));
12775 new_value = dial->adjustment->value;
12777 if (new_value < dial->adjustment->lower)
12778 new_value = dial->adjustment->lower;
12780 if (new_value > dial->adjustment->upper)
12781 new_value = dial->adjustment->upper;
12783 if (new_value != dial->adjustment->value)
12785 dial->adjustment->value = new_value;
12786 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
12789 dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
12790 (dial->adjustment->upper - dial->adjustment->lower);
12792 gtk_widget_draw (GTK_WIDGET(dial), NULL);
12796 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
12801 g_return_if_fail (adjustment != NULL);
12802 g_return_if_fail (data != NULL);
12804 dial = GTK_DIAL (data);
12806 if ((dial->old_value != adjustment->value) ||
12807 (dial->old_lower != adjustment->lower) ||
12808 (dial->old_upper != adjustment->upper))
12810 gtk_dial_update (dial);
12812 dial->old_value = adjustment->value;
12813 dial->old_lower = adjustment->lower;
12814 dial->old_upper = adjustment->upper;
12819 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
12824 g_return_if_fail (adjustment != NULL);
12825 g_return_if_fail (data != NULL);
12827 dial = GTK_DIAL (data);
12829 if (dial->old_value != adjustment->value)
12831 gtk_dial_update (dial);
12833 dial->old_value = adjustment->value;
12840 <!-- ----------------------------------------------------------------- -->
12842 <title>Possible Enhancements</title>
12844 <para>The Dial widget as we've described it so far runs about 670 lines of
12845 code. Although that might sound like a fair bit, we've really
12846 accomplished quite a bit with that much code, especially since much of
12847 that length is headers and boilerplate. However, there are quite a few
12848 more enhancements that could be made to this widget:</para>
12851 <listitem><simpara> If you try this widget out, you'll find that there is some
12852 flashing as the pointer is dragged around. This is because the entire
12853 widget is erased every time the pointer is moved before being
12854 redrawn. Often, the best way to handle this problem is to draw to an
12855 offscreen pixmap, then copy the final results onto the screen in one
12856 step. (The ProgressBar widget draws itself in this fashion.)</simpara>
12859 <listitem><simpara> The user should be able to use the up and down arrow keys to
12860 increase and decrease the value.</simpara>
12863 <listitem><simpara> It would be nice if the widget had buttons to increase and
12864 decrease the value in small or large steps. Although it would be
12865 possible to use embedded Button widgets for this, we would also like
12866 the buttons to auto-repeat when held down, as the arrows on a
12867 scrollbar do. Most of the code to implement this type of behavior can
12868 be found in the Range widget.</simpara>
12871 <listitem><simpara> The Dial widget could be made into a container widget with a
12872 single child widget positioned at the bottom between the buttons
12873 mentioned above. The user could then add their choice of a label or
12874 entry widget to display the current value of the dial.</simpara>
12881 <!-- ----------------------------------------------------------------- -->
12882 <sect1 id="sec-LearningMore">
12883 <title>Learning More</title>
12885 <para>Only a small part of the many details involved in creating widgets
12886 could be described above. If you want to write your own widgets, the
12887 best source of examples is the GTK source itself. Ask yourself some
12888 questions about the widget you want to write: IS it a Container
12889 widget? Does it have its own window? Is it a modification of an
12890 existing widget? Then find a similar widget, and start making changes.
12896 <!-- ***************************************************************** -->
12897 <chapter id="ch-Scribble">
12898 <title>Scribble, A Simple Example Drawing Program</title>
12900 <!-- ----------------------------------------------------------------- -->
12901 <sect1 id="sec-ScribbleOverview">
12902 <title>Overview</title>
12904 <para>In this section, we will build a simple drawing program. In the
12905 process, we will examine how to handle mouse events, how to draw in a
12906 window, and how to do drawing better by using a backing pixmap. After
12907 creating the simple drawing program, we will extend it by adding
12908 support for XInput devices, such as drawing tablets. GTK provides
12909 support routines which makes getting extended information, such as
12910 pressure and tilt, from such devices quite easy.</para>
12913 <inlinemediaobject>
12915 <imagedata fileref="scribble.png" format="png">
12917 </inlinemediaobject>
12922 <!-- ----------------------------------------------------------------- -->
12923 <sect1 id="sec-EventHandling">
12924 <title>Event Handling</title>
12926 <para>The GTK signals we have already discussed are for high-level actions,
12927 such as a menu item being selected. However, sometimes it is useful to
12928 learn about lower-level occurrences, such as the mouse being moved, or
12929 a key being pressed. There are also GTK signals corresponding to these
12930 low-level <emphasis>events</emphasis>. The handlers for these signals have an
12931 extra parameter which is a pointer to a structure containing
12932 information about the event. For instance, motion event handlers are
12933 passed a pointer to a GdkEventMotion structure which looks (in part)
12936 <programlisting role="C">
12937 struct _GdkEventMotion
12950 <para><literal>type</literal> will be set to the event type, in this case
12951 <literal>GDK_MOTION_NOTIFY</literal>, window is the window in which the event
12952 occurred. <literal>x</literal> and <literal>y</literal> give the coordinates of the event.
12953 <literal>state</literal> specifies the modifier state when the event
12954 occurred (that is, it specifies which modifier keys and mouse buttons
12955 were pressed). It is the bitwise OR of some of the following:</para>
12957 <programlisting role="C">
12973 <para>As for other signals, to determine what happens when an event occurs
12974 we call <literal>gtk_signal_connect()</literal>. But we also need let GTK
12975 know which events we want to be notified about. To do this, we call
12976 the function:</para>
12978 <programlisting role="C">
12979 void gtk_widget_set_events (GtkWidget *widget,
12983 <para>The second field specifies the events we are interested in. It
12984 is the bitwise OR of constants that specify different types
12985 of events. For future reference the event types are:</para>
12987 <programlisting role="C">
12989 GDK_POINTER_MOTION_MASK
12990 GDK_POINTER_MOTION_HINT_MASK
12991 GDK_BUTTON_MOTION_MASK
12992 GDK_BUTTON1_MOTION_MASK
12993 GDK_BUTTON2_MOTION_MASK
12994 GDK_BUTTON3_MOTION_MASK
12995 GDK_BUTTON_PRESS_MASK
12996 GDK_BUTTON_RELEASE_MASK
12998 GDK_KEY_RELEASE_MASK
12999 GDK_ENTER_NOTIFY_MASK
13000 GDK_LEAVE_NOTIFY_MASK
13001 GDK_FOCUS_CHANGE_MASK
13003 GDK_PROPERTY_CHANGE_MASK
13004 GDK_PROXIMITY_IN_MASK
13005 GDK_PROXIMITY_OUT_MASK
13008 <para>There are a few subtle points that have to be observed when calling
13009 <literal>gtk_widget_set_events()</literal>. First, it must be called before the X window
13010 for a GTK widget is created. In practical terms, this means you
13011 should call it immediately after creating the widget. Second, the
13012 widget must have an associated X window. For efficiency, many widget
13013 types do not have their own window, but draw in their parent's window.
13014 These widgets are:</para>
13016 <programlisting role="C">
13036 <para>To capture events for these widgets, you need to use an EventBox
13037 widget. See the section on the <link linkend="sec-EventBox">EventBox</link> widget for details.</para>
13039 <para>For our drawing program, we want to know when the mouse button is
13040 pressed and when the mouse is moved, so we specify
13041 <literal>GDK_POINTER_MOTION_MASK</literal> and <literal>GDK_BUTTON_PRESS_MASK</literal>. We also
13042 want to know when we need to redraw our window, so we specify
13043 <literal>GDK_EXPOSURE_MASK</literal>. Although we want to be notified via a
13044 Configure event when our window size changes, we don't have to specify
13045 the corresponding <literal>GDK_STRUCTURE_MASK</literal> flag, because it is
13046 automatically specified for all windows.</para>
13048 <para>It turns out, however, that there is a problem with just specifying
13049 <literal>GDK_POINTER_MOTION_MASK</literal>. This will cause the server to add a new
13050 motion event to the event queue every time the user moves the mouse.
13051 Imagine that it takes us 0.1 seconds to handle a motion event, but the
13052 X server queues a new motion event every 0.05 seconds. We will soon
13053 get way behind the users drawing. If the user draws for 5 seconds,
13054 it will take us another 5 seconds to catch up after they release
13055 the mouse button! What we would like is to only get one motion
13056 event for each event we process. The way to do this is to
13057 specify <literal>GDK_POINTER_MOTION_HINT_MASK</literal>. </para>
13059 <para>When we specify <literal>GDK_POINTER_MOTION_HINT_MASK</literal>, the server sends
13060 us a motion event the first time the pointer moves after entering
13061 our window, or after a button press or release event. Subsequent
13062 motion events will be suppressed until we explicitly ask for
13063 the position of the pointer using the function:</para>
13065 <programlisting role="C">
13066 GdkWindow* gdk_window_get_pointer (GdkWindow *window,
13069 GdkModifierType *mask);
13072 <para>(There is another function, <literal>gtk_widget_get_pointer()</literal> which
13073 has a simpler interface, but turns out not to be very useful, since
13074 it only retrieves the position of the mouse, not whether the buttons
13075 are pressed.)</para>
13077 <para>The code to set the events for our window then looks like:</para>
13079 <programlisting role="C">
13080 gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
13081 (GtkSignalFunc) expose_event, NULL);
13082 gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
13083 (GtkSignalFunc) configure_event, NULL);
13084 gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
13085 (GtkSignalFunc) motion_notify_event, NULL);
13086 gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
13087 (GtkSignalFunc) button_press_event, NULL);
13089 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
13090 | GDK_LEAVE_NOTIFY_MASK
13091 | GDK_BUTTON_PRESS_MASK
13092 | GDK_POINTER_MOTION_MASK
13093 | GDK_POINTER_MOTION_HINT_MASK);
13096 <para>We'll save the "expose_event" and "configure_event" handlers for
13097 later. The "motion_notify_event" and "button_press_event" handlers
13098 are pretty simple:</para>
13100 <programlisting role="C">
13102 button_press_event (GtkWidget *widget, GdkEventButton *event)
13104 if (event->button == 1 && pixmap != NULL)
13105 draw_brush (widget, event->x, event->y);
13111 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
13114 GdkModifierType state;
13116 if (event->is_hint)
13117 gdk_window_get_pointer (event->window, &x, &y, &state);
13122 state = event->state;
13125 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
13126 draw_brush (widget, x, y);
13134 <!-- ----------------------------------------------------------------- -->
13135 <sect1 id="sec-TheDrawingAreaWidget">
13136 <title>The DrawingArea Widget, And Drawing</title>
13138 <para>We now turn to the process of drawing on the screen. The
13139 widget we use for this is the DrawingArea widget. A drawing area
13140 widget is essentially an X window and nothing more. It is a blank
13141 canvas in which we can draw whatever we like. A drawing area
13142 is created using the call:</para>
13144 <programlisting role="C">
13145 GtkWidget* gtk_drawing_area_new (void);
13148 <para>A default size for the widget can be specified by calling:</para>
13150 <programlisting role="C">
13151 void gtk_drawing_area_size (GtkDrawingArea *darea,
13156 <para>This default size can be overridden, as is true for all widgets,
13157 by calling <literal>gtk_widget_set_size_request()</literal>, and that, in turn, can
13158 be overridden if the user manually resizes the the window containing
13159 the drawing area.</para>
13161 <para>It should be noted that when we create a DrawingArea widget, we are
13162 <emphasis>completely</emphasis> responsible for drawing the contents. If our
13163 window is obscured then uncovered, we get an exposure event and must
13164 redraw what was previously hidden.</para>
13166 <para>Having to remember everything that was drawn on the screen so we
13167 can properly redraw it can, to say the least, be a nuisance. In
13168 addition, it can be visually distracting if portions of the
13169 window are cleared, then redrawn step by step. The solution to
13170 this problem is to use an offscreen <emphasis>backing pixmap</emphasis>.
13171 Instead of drawing directly to the screen, we draw to an image
13172 stored in server memory but not displayed, then when the image
13173 changes or new portions of the image are displayed, we copy the
13174 relevant portions onto the screen.</para>
13176 <para>To create an offscreen pixmap, we call the function:</para>
13178 <programlisting role="C">
13179 GdkPixmap* gdk_pixmap_new (GdkWindow *window,
13185 <para>The <literal>window</literal> parameter specifies a GDK window that this pixmap
13186 takes some of its properties from. <literal>width</literal> and <literal>height</literal>
13187 specify the size of the pixmap. <literal>depth</literal> specifies the <emphasis>color
13188 depth</emphasis>, that is the number of bits per pixel, for the new window.
13189 If the depth is specified as <literal>-1</literal>, it will match the depth
13190 of <literal>window</literal>.</para>
13192 <para>We create the pixmap in our "configure_event" handler. This event
13193 is generated whenever the window changes size, including when it
13194 is originally created.</para>
13196 <programlisting role="C">
13197 /* Backing pixmap for drawing area */
13198 static GdkPixmap *pixmap = NULL;
13200 /* Create a new backing pixmap of the appropriate size */
13202 configure_event (GtkWidget *widget, GdkEventConfigure *event)
13205 gdk_pixmap_unref(pixmap);
13207 pixmap = gdk_pixmap_new(widget->window,
13208 widget->allocation.width,
13209 widget->allocation.height,
13211 gdk_draw_rectangle (pixmap,
13212 widget->style->white_gc,
13215 widget->allocation.width,
13216 widget->allocation.height);
13222 <para>The call to <literal>gdk_draw_rectangle()</literal> clears the pixmap
13223 initially to white. We'll say more about that in a moment.</para>
13225 <para>Our exposure event handler then simply copies the relevant portion
13226 of the pixmap onto the screen (we determine the area we need
13227 to redraw by using the event->area field of the exposure event):</para>
13229 <programlisting role="C">
13230 /* Redraw the screen from the backing pixmap */
13232 expose_event (GtkWidget *widget, GdkEventExpose *event)
13234 gdk_draw_pixmap(widget->window,
13235 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
13237 event->area.x, event->area.y,
13238 event->area.x, event->area.y,
13239 event->area.width, event->area.height);
13245 <para>We've now seen how to keep the screen up to date with our pixmap, but
13246 how do we actually draw interesting stuff on our pixmap? There are a
13247 large number of calls in GTK's GDK library for drawing on
13248 <emphasis>drawables</emphasis>. A drawable is simply something that can be drawn
13249 upon. It can be a window, a pixmap, or a bitmap (a black and white
13250 image). We've already seen two such calls above,
13251 <literal>gdk_draw_rectangle()</literal> and <literal>gdk_draw_pixmap()</literal>. The
13252 complete list is:</para>
13254 <programlisting role="C">
13256 gdk_draw_rectangle ()
13258 gdk_draw_polygon ()
13265 gdk_draw_segments ()
13268 <para>See the reference documentation or the header file
13269 <literal><gdk/gdk.h></literal> for further details on these functions.
13270 These functions all share the same first two arguments. The first
13271 argument is the drawable to draw upon, the second argument is a
13272 <emphasis>graphics context</emphasis> (GC). </para>
13274 <para>A graphics context encapsulates information about things such as
13275 foreground and background color and line width. GDK has a full set of
13276 functions for creating and modifying graphics contexts, but to keep
13277 things simple we'll just use predefined graphics contexts. Each widget
13278 has an associated style. (Which can be modified in a gtkrc file, see
13279 the section GTK's rc file.) This, among other things, stores a number
13280 of graphics contexts. Some examples of accessing these graphics
13281 contexts are:</para>
13283 <programlisting role="C">
13284 widget->style->white_gc
13285 widget->style->black_gc
13286 widget->style->fg_gc[GTK_STATE_NORMAL]
13287 widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
13290 <para>The fields <literal>fg_gc</literal>, <literal>bg_gc</literal>, <literal>dark_gc</literal>, and
13291 <literal>light_gc</literal> are indexed by a parameter of type
13292 <literal>GtkStateType</literal> which can take on the values:</para>
13294 <programlisting role="C">
13297 GTK_STATE_PRELIGHT,
13298 GTK_STATE_SELECTED,
13299 GTK_STATE_INSENSITIVE
13302 <para>For instance, for <literal>GTK_STATE_SELECTED</literal> the default foreground
13303 color is white and the default background color, dark blue.</para>
13305 <para>Our function <literal>draw_brush()</literal>, which does the actual drawing
13306 on the screen, is then:</para>
13308 <programlisting role="C">
13309 /* Draw a rectangle on the screen */
13311 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
13313 GdkRectangle update_rect;
13315 update_rect.x = x - 5;
13316 update_rect.y = y - 5;
13317 update_rect.width = 10;
13318 update_rect.height = 10;
13319 gdk_draw_rectangle (pixmap,
13320 widget->style->black_gc,
13322 update_rect.x, update_rect.y,
13323 update_rect.width, update_rect.height);
13324 gtk_widget_draw (widget, &update_rect);
13328 <para>After we draw the rectangle representing the brush onto the pixmap,
13329 we call the function:</para>
13331 <programlisting role="C">
13332 void gtk_widget_draw (GtkWidget *widget,
13333 GdkRectangle *area);
13336 <para>which notifies X that the area given by the <literal>area</literal> parameter
13337 needs to be updated. X will eventually generate an expose event
13338 (possibly combining the areas passed in several calls to
13339 <literal>gtk_widget_draw()</literal>) which will cause our expose event handler
13340 to copy the relevant portions to the screen.</para>
13342 <para>We have now covered the entire drawing program except for a few
13343 mundane details like creating the main window.</para>
13347 <!-- ----------------------------------------------------------------- -->
13348 <sect1 id="sec-AddingXInputSupport">
13349 <title>Adding XInput support</title>
13351 <para>It is now possible to buy quite inexpensive input devices such
13352 as drawing tablets, which allow drawing with a much greater
13353 ease of artistic expression than does a mouse. The simplest way
13354 to use such devices is simply as a replacement for the mouse,
13355 but that misses out many of the advantages of these devices,
13359 <listitem><simpara> Pressure sensitivity</simpara>
13361 <listitem><simpara> Tilt reporting</simpara>
13363 <listitem><simpara> Sub-pixel positioning</simpara>
13365 <listitem><simpara> Multiple inputs (for example, a stylus with a point and eraser)</simpara>
13369 <para>For information about the XInput extension, see the <ulink
13370 url="http://www.gtk.org/~otaylor/xinput/howto/index.html">XInput HOWTO</ulink>.</para>
13372 <para>If we examine the full definition of, for example, the GdkEventMotion
13373 structure, we see that it has fields to support extended device
13374 information.</para>
13376 <programlisting role="C">
13377 struct _GdkEventMotion
13389 GdkInputSource source;
13394 <para><literal>pressure</literal> gives the pressure as a floating point number between
13395 0 and 1. <literal>xtilt</literal> and <literal>ytilt</literal> can take on values between
13396 -1 and 1, corresponding to the degree of tilt in each direction.
13397 <literal>source</literal> and <literal>deviceid</literal> specify the device for which the
13398 event occurred in two different ways. <literal>source</literal> gives some simple
13399 information about the type of device. It can take the enumeration
13402 <programlisting role="C">
13409 <para><literal>deviceid</literal> specifies a unique numeric ID for the device. This can
13410 be used to find out further information about the device using the
13411 <literal>gdk_input_list_devices()</literal> call (see below). The special value
13412 <literal>GDK_CORE_POINTER</literal> is used for the core pointer device. (Usually
13415 <!-- ----------------------------------------------------------------- -->
13417 <title>Enabling extended device information</title>
13419 <para>To let GTK know about our interest in the extended device information,
13420 we merely have to add a single line to our program:</para>
13422 <programlisting role="C">
13423 gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
13426 <para>By giving the value <literal>GDK_EXTENSION_EVENTS_CURSOR</literal> we say that
13427 we are interested in extension events, but only if we don't have
13428 to draw our own cursor. See the section <link
13429 linkend="sec-FurtherSophistications"> Further Sophistications </link> below
13430 for more information about drawing the cursor. We could also
13431 give the values <literal>GDK_EXTENSION_EVENTS_ALL</literal> if we were willing
13432 to draw our own cursor, or <literal>GDK_EXTENSION_EVENTS_NONE</literal> to revert
13433 back to the default condition.</para>
13435 <para>This is not completely the end of the story however. By default,
13436 no extension devices are enabled. We need a mechanism to allow
13437 users to enable and configure their extension devices. GTK provides
13438 the InputDialog widget to automate this process. The following
13439 procedure manages an InputDialog widget. It creates the dialog if
13440 it isn't present, and raises it to the top otherwise.</para>
13442 <programlisting role="C">
13444 input_dialog_destroy (GtkWidget *w, gpointer data)
13446 *((GtkWidget **)data) = NULL;
13450 create_input_dialog ()
13452 static GtkWidget *inputd = NULL;
13456 inputd = gtk_input_dialog_new();
13458 gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
13459 (GtkSignalFunc)input_dialog_destroy, &inputd);
13460 gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
13462 (GtkSignalFunc)gtk_widget_hide,
13463 GTK_OBJECT(inputd));
13464 gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
13466 gtk_widget_show (inputd);
13470 if (!GTK_WIDGET_MAPPED(inputd))
13471 gtk_widget_show(inputd);
13473 gdk_window_raise(inputd->window);
13478 <para>(You might want to take note of the way we handle this dialog. By
13479 connecting to the "destroy" signal, we make sure that we don't keep a
13480 pointer to dialog around after it is destroyed - that could lead to a
13483 <para>The InputDialog has two buttons "Close" and "Save", which by default
13484 have no actions assigned to them. In the above function we make
13485 "Close" hide the dialog, hide the "Save" button, since we don't
13486 implement saving of XInput options in this program.</para>
13490 <!-- ----------------------------------------------------------------- -->
13492 <title>Using extended device information</title>
13494 <para>Once we've enabled the device, we can just use the extended
13495 device information in the extra fields of the event structures.
13496 In fact, it is always safe to use this information since these
13497 fields will have reasonable default values even when extended
13498 events are not enabled.</para>
13500 <para>Once change we do have to make is to call
13501 <literal>gdk_input_window_get_pointer()</literal> instead of
13502 <literal>gdk_window_get_pointer</literal>. This is necessary because
13503 <literal>gdk_window_get_pointer</literal> doesn't return the extended device
13504 information.</para>
13506 <programlisting role="C">
13507 void gdk_input_window_get_pointer( GdkWindow *window,
13514 GdkModifierType *mask);
13517 <para>When calling this function, we need to specify the device ID as
13518 well as the window. Usually, we'll get the device ID from the
13519 <literal>deviceid</literal> field of an event structure. Again, this function
13520 will return reasonable values when extension events are not
13521 enabled. (In this case, <literal>event->deviceid</literal> will have the value
13522 <literal>GDK_CORE_POINTER</literal>).</para>
13524 <para>So the basic structure of our button-press and motion event handlers
13525 doesn't change much - we just need to add code to deal with the
13526 extended information.</para>
13528 <programlisting role="C">
13530 button_press_event (GtkWidget *widget, GdkEventButton *event)
13532 print_button_press (event->deviceid);
13534 if (event->button == 1 && pixmap != NULL)
13535 draw_brush (widget, event->source, event->x, event->y, event->pressure);
13541 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
13545 GdkModifierType state;
13547 if (event->is_hint)
13548 gdk_input_window_get_pointer (event->window, event->deviceid,
13549 &x, &y, &pressure, NULL, NULL, &state);
13554 pressure = event->pressure;
13555 state = event->state;
13558 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
13559 draw_brush (widget, event->source, x, y, pressure);
13565 <para>We also need to do something with the new information. Our new
13566 <literal>draw_brush()</literal> function draws with a different color for
13567 each <literal>event->source</literal> and changes the brush size depending
13568 on the pressure.</para>
13570 <programlisting role="C">
13571 /* Draw a rectangle on the screen, size depending on pressure,
13572 and color on the type of device */
13574 draw_brush (GtkWidget *widget, GdkInputSource source,
13575 gdouble x, gdouble y, gdouble pressure)
13578 GdkRectangle update_rect;
13582 case GDK_SOURCE_MOUSE:
13583 gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
13585 case GDK_SOURCE_PEN:
13586 gc = widget->style->black_gc;
13588 case GDK_SOURCE_ERASER:
13589 gc = widget->style->white_gc;
13592 gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
13595 update_rect.x = x - 10 * pressure;
13596 update_rect.y = y - 10 * pressure;
13597 update_rect.width = 20 * pressure;
13598 update_rect.height = 20 * pressure;
13599 gdk_draw_rectangle (pixmap, gc, TRUE,
13600 update_rect.x, update_rect.y,
13601 update_rect.width, update_rect.height);
13602 gtk_widget_draw (widget, &update_rect);
13608 <!-- ----------------------------------------------------------------- -->
13610 <title>Finding out more about a device</title>
13612 <para>As an example of how to find out more about a device, our program
13613 will print the name of the device that generates each button
13614 press. To find out the name of a device, we call the function:</para>
13616 <programlisting role="C">
13617 GList *gdk_input_list_devices (void);
13620 <para>which returns a GList (a linked list type from the GLib library)
13621 of GdkDeviceInfo structures. The GdkDeviceInfo structure is defined
13624 <programlisting role="C">
13625 struct _GdkDeviceInfo
13629 GdkInputSource source;
13635 GdkDeviceKey *keys;
13639 <para>Most of these fields are configuration information that you can ignore
13640 unless you are implementing XInput configuration saving. The fieldwe
13641 are interested in here is <literal>name</literal> which is simply the name that X
13642 assigns to the device. The other field that isn't configuration
13643 information is <literal>has_cursor</literal>. If <literal>has_cursor</literal> is false, then we
13644 we need to draw our own cursor. But since we've specified
13645 <literal>GDK_EXTENSION_EVENTS_CURSOR</literal>, we don't have to worry about this.</para>
13647 <para>Our <literal>print_button_press()</literal> function simply iterates through
13648 the returned list until it finds a match, then prints out
13649 the name of the device.</para>
13651 <programlisting role="C">
13653 print_button_press (guint32 deviceid)
13657 /* gdk_input_list_devices returns an internal list, so we shouldn't
13658 free it afterwards */
13659 tmp_list = gdk_input_list_devices();
13663 GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
13665 if (info->deviceid == deviceid)
13667 printf("Button press on device '%s'\n", info->name);
13671 tmp_list = tmp_list->next;
13676 <para>That completes the changes to "XInputize" our program.</para>
13680 <!-- ----------------------------------------------------------------- -->
13681 <sect2 id="sec-FurtherSophistications">
13682 <title>Further sophistications</title>
13684 <para>Although our program now supports XInput quite well, it lacks some
13685 features we would want in a full-featured application. First, the user
13686 probably doesn't want to have to configure their device each time they
13687 run the program, so we should allow them to save the device
13688 configuration. This is done by iterating through the return of
13689 <literal>gdk_input_list_devices()</literal> and writing out the configuration to a
13692 <para>To restore the state next time the program is run, GDK provides
13693 functions to change device configuration:</para>
13695 <programlisting role="C">
13696 gdk_input_set_extension_events()
13697 gdk_input_set_source()
13698 gdk_input_set_mode()
13699 gdk_input_set_axes()
13700 gdk_input_set_key()
13703 <para>(The list returned from <literal>gdk_input_list_devices()</literal> should not be
13704 modified directly.) An example of doing this can be found in the
13705 drawing program gsumi. (Available from <ulink
13706 url="http://www.msc.cornell.edu/~otaylor/gsumi/">http://www.msc.cornell.edu/~otaylor/gsumi/</ulink>) Eventually, it
13707 would be nice to have a standard way of doing this for all
13708 applications. This probably belongs at a slightly higher level than
13709 GTK, perhaps in the GNOME library.</para>
13711 <para>Another major omission that we have mentioned above is the lack of
13712 cursor drawing. Platforms other than XFree86 currently do not allow
13713 simultaneously using a device as both the core pointer and directly by
13714 an application. See the <ulink
13715 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html">XInput-HOWTO</ulink> for more information about this. This means that
13716 applications that want to support the widest audience need to draw
13717 their own cursor.</para>
13719 <para>An application that draws its own cursor needs to do two things:
13720 determine if the current device needs a cursor drawn or not, and
13721 determine if the current device is in proximity. (If the current
13722 device is a drawing tablet, it's a nice touch to make the cursor
13723 disappear when the stylus is lifted from the tablet. When the
13724 device is touching the stylus, that is called "in proximity.")
13725 The first is done by searching the device list, as we did
13726 to find out the device name. The second is achieved by selecting
13727 "proximity_out" events. An example of drawing one's own cursor is
13728 found in the "testinput" program found in the GTK distribution.</para>
13735 <!-- ***************************************************************** -->
13736 <chapter id="ch-Tips">
13737 <title>Tips For Writing GTK Applications</title>
13739 <para>This section is simply a gathering of wisdom, general style guidelines
13740 and hints to creating good GTK applications. Currently this section
13741 is very short, but I hope it will get longer in future editions of
13742 this tutorial.</para>
13744 <para>Use GNU autoconf and automake! They are your friends :) Automake
13745 examines C files, determines how they depend on each other, and
13746 generates a Makefile so the files can be compiled in the correct
13747 order. Autoconf permits automatic configuration of software
13748 installation, handling a large number of system quirks to increase
13749 portability. I am planning to make a quick intro on them here.</para>
13751 <para>When writing C code, use only C comments (beginning with "/*" and
13752 ending with "*/"), and don't use C++-style comments ("//"). Although
13753 many C compilers understand C++ comments, others don't, and the ANSI C
13754 standard does not require that C++-style comments be processed as
13759 <!-- ***************************************************************** -->
13760 <chapter id="ch-Contributing">
13761 <title>Contributing</title>
13763 <para>This document, like so much other great software out there, was
13764 created for free by volunteers. If you are at all knowledgeable about
13765 any aspect of GTK that does not already have documentation, please
13766 consider contributing to this document.</para>
13768 <para>If you do decide to contribute, please mail your text to Tony Gale,
13769 <literal><ulink url="mailto:gale@gtk.org">gale@gtk.org</ulink></literal>. Also, be aware that the entirety of this
13770 document is free, and any addition by you provide must also be
13771 free. That is, people may use any portion of your examples in their
13772 programs, and copies of this document may be distributed at will, etc.</para>
13774 <para>Thank you.</para>
13778 <!-- ***************************************************************** -->
13779 <chapter id="ch-Credits">
13780 <title>Credits</title>
13782 <para>We would like to thank the following for their contributions to this text.</para>
13785 <listitem><simpara>Bawer Dagdeviren, <literal><ulink url="mailto:chamele0n@geocities.com">chamele0n@geocities.com</ulink></literal> for the menus tutorial.</simpara>
13788 <listitem><simpara>Raph Levien, <literal><ulink url="mailto:raph@acm.org">raph@acm.org</ulink></literal>
13789 for hello world ala GTK, widget packing, and general all around wisdom.
13790 He's also generously donated a home for this tutorial.</simpara>
13793 <listitem><simpara>Peter Mattis, <literal><ulink url="mailto:petm@xcf.berkeley.edu">petm@xcf.berkeley.edu</ulink></literal> for the simplest GTK program..
13794 and the ability to make it :)</simpara>
13797 <listitem><simpara>Werner Koch <literal><ulink url="mailto:werner.koch@guug.de">werner.koch@guug.de</ulink></literal> for converting the original plain text to
13798 SGML, and the widget class hierarchy.</simpara>
13801 <listitem><simpara>Mark Crichton <literal><ulink
13802 url="mailto:crichton@expert.cc.purdue.edu">crichton@expert.cc.purdue.edu</ulink></literal> for the menu factory code,
13803 and the table packing tutorial.</simpara>
13806 <listitem><simpara>Owen Taylor <literal><ulink url="mailto:owt1@cornell.edu">owt1@cornell.edu</ulink></literal> for the EventBox widget section (and the
13807 patch to the distro). He's also responsible for the selections code
13808 and tutorial, as well as the sections on writing your own GTK widgets,
13809 and the example application. Thanks a lot Owen for all you help!</simpara>
13812 <listitem><simpara>Mark VanderBoom <literal><ulink url="mailto:mvboom42@calvin.edu">mvboom42@calvin.edu</ulink></literal> for his wonderful work on the
13813 Notebook, Progress Bar, Dialogs, and File selection widgets. Thanks a
13814 lot Mark! You've been a great help.</simpara>
13817 <listitem><simpara>Tim Janik <literal><ulink url="mailto:timj@gtk.org">timj@gtk.org</ulink></literal> for his great job on the Lists
13818 Widget. His excellent work on automatically extracting the widget tree
13819 and signal information from GTK. Thanks Tim :)</simpara>
13822 <listitem><simpara>Rajat Datta <literal><ulink url="mailto:rajat@ix.netcom.com">rajat@ix.netcom.com</ulink>
13823 </literal> for the excellent job on the Pixmap
13824 tutorial.</simpara>
13827 <listitem><simpara>Michael K. Johnson <literal><ulink url="mailto:johnsonm@redhat.com">johnsonm@redhat.com</ulink></literal> for info and code for popup menus.</simpara>
13830 <listitem><simpara>David Huggins-Daines <literal><ulink
13831 url="mailto:bn711@freenet.carleton.ca">bn711@freenet.carleton.ca</ulink></literal> for the Range Widgets and Tree
13832 Widget sections.</simpara>
13835 <listitem><simpara>Stefan Mars <literal><ulink url="mailto:mars@lysator.liu.se">mars@lysator.liu.se</ulink></literal> for the CList section.</simpara>
13838 <listitem><simpara>David A. Wheeler <literal><ulink url="mailto:dwheeler@ida.org">dwheeler@ida.org</ulink></literal> for portions of the text on GLib
13839 and various tutorial fixups and improvements.
13840 The GLib text was in turn based on material developed by Damon Chaplin
13841 <literal><ulink url="mailto:DAChaplin@msn.com">DAChaplin@msn.com</ulink></literal></simpara>
13844 <listitem><simpara>David King for style checking the entire document.</simpara>
13848 <para>And to all of you who commented on and helped refine this document.</para>
13850 <para>Thanks.</para>
13854 <!-- ***************************************************************** -->
13855 <chapter id="ch-Copyright">
13856 <title>Tutorial Copyright and Permissions Notice</title>
13858 <para>The GTK Tutorial is Copyright (C) 1997 Ian Main. </para>
13860 <para>Copyright (C) 1998-1999 Tony Gale.</para>
13862 <para>Permission is granted to make and distribute verbatim copies of this
13863 manual provided the copyright notice and this permission notice are
13864 preserved on all copies.</para>
13866 <para>Permission is granted to copy and distribute modified versions of
13867 this document under the conditions for verbatim copying, provided that
13868 this copyright notice is included exactly as in the original,
13869 and that the entire resulting derived work is distributed under
13870 the terms of a permission notice identical to this one.</para>
13872 <para>Permission is granted to copy and distribute translations of this
13873 document into another language, under the above conditions for modified
13876 <para>If you are intending to incorporate this document into a published
13877 work, please contact the maintainer, and we will make an effort
13878 to ensure that you have the most up to date information available.</para>
13880 <para>There is no guarantee that this document lives up to its intended
13881 purpose. This is simply provided as a free resource. As such,
13882 the authors and maintainers of the information provided within can
13883 not make any guarantee that the information is even accurate.</para>
13887 <!-- ***************************************************************** -->
13888 <!-- ***************************************************************** -->
13890 <!-- ***************************************************************** -->
13891 <appendix id="app-GTKSignals">
13892 <title>GTK Signals</title>
13894 <para>As GTK is an object oriented widget set, it has a hierarchy of
13895 inheritance. This inheritance mechanism applies for
13896 signals. Therefore, you should refer to the widget hierarchy tree when
13897 using the signals listed in this section.</para>
13899 <!-- ----------------------------------------------------------------- -->
13900 <sect1 id="sec-GtkObject">
13901 <title>GtkObject</title>
13903 <programlisting role="C">
13904 void GtkObject::destroy (GtkObject *,
13910 <!-- ----------------------------------------------------------------- -->
13911 <sect1 id="sec-GtkWidget">
13912 <title>GtkWidget</title>
13914 <programlisting role="C">
13915 void GtkWidget::show (GtkWidget *,
13917 void GtkWidget::hide (GtkWidget *,
13919 void GtkWidget::map (GtkWidget *,
13921 void GtkWidget::unmap (GtkWidget *,
13923 void GtkWidget::realize (GtkWidget *,
13925 void GtkWidget::unrealize (GtkWidget *,
13927 void GtkWidget::draw (GtkWidget *,
13930 void GtkWidget::draw-focus (GtkWidget *,
13932 void GtkWidget::draw-default (GtkWidget *,
13934 void GtkWidget::size-request (GtkWidget *,
13937 void GtkWidget::size-allocate (GtkWidget *,
13940 void GtkWidget::state-changed (GtkWidget *,
13943 void GtkWidget::parent-set (GtkWidget *,
13946 void GtkWidget::style-set (GtkWidget *,
13949 void GtkWidget::add-accelerator (GtkWidget *,
13956 void GtkWidget::remove-accelerator (GtkWidget *,
13961 gboolean GtkWidget::event (GtkWidget *,
13964 gboolean GtkWidget::button-press-event (GtkWidget *,
13967 gboolean GtkWidget::button-release-event (GtkWidget *,
13970 gboolean GtkWidget::motion-notify-event (GtkWidget *,
13973 gboolean GtkWidget::delete-event (GtkWidget *,
13976 gboolean GtkWidget::destroy-event (GtkWidget *,
13979 gboolean GtkWidget::expose-event (GtkWidget *,
13982 gboolean GtkWidget::key-press-event (GtkWidget *,
13985 gboolean GtkWidget::key-release-event (GtkWidget *,
13988 gboolean GtkWidget::enter-notify-event (GtkWidget *,
13991 gboolean GtkWidget::leave-notify-event (GtkWidget *,
13994 gboolean GtkWidget::configure-event (GtkWidget *,
13997 gboolean GtkWidget::focus-in-event (GtkWidget *,
14000 gboolean GtkWidget::focus-out-event (GtkWidget *,
14003 gboolean GtkWidget::map-event (GtkWidget *,
14006 gboolean GtkWidget::unmap-event (GtkWidget *,
14009 gboolean GtkWidget::property-notify-event (GtkWidget *,
14012 gboolean GtkWidget::selection-clear-event (GtkWidget *,
14015 gboolean GtkWidget::selection-request-event (GtkWidget *,
14018 gboolean GtkWidget::selection-notify-event (GtkWidget *,
14021 void GtkWidget::selection-get (GtkWidget *,
14022 GtkSelectionData *,
14025 void GtkWidget::selection-received (GtkWidget *,
14026 GtkSelectionData *,
14029 gboolean GtkWidget::proximity-in-event (GtkWidget *,
14032 gboolean GtkWidget::proximity-out-event (GtkWidget *,
14035 void GtkWidget::drag-begin (GtkWidget *,
14038 void GtkWidget::drag-end (GtkWidget *,
14041 void GtkWidget::drag-data-delete (GtkWidget *,
14044 void GtkWidget::drag-leave (GtkWidget *,
14048 gboolean GtkWidget::drag-motion (GtkWidget *,
14054 gboolean GtkWidget::drag-drop (GtkWidget *,
14060 void GtkWidget::drag-data-get (GtkWidget *,
14062 GtkSelectionData *,
14066 void GtkWidget::drag-data-received (GtkWidget *,
14070 GtkSelectionData *,
14074 gboolean GtkWidget::client-event (GtkWidget *,
14077 gboolean GtkWidget::no-expose-event (GtkWidget *,
14080 gboolean GtkWidget::visibility-notify-event (GtkWidget *,
14083 void GtkWidget::debug-msg (GtkWidget *,
14090 <!-- ----------------------------------------------------------------- -->
14091 <sect1 id="sec-GtkData">
14092 <title>GtkData</title>
14094 <programlisting role="C">
14095 void GtkData::disconnect (GtkData *,
14101 <!-- ----------------------------------------------------------------- -->
14102 <sect1 id="sec-GtkContainer">
14103 <title>GtkContainer</title>
14105 <programlisting role="C">
14106 void GtkContainer::add (GtkContainer *,
14109 void GtkContainer::remove (GtkContainer *,
14112 void GtkContainer::check-resize (GtkContainer *,
14114 GtkDirectionType GtkContainer::focus (GtkContainer *,
14117 void GtkContainer::set-focus-child (GtkContainer *,
14124 <!-- ----------------------------------------------------------------- -->
14125 <sect1 id="sec-GtkCalendar">
14126 <title>GtkCalendar</title>
14128 <programlisting role="C">
14129 void GtkCalendar::month-changed (GtkCalendar *,
14131 void GtkCalendar::day-selected (GtkCalendar *,
14133 void GtkCalendar::day-selected-double-click (GtkCalendar *,
14135 void GtkCalendar::prev-month (GtkCalendar *,
14137 void GtkCalendar::next-month (GtkCalendar *,
14139 void GtkCalendar::prev-year (GtkCalendar *,
14141 void GtkCalendar::next-year (GtkCalendar *,
14147 <!-- ----------------------------------------------------------------- -->
14148 <sect1 id="sec-GtkEditable">
14149 <title>GtkEditable</title>
14151 <programlisting role="C">
14152 void GtkEditable::changed (GtkEditable *,
14154 void GtkEditable::insert-text (GtkEditable *,
14159 void GtkEditable::delete-text (GtkEditable *,
14163 void GtkEditable::activate (GtkEditable *,
14165 void GtkEditable::set-editable (GtkEditable *,
14168 void GtkEditable::move-cursor (GtkEditable *,
14172 void GtkEditable::move-word (GtkEditable *,
14175 void GtkEditable::move-page (GtkEditable *,
14179 void GtkEditable::move-to-row (GtkEditable *,
14182 void GtkEditable::move-to-column (GtkEditable *,
14185 void GtkEditable::kill-char (GtkEditable *,
14188 void GtkEditable::kill-word (GtkEditable *,
14191 void GtkEditable::kill-line (GtkEditable *,
14194 void GtkEditable::cut-clipboard (GtkEditable *,
14196 void GtkEditable::copy-clipboard (GtkEditable *,
14198 void GtkEditable::paste-clipboard (GtkEditable *,
14204 <!-- ----------------------------------------------------------------- -->
14205 <sect1 id="sec-GtkNotebook">
14206 <title>GtkNotebook</title>
14208 <programlisting role="C">
14209 void GtkNotebook::switch-page (GtkNotebook *,
14217 <!-- ----------------------------------------------------------------- -->
14218 <sect1 id="sec-GtkList">
14219 <title>GtkList</title>
14221 <programlisting role="C">
14222 void GtkList::selection-changed (GtkList *,
14224 void GtkList::select-child (GtkList *,
14227 void GtkList::unselect-child (GtkList *,
14234 <!-- ----------------------------------------------------------------- -->
14235 <sect1 id="sec-GtkMenuShell">
14236 <title>GtkMenuShell</title>
14238 <programlisting role="C">
14239 void GtkMenuShell::deactivate (GtkMenuShell *,
14241 void GtkMenuShell::selection-done (GtkMenuShell *,
14243 void GtkMenuShell::move-current (GtkMenuShell *,
14244 GtkMenuDirectionType,
14246 void GtkMenuShell::activate-current (GtkMenuShell *,
14249 void GtkMenuShell::cancel (GtkMenuShell *,
14255 <!-- ----------------------------------------------------------------- -->
14256 <sect1 id="sec-GtkToolbar">
14257 <title>GtkToolbar</title>
14259 <programlisting role="C">
14260 void GtkToolbar::orientation-changed (GtkToolbar *,
14263 void GtkToolbar::style-changed (GtkToolbar *,
14270 <!-- ----------------------------------------------------------------- -->
14271 <sect1 id="sec-GtkButton">
14272 <title>GtkButton</title>
14274 <programlisting role="C">
14275 void GtkButton::pressed (GtkButton *,
14277 void GtkButton::released (GtkButton *,
14279 void GtkButton::clicked (GtkButton *,
14281 void GtkButton::enter (GtkButton *,
14283 void GtkButton::leave (GtkButton *,
14289 <!-- ----------------------------------------------------------------- -->
14290 <sect1 id="sec-GtkItem">
14291 <title>GtkItem</title>
14293 <programlisting role="C">
14294 void GtkItem::select (GtkItem *,
14296 void GtkItem::deselect (GtkItem *,
14298 void GtkItem::toggle (GtkItem *,
14304 <!-- ----------------------------------------------------------------- -->
14305 <sect1 id="sec-GtkWindow">
14306 <title>GtkWindow</title>
14308 <programlisting role="C">
14309 void GtkWindow::set-focus (GtkWindow *,
14316 <!-- ----------------------------------------------------------------- -->
14317 <sect1 id="sec-GtkHandleBox">
14318 <title>GtkHandleBox</title>
14320 <programlisting role="C">
14321 void GtkHandleBox::child-attached (GtkHandleBox *,
14324 void GtkHandleBox::child-detached (GtkHandleBox *,
14331 <!-- ----------------------------------------------------------------- -->
14332 <sect1 id="sec-GtkToggleButton">
14333 <title>GtkToggleButton</title>
14335 <programlisting role="C">
14336 void GtkToggleButton::toggled (GtkToggleButton *,
14342 <!-- ----------------------------------------------------------------- -->
14343 <sect1 id="sec-GtkMenuItem">
14344 <title>GtkMenuItem</title>
14346 <programlisting role="C">
14347 void GtkMenuItem::activate (GtkMenuItem *,
14349 void GtkMenuItem::activate-item (GtkMenuItem *,
14355 <!-- ----------------------------------------------------------------- -->
14356 <sect1 id="sec-GtkCheckMenuItem">
14357 <title>GtkCheckMenuItem</title>
14359 <programlisting role="C">
14360 void GtkCheckMenuItem::toggled (GtkCheckMenuItem *,
14366 <!-- ----------------------------------------------------------------- -->
14367 <sect1 id="sec-GtkInputDialog">
14368 <title>GtkInputDialog</title>
14370 <programlisting role="C">
14371 void GtkInputDialog::enable-device (GtkInputDialog *,
14374 void GtkInputDialog::disable-device (GtkInputDialog *,
14381 <!-- ----------------------------------------------------------------- -->
14382 <sect1 id="sec-GtkColorSelection">
14383 <title>GtkColorSelection</title>
14385 <programlisting role="C">
14386 void GtkColorSelection::color-changed (GtkColorSelection *,
14392 <!-- ----------------------------------------------------------------- -->
14393 <sect1 id="sec-GtkStatusBar">
14394 <title>GtkStatusBar</title>
14396 <programlisting role="C">
14397 void GtkStatusbar::text-pushed (GtkStatusbar *,
14401 void GtkStatusbar::text-popped (GtkStatusbar *,
14409 <!-- ----------------------------------------------------------------- -->
14410 <sect1 id="sec-GtkCurve">
14411 <title>GtkCurve</title>
14413 <programlisting role="C">
14414 void GtkCurve::curve-type-changed (GtkCurve *,
14420 <!-- ----------------------------------------------------------------- -->
14421 <sect1 id="sec-GtkAdjustment">
14422 <title>GtkAdjustment</title>
14424 <programlisting role="C">
14425 void GtkAdjustment::changed (GtkAdjustment *,
14427 void GtkAdjustment::value-changed (GtkAdjustment *,
14434 <!-- ***************************************************************** -->
14435 <appendix id="app-GDKEventTypes">
14436 <title>GDK Event Types</title>
14438 <para>The following data types are passed into event handlers by GTK+. For
14439 each data type listed, the signals that use this data type are listed.</para>
14442 <listitem><simpara> GdkEvent</simpara>
14444 <listitem><simpara>drag_end_event</simpara>
14449 <listitem><simpara> GdkEventType<</simpara>
14452 <listitem><simpara> GdkEventAny</simpara>
14454 <listitem><simpara>delete_event</simpara>
14456 <listitem><simpara>destroy_event</simpara>
14458 <listitem><simpara>map_event</simpara>
14460 <listitem><simpara>unmap_event</simpara>
14462 <listitem><simpara>no_expose_event</simpara>
14467 <listitem><simpara> GdkEventExpose</simpara>
14469 <listitem><simpara>expose_event</simpara>
14474 <listitem><simpara> GdkEventNoExpose</simpara>
14477 <listitem><simpara> GdkEventVisibility</simpara>
14480 <listitem><simpara> GdkEventMotion</simpara>
14482 <listitem><simpara>motion_notify_event</simpara>
14486 <listitem><simpara> GdkEventButton</simpara>
14488 <listitem><simpara>button_press_event</simpara>
14490 <listitem><simpara>button_release_event</simpara>
14495 <listitem><simpara> GdkEventKey</simpara>
14497 <listitem><simpara>key_press_event</simpara>
14499 <listitem><simpara>key_release_event</simpara>
14504 <listitem><simpara> GdkEventCrossing</simpara>
14506 <listitem><simpara>enter_notify_event</simpara>
14508 <listitem><simpara>leave_notify_event</simpara>
14513 <listitem><simpara> GdkEventFocus</simpara>
14515 <listitem><simpara>focus_in_event</simpara>
14517 <listitem><simpara>focus_out_event</simpara>
14522 <listitem><simpara> GdkEventConfigure</simpara>
14524 <listitem><simpara>configure_event</simpara>
14529 <listitem><simpara> GdkEventProperty</simpara>
14531 <listitem><simpara>property_notify_event</simpara>
14536 <listitem><simpara> GdkEventSelection</simpara>
14538 <listitem><simpara>selection_clear_event</simpara>
14540 <listitem><simpara>selection_request_event</simpara>
14542 <listitem><simpara>selection_notify_event</simpara>
14547 <listitem><simpara> GdkEventProximity</simpara>
14549 <listitem><simpara>proximity_in_event</simpara>
14551 <listitem><simpara>proximity_out_event</simpara>
14556 <listitem><simpara> GdkEventDragBegin</simpara>
14558 <listitem><simpara>drag_begin_event</simpara>
14563 <listitem><simpara> GdkEventDragRequest</simpara>
14565 <listitem><simpara>drag_request_event</simpara>
14570 <listitem><simpara> GdkEventDropEnter</simpara>
14572 <listitem><simpara>drop_enter_event</simpara>
14577 <listitem><simpara> GdkEventDropLeave</simpara>
14579 <listitem><simpara>drop_leave_event</simpara>
14584 <listitem><simpara> GdkEventDropDataAvailable</simpara>
14586 <listitem><simpara>drop_data_available_event</simpara>
14591 <listitem><simpara> GdkEventClient</simpara>
14593 <listitem><simpara>client_event</simpara>
14598 <listitem><simpara> GdkEventOther</simpara>
14600 <listitem><simpara>other_event</simpara>
14606 <para>The data type <literal>GdkEventType</literal> is a special data type that is used by
14607 all the other data types as an indicator of the data type being passed
14608 to the signal handler. As you will see below, each of the event data
14609 structures has a member of this type. It is defined as an enumeration
14610 type as follows:</para>
14612 <programlisting role="C">
14619 GDK_MOTION_NOTIFY = 3,
14620 GDK_BUTTON_PRESS = 4,
14621 GDK_2BUTTON_PRESS = 5,
14622 GDK_3BUTTON_PRESS = 6,
14623 GDK_BUTTON_RELEASE = 7,
14625 GDK_KEY_RELEASE = 9,
14626 GDK_ENTER_NOTIFY = 10,
14627 GDK_LEAVE_NOTIFY = 11,
14628 GDK_FOCUS_CHANGE = 12,
14629 GDK_CONFIGURE = 13,
14632 GDK_PROPERTY_NOTIFY = 16,
14633 GDK_SELECTION_CLEAR = 17,
14634 GDK_SELECTION_REQUEST = 18,
14635 GDK_SELECTION_NOTIFY = 19,
14636 GDK_PROXIMITY_IN = 20,
14637 GDK_PROXIMITY_OUT = 21,
14638 GDK_DRAG_BEGIN = 22,
14639 GDK_DRAG_REQUEST = 23,
14640 GDK_DROP_ENTER = 24,
14641 GDK_DROP_LEAVE = 25,
14642 GDK_DROP_DATA_AVAIL = 26,
14643 GDK_CLIENT_EVENT = 27,
14644 GDK_VISIBILITY_NOTIFY = 28,
14645 GDK_NO_EXPOSE = 29,
14646 GDK_OTHER_EVENT = 9999 /* Deprecated, use filters instead */
14650 <para>The other event type that is different from the others is
14651 <literal>GdkEvent</literal> itself. This is a union of all the other
14652 data types, which allows it to be cast to a specific
14653 event data type within a signal handler.</para>
14655 <!-- Just a big list for now, needs expanding upon - TRG -->
14656 <para>So, the event data types are defined as follows:</para>
14658 <programlisting role="C">
14659 struct _GdkEventAny
14666 struct _GdkEventExpose
14672 gint count; /* If non-zero, how many more events follow. */
14675 struct _GdkEventNoExpose
14680 /* XXX: does anyone need the X major_code or minor_code fields? */
14683 struct _GdkEventVisibility
14688 GdkVisibilityState state;
14691 struct _GdkEventMotion
14704 GdkInputSource source;
14706 gdouble x_root, y_root;
14709 struct _GdkEventButton
14722 GdkInputSource source;
14724 gdouble x_root, y_root;
14727 struct _GdkEventKey
14739 struct _GdkEventCrossing
14744 GdkWindow *subwindow;
14745 GdkNotifyType detail;
14748 struct _GdkEventFocus
14756 struct _GdkEventConfigure
14766 struct _GdkEventProperty
14776 struct _GdkEventSelection
14788 /* This event type will be used pretty rarely. It only is important
14789 for XInput aware programs that are drawing their own cursor */
14791 struct _GdkEventProximity
14797 GdkInputSource source;
14801 struct _GdkEventDragRequest
14809 guint protocol_version:4;
14811 guint willaccept:1;
14812 guint delete_data:1; /* Do *not* delete if link is sent, only
14819 guint8 isdrop; /* This gdk event can be generated by a couple of
14820 X events - this lets the app know whether the
14821 drop really occurred or we just set the data */
14823 GdkPoint drop_coords;
14828 struct _GdkEventDragBegin
14835 guint protocol_version:4;
14842 struct _GdkEventDropEnter
14850 guint protocol_version:4;
14852 guint extended_typelist:1;
14859 struct _GdkEventDropLeave
14867 guint protocol_version:4;
14874 struct _GdkEventDropDataAvailable
14882 guint protocol_version:4;
14888 gchar *data_type; /* MIME type */
14889 gulong data_numbytes;
14895 struct _GdkEventClient
14900 GdkAtom message_type;
14901 gushort data_format;
14909 struct _GdkEventOther
14920 <!-- ***************************************************************** -->
14921 <appendix id="app-CodeExamples">
14922 <title>Code Examples</title>
14924 <para>Below are the code examples that are used in the above text
14925 which are not included in complete form elsewhere.</para>
14927 <!-- ----------------------------------------------------------------- -->
14928 <sect1 id="sec-Tictactoe">
14929 <title>Tictactoe</title>
14930 <!-- ----------------------------------------------------------------- -->
14932 <title>tictactoe.h</title>
14934 <programlisting role="C">
14935 <!-- example-start tictactoe tictactoe.h -->
14937 /* GTK - The GIMP Toolkit
14938 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
14940 * This library is free software; you can redistribute it and/or
14941 * modify it under the terms of the GNU Library General Public
14942 * License as published by the Free Software Foundation; either
14943 * version 2 of the License, or (at your option) any later version.
14945 * This library is distributed in the hope that it will be useful,
14946 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14947 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14948 * Library General Public License for more details.
14950 * You should have received a copy of the GNU Library General Public
14951 * License along with this library; if not, write to the
14952 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14953 * Boston, MA 02111-1307, USA.
14955 #ifndef __TICTACTOE_H__
14956 #define __TICTACTOE_H__
14959 #include <gdk/gdk.h>
14960 #include <gtk/gtkvbox.h>
14965 #endif /* __cplusplus */
14967 #define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
14968 #define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
14969 #define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
14972 typedef struct _Tictactoe Tictactoe;
14973 typedef struct _TictactoeClass TictactoeClass;
14979 GtkWidget *buttons[3][3];
14982 struct _TictactoeClass
14984 GtkVBoxClass parent_class;
14986 void (* tictactoe) (Tictactoe *ttt);
14989 GtkType tictactoe_get_type (void);
14990 GtkWidget* tictactoe_new (void);
14991 void tictactoe_clear (Tictactoe *ttt);
14995 #endif /* __cplusplus */
14997 #endif /* __TICTACTOE_H__ */
14999 <!-- example-end -->
15004 <!-- ----------------------------------------------------------------- -->
15006 <title>tictactoe.c</title>
15008 <programlisting role="C">
15009 <!-- example-start tictactoe tictactoe.c -->
15011 /* GTK - The GIMP Toolkit
15012 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15014 * This library is free software; you can redistribute it and/or
15015 * modify it under the terms of the GNU Library General Public
15016 * License as published by the Free Software Foundation; either
15017 * version 2 of the License, or (at your option) any later version.
15019 * This library is distributed in the hope that it will be useful,
15020 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15021 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15022 * Library General Public License for more details.
15024 * You should have received a copy of the GNU Library General Public
15025 * License along with this library; if not, write to the
15026 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15027 * Boston, MA 02111-1307, USA.
15029 #include "gtk/gtksignal.h"
15030 #include "gtk/gtktable.h"
15031 #include "gtk/gtktogglebutton.h"
15032 #include "tictactoe.h"
15039 static void tictactoe_class_init (TictactoeClass *klass);
15040 static void tictactoe_init (Tictactoe *ttt);
15041 static void tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt);
15043 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
15046 tictactoe_get_type ()
15048 static GType ttt_type = 0;
15052 static const GTypeInfo ttt_info =
15054 sizeof (TictactoeClass),
15057 (GClassInitFunc) tictactoe_class_init,
15060 sizeof (Tictactoe),
15062 (GInstanceInitFunc) tictactoe_init,
15065 ttt_type = g_type_register_static (GTK_TYPE_VBOX, "Tictactoe", &ttt_info, 0);
15072 tictactoe_class_init (TictactoeClass *class)
15074 GtkObjectClass *object_class;
15076 object_class = (GtkObjectClass*) class;
15078 tictactoe_signals[TICTACTOE_SIGNAL] = g_signal_new ("tictactoe",
15079 G_TYPE_FROM_CLASS (object_class),
15080 G_SIGNAL_RUN_FIRST,
15084 g_cclosure_marshal_VOID__VOID,
15085 G_TYPE_NONE, 0, NULL);
15088 class->tictactoe = NULL;
15092 tictactoe_init (Tictactoe *ttt)
15097 table = gtk_table_new (3, 3, TRUE);
15098 gtk_container_add (GTK_CONTAINER (ttt), table);
15099 gtk_widget_show (table);
15101 for (i = 0; i < 3; i++)
15102 for (j = 0; j < 3; j++)
15104 ttt->buttons[i][j] = gtk_toggle_button_new ();
15105 gtk_table_attach_defaults (GTK_TABLE (table), ttt->buttons[i][j],
15107 g_signal_connect (G_OBJECT (ttt->buttons[i][j]), "toggled",
15108 G_CALLBACK (tictactoe_toggle), ttt);
15109 gtk_widget_set_size_request (ttt->buttons[i][j], 20, 20);
15110 gtk_widget_show (ttt->buttons[i][j]);
15117 return GTK_WIDGET (g_object_new (tictactoe_get_type (), NULL));
15121 tictactoe_clear (Tictactoe *ttt)
15125 for (i = 0; i < 3; i++)
15126 for (j = 0; j < 3; j++)
15128 g_signal_handlers_block_by_func (G_OBJECT (ttt->buttons[i][j]),
15130 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
15132 g_signal_handlers_unblock_by_func (G_OBJECT (ttt->buttons[i][j]),
15138 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
15142 static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
15143 { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
15144 { 0, 1, 2 }, { 0, 1, 2 } };
15145 static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
15146 { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
15147 { 0, 1, 2 }, { 2, 1, 0 } };
15149 int success, found;
15151 for (k = 0; k < 8; k++)
15156 for (i = 0; i < 3; i++)
15158 success = success &&
15159 GTK_TOGGLE_BUTTON (ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
15161 ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
15164 if (success && found)
15166 g_signal_emit (G_OBJECT (ttt),
15167 tictactoe_signals[TICTACTOE_SIGNAL], 0);
15173 <!-- example-end -->
15178 <!-- ----------------------------------------------------------------- -->
15180 <title>ttt_test.c</title>
15182 <programlisting role="C">
15183 <!-- example-start tictactoe ttt_test.c -->
15185 #include <stdlib.h>
15186 #include <gtk/gtk.h>
15187 #include "tictactoe.h"
15189 void win( GtkWidget *widget,
15192 g_print ("Yay!\n");
15193 tictactoe_clear (TICTACTOE (widget));
15196 int main( int argc,
15202 gtk_init (&argc, &argv);
15204 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
15206 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
15208 g_signal_connect (G_OBJECT (window), "destroy",
15209 G_CALLBACK (exit), NULL);
15211 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
15213 ttt = tictactoe_new ();
15215 gtk_container_add (GTK_CONTAINER (window), ttt);
15216 gtk_widget_show (ttt);
15218 g_signal_connect (G_OBJECT (ttt), "tictactoe",
15219 G_CALLBACK (win), NULL);
15221 gtk_widget_show (window);
15228 <!-- example-end -->
15234 <!-- ----------------------------------------------------------------- -->
15235 <sect1 id="sec-GtkDial">
15236 <title>GtkDial</title>
15238 <!-- ----------------------------------------------------------------- -->
15240 <title>gtkdial.h</title>
15242 <programlisting role="C">
15243 <!-- example-start gtkdial gtkdial.h -->
15245 /* GTK - The GIMP Toolkit
15246 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15248 * This library is free software; you can redistribute it and/or
15249 * modify it under the terms of the GNU Library General Public
15250 * License as published by the Free Software Foundation; either
15251 * version 2 of the License, or (at your option) any later version.
15253 * This library is distributed in the hope that it will be useful,
15254 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15255 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15256 * Library General Public License for more details.
15258 * You should have received a copy of the GNU Library General Public
15259 * License along with this library; if not, write to the
15260 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15261 * Boston, MA 02111-1307, USA.
15263 #ifndef __GTK_DIAL_H__
15264 #define __GTK_DIAL_H__
15267 #include <gdk/gdk.h>
15268 #include <gtk/gtkadjustment.h>
15269 #include <gtk/gtkwidget.h>
15274 #endif /* __cplusplus */
15277 #define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
15278 #define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
15279 #define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
15282 typedef struct _GtkDial GtkDial;
15283 typedef struct _GtkDialClass GtkDialClass;
15289 /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
15292 /* Button currently pressed or 0 if none */
15295 /* Dimensions of dial components */
15297 gint pointer_width;
15299 /* ID of update timer, or 0 if none */
15302 /* Current angle */
15306 /* Old values from adjustment stored so we know when something changes */
15311 /* The adjustment object that stores the data for this dial */
15312 GtkAdjustment *adjustment;
15315 struct _GtkDialClass
15317 GtkWidgetClass parent_class;
15321 GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
15322 GtkType gtk_dial_get_type (void);
15323 GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
15324 void gtk_dial_set_update_policy (GtkDial *dial,
15325 GtkUpdateType policy);
15327 void gtk_dial_set_adjustment (GtkDial *dial,
15328 GtkAdjustment *adjustment);
15331 #endif /* __cplusplus */
15334 #endif /* __GTK_DIAL_H__ */
15335 <!-- example-end -->
15340 <!-- ----------------------------------------------------------------- -->
15342 <title>gtkdial.c</title>
15344 <programlisting role="C">
15345 <!-- example-start gtkdial gtkdial.c -->
15347 /* GTK - The GIMP Toolkit
15348 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15350 * This library is free software; you can redistribute it and/or
15351 * modify it under the terms of the GNU Library General Public
15352 * License as published by the Free Software Foundation; either
15353 * version 2 of the License, or (at your option) any later version.
15355 * This library is distributed in the hope that it will be useful,
15356 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15357 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15358 * Library General Public License for more details.
15360 * You should have received a copy of the GNU Library General Public
15361 * License along with this library; if not, write to the
15362 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15363 * Boston, MA 02111-1307, USA.
15365 #include <math.h>
15366 #include <stdio.h>
15367 #include <gtk/gtkmain.h>
15368 #include <gtk/gtksignal.h>
15370 #include "gtkdial.h"
15372 #define SCROLL_DELAY_LENGTH 300
15373 #define DIAL_DEFAULT_SIZE 100
15375 /* Forward declarations */
15377 static void gtk_dial_class_init (GtkDialClass *klass);
15378 static void gtk_dial_init (GtkDial *dial);
15379 static void gtk_dial_destroy (GtkObject *object);
15380 static void gtk_dial_realize (GtkWidget *widget);
15381 static void gtk_dial_size_request (GtkWidget *widget,
15382 GtkRequisition *requisition);
15383 static void gtk_dial_size_allocate (GtkWidget *widget,
15384 GtkAllocation *allocation);
15385 static gint gtk_dial_expose (GtkWidget *widget,
15386 GdkEventExpose *event);
15387 static gint gtk_dial_button_press (GtkWidget *widget,
15388 GdkEventButton *event);
15389 static gint gtk_dial_button_release (GtkWidget *widget,
15390 GdkEventButton *event);
15391 static gint gtk_dial_motion_notify (GtkWidget *widget,
15392 GdkEventMotion *event);
15393 static gint gtk_dial_timer (GtkDial *dial);
15395 static void gtk_dial_update_mouse (GtkDial *dial, gint x, gint y);
15396 static void gtk_dial_update (GtkDial *dial);
15397 static void gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
15399 static void gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
15404 static GtkWidgetClass *parent_class = NULL;
15407 gtk_dial_get_type ()
15409 static GType dial_type = 0;
15413 static const GTypeInfo dial_info =
15415 sizeof (GtkDialClass),
15418 (GClassInitFunc) gtk_dial_class_init,
15423 (GInstanceInitFunc) gtk_dial_init,
15426 dial_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkDial", &dial_info, 0);
15433 gtk_dial_class_init (GtkDialClass *class)
15435 GtkObjectClass *object_class;
15436 GtkWidgetClass *widget_class;
15438 object_class = (GtkObjectClass*) class;
15439 widget_class = (GtkWidgetClass*) class;
15441 parent_class = gtk_type_class (gtk_widget_get_type ());
15443 object_class->destroy = gtk_dial_destroy;
15445 widget_class->realize = gtk_dial_realize;
15446 widget_class->expose_event = gtk_dial_expose;
15447 widget_class->size_request = gtk_dial_size_request;
15448 widget_class->size_allocate = gtk_dial_size_allocate;
15449 widget_class->button_press_event = gtk_dial_button_press;
15450 widget_class->button_release_event = gtk_dial_button_release;
15451 widget_class->motion_notify_event = gtk_dial_motion_notify;
15455 gtk_dial_init (GtkDial *dial)
15457 dial->button = 0;
15458 dial->policy = GTK_UPDATE_CONTINUOUS;
15459 dial->timer = 0;
15460 dial->radius = 0;
15461 dial->pointer_width = 0;
15462 dial->angle = 0.0;
15463 dial->old_value = 0.0;
15464 dial->old_lower = 0.0;
15465 dial->old_upper = 0.0;
15466 dial->adjustment = NULL;
15470 gtk_dial_new (GtkAdjustment *adjustment)
15474 dial = g_object_new (gtk_dial_get_type (), NULL);
15477 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
15479 gtk_dial_set_adjustment (dial, adjustment);
15481 return GTK_WIDGET (dial);
15485 gtk_dial_destroy (GtkObject *object)
15489 g_return_if_fail (object != NULL);
15490 g_return_if_fail (GTK_IS_DIAL (object));
15492 dial = GTK_DIAL (object);
15494 if (dial->adjustment)
15495 g_object_unref (GTK_OBJECT (dial->adjustment));
15497 if (GTK_OBJECT_CLASS (parent_class)->destroy)
15498 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
15502 gtk_dial_get_adjustment (GtkDial *dial)
15504 g_return_val_if_fail (dial != NULL, NULL);
15505 g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
15507 return dial->adjustment;
15511 gtk_dial_set_update_policy (GtkDial *dial,
15512 GtkUpdateType policy)
15514 g_return_if_fail (dial != NULL);
15515 g_return_if_fail (GTK_IS_DIAL (dial));
15517 dial->policy = policy;
15521 gtk_dial_set_adjustment (GtkDial *dial,
15522 GtkAdjustment *adjustment)
15524 g_return_if_fail (dial != NULL);
15525 g_return_if_fail (GTK_IS_DIAL (dial));
15527 if (dial->adjustment)
15529 g_signal_handlers_disconnect_by_func (GTK_OBJECT (dial->adjustment), NULL, (gpointer) dial);
15530 g_object_unref (GTK_OBJECT (dial->adjustment));
15533 dial->adjustment = adjustment;
15534 g_object_ref (GTK_OBJECT (dial->adjustment));
15536 g_signal_connect (GTK_OBJECT (adjustment), "changed",
15537 GTK_SIGNAL_FUNC (gtk_dial_adjustment_changed),
15539 g_signal_connect (GTK_OBJECT (adjustment), "value_changed",
15540 GTK_SIGNAL_FUNC (gtk_dial_adjustment_value_changed),
15543 dial->old_value = adjustment->value;
15544 dial->old_lower = adjustment->lower;
15545 dial->old_upper = adjustment->upper;
15547 gtk_dial_update (dial);
15551 gtk_dial_realize (GtkWidget *widget)
15554 GdkWindowAttr attributes;
15555 gint attributes_mask;
15557 g_return_if_fail (widget != NULL);
15558 g_return_if_fail (GTK_IS_DIAL (widget));
15560 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
15561 dial = GTK_DIAL (widget);
15563 attributes.x = widget->allocation.x;
15564 attributes.y = widget->allocation.y;
15565 attributes.width = widget->allocation.width;
15566 attributes.height = widget->allocation.height;
15567 attributes.wclass = GDK_INPUT_OUTPUT;
15568 attributes.window_type = GDK_WINDOW_CHILD;
15569 attributes.event_mask = gtk_widget_get_events (widget) |
15570 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
15571 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
15572 GDK_POINTER_MOTION_HINT_MASK;
15573 attributes.visual = gtk_widget_get_visual (widget);
15574 attributes.colormap = gtk_widget_get_colormap (widget);
15576 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
15577 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
15579 widget->style = gtk_style_attach (widget->style, widget->window);
15581 gdk_window_set_user_data (widget->window, widget);
15583 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
15587 gtk_dial_size_request (GtkWidget *widget,
15588 GtkRequisition *requisition)
15590 requisition->width = DIAL_DEFAULT_SIZE;
15591 requisition->height = DIAL_DEFAULT_SIZE;
15595 gtk_dial_size_allocate (GtkWidget *widget,
15596 GtkAllocation *allocation)
15600 g_return_if_fail (widget != NULL);
15601 g_return_if_fail (GTK_IS_DIAL (widget));
15602 g_return_if_fail (allocation != NULL);
15604 widget->allocation = *allocation;
15605 dial = GTK_DIAL (widget);
15607 if (GTK_WIDGET_REALIZED (widget))
15610 gdk_window_move_resize (widget->window,
15611 allocation->x, allocation->y,
15612 allocation->width, allocation->height);
15615 dial->radius = MIN (allocation->width, allocation->height) * 0.45;
15616 dial->pointer_width = dial->radius / 5;
15620 gtk_dial_expose (GtkWidget *widget,
15621 GdkEventExpose *event)
15624 GdkPoint points[6];
15626 gdouble theta, last, increment;
15627 GtkStyle *blankstyle;
15633 g_return_val_if_fail (widget != NULL, FALSE);
15634 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
15635 g_return_val_if_fail (event != NULL, FALSE);
15637 if (event->count > 0)
15640 dial = GTK_DIAL (widget);
15642 /* gdk_window_clear_area (widget->window,
15644 widget->allocation.width,
15645 widget->allocation.height);
15647 xc = widget->allocation.width / 2;
15648 yc = widget->allocation.height / 2;
15650 upper = dial->adjustment->upper;
15651 lower = dial->adjustment->lower;
15653 /* Erase old pointer */
15655 s = sin (dial->last_angle);
15656 c = cos (dial->last_angle);
15657 dial->last_angle = dial->angle;
15659 points[0].x = xc + s*dial->pointer_width/2;
15660 points[0].y = yc + c*dial->pointer_width/2;
15661 points[1].x = xc + c*dial->radius;
15662 points[1].y = yc - s*dial->radius;
15663 points[2].x = xc - s*dial->pointer_width/2;
15664 points[2].y = yc - c*dial->pointer_width/2;
15665 points[3].x = xc - c*dial->radius/10;
15666 points[3].y = yc + s*dial->radius/10;
15667 points[4].x = points[0].x;
15668 points[4].y = points[0].y;
15670 blankstyle = gtk_style_new ();
15671 blankstyle->bg_gc[GTK_STATE_NORMAL] =
15672 widget->style->bg_gc[GTK_STATE_NORMAL];
15673 blankstyle->dark_gc[GTK_STATE_NORMAL] =
15674 widget->style->bg_gc[GTK_STATE_NORMAL];
15675 blankstyle->light_gc[GTK_STATE_NORMAL] =
15676 widget->style->bg_gc[GTK_STATE_NORMAL];
15677 blankstyle->black_gc =
15678 widget->style->bg_gc[GTK_STATE_NORMAL];
15680 gtk_paint_polygon (blankstyle,
15690 g_object_unref (blankstyle);
15695 if ((upper - lower) == 0)
15698 increment = (100*M_PI) / (dial->radius*dial->radius);
15700 inc = (upper - lower);
15702 while (inc < 100) inc *= 10;
15703 while (inc >= 1000) inc /= 10;
15706 for (i = 0; i <= inc; i++)
15708 theta = ((gfloat)i*M_PI / (18*inc/24.) - M_PI/6.);
15710 if ((theta - last) < (increment))
15717 tick_length = (i%(inc/10) == 0) ? dial->pointer_width : dial->pointer_width / 2;
15719 gdk_draw_line (widget->window,
15720 widget->style->fg_gc[widget->state],
15721 xc + c*(dial->radius - tick_length),
15722 yc - s*(dial->radius - tick_length),
15723 xc + c*dial->radius,
15724 yc - s*dial->radius);
15729 s = sin (dial->angle);
15730 c = cos (dial->angle);
15731 dial->last_angle = dial->angle;
15733 points[0].x = xc + s*dial->pointer_width/2;
15734 points[0].y = yc + c*dial->pointer_width/2;
15735 points[1].x = xc + c*dial->radius;
15736 points[1].y = yc - s*dial->radius;
15737 points[2].x = xc - s*dial->pointer_width/2;
15738 points[2].y = yc - c*dial->pointer_width/2;
15739 points[3].x = xc - c*dial->radius/10;
15740 points[3].y = yc + s*dial->radius/10;
15741 points[4].x = points[0].x;
15742 points[4].y = points[0].y;
15745 gtk_paint_polygon (widget->style,
15759 gtk_dial_button_press (GtkWidget *widget,
15760 GdkEventButton *event)
15766 double d_perpendicular;
15768 g_return_val_if_fail (widget != NULL, FALSE);
15769 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
15770 g_return_val_if_fail (event != NULL, FALSE);
15772 dial = GTK_DIAL (widget);
15774 /* Determine if button press was within pointer region - we
15775 do this by computing the parallel and perpendicular distance of
15776 the point where the mouse was pressed from the line passing through
15779 dx = event->x - widget->allocation.width / 2;
15780 dy = widget->allocation.height / 2 - event->y;
15782 s = sin (dial->angle);
15783 c = cos (dial->angle);
15785 d_parallel = s*dy + c*dx;
15786 d_perpendicular = fabs (s*dx - c*dy);
15788 if (!dial->button &&
15789 (d_perpendicular < dial->pointer_width/2) &&
15790 (d_parallel > - dial->pointer_width))
15792 gtk_grab_add (widget);
15794 dial->button = event->button;
15796 gtk_dial_update_mouse (dial, event->x, event->y);
15803 gtk_dial_button_release (GtkWidget *widget,
15804 GdkEventButton *event)
15808 g_return_val_if_fail (widget != NULL, FALSE);
15809 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
15810 g_return_val_if_fail (event != NULL, FALSE);
15812 dial = GTK_DIAL (widget);
15814 if (dial->button == event->button)
15816 gtk_grab_remove (widget);
15818 dial->button = 0;
15820 if (dial->policy == GTK_UPDATE_DELAYED)
15821 gtk_timeout_remove (dial->timer);
15823 if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
15824 (dial->old_value != dial->adjustment->value))
15825 g_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
15832 gtk_dial_motion_notify (GtkWidget *widget,
15833 GdkEventMotion *event)
15836 GdkModifierType mods;
15839 g_return_val_if_fail (widget != NULL, FALSE);
15840 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
15841 g_return_val_if_fail (event != NULL, FALSE);
15843 dial = GTK_DIAL (widget);
15845 if (dial->button != 0)
15850 if (event->is_hint || (event->window != widget->window))
15851 gdk_window_get_pointer (widget->window, &x, &y, &mods);
15853 switch (dial->button)
15856 mask = GDK_BUTTON1_MASK;
15859 mask = GDK_BUTTON2_MASK;
15862 mask = GDK_BUTTON3_MASK;
15869 if (mods & mask)
15870 gtk_dial_update_mouse (dial, x,y);
15877 gtk_dial_timer (GtkDial *dial)
15879 g_return_val_if_fail (dial != NULL, FALSE);
15880 g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
15882 if (dial->policy == GTK_UPDATE_DELAYED)
15883 g_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
15889 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
15894 g_return_if_fail (dial != NULL);
15895 g_return_if_fail (GTK_IS_DIAL (dial));
15897 xc = GTK_WIDGET(dial)->allocation.width / 2;
15898 yc = GTK_WIDGET(dial)->allocation.height / 2;
15900 old_value = dial->adjustment->value;
15901 dial->angle = atan2(yc-y, x-xc);
15903 if (dial->angle < -M_PI/2.)
15904 dial->angle += 2*M_PI;
15906 if (dial->angle < -M_PI/6)
15907 dial->angle = -M_PI/6;
15909 if (dial->angle > 7.*M_PI/6.)
15910 dial->angle = 7.*M_PI/6.;
15912 dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
15913 (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
15915 if (dial->adjustment->value != old_value)
15917 if (dial->policy == GTK_UPDATE_CONTINUOUS)
15919 g_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
15923 gtk_widget_queue_draw (GTK_WIDGET (dial));
15925 if (dial->policy == GTK_UPDATE_DELAYED)
15927 if (dial->timer)
15928 gtk_timeout_remove (dial->timer);
15930 dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
15931 (GtkFunction) gtk_dial_timer,
15939 gtk_dial_update (GtkDial *dial)
15943 g_return_if_fail (dial != NULL);
15944 g_return_if_fail (GTK_IS_DIAL (dial));
15946 new_value = dial->adjustment->value;
15948 if (new_value < dial->adjustment->lower)
15949 new_value = dial->adjustment->lower;
15951 if (new_value > dial->adjustment->upper)
15952 new_value = dial->adjustment->upper;
15954 if (new_value != dial->adjustment->value)
15956 dial->adjustment->value = new_value;
15957 g_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
15960 dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
15961 (dial->adjustment->upper - dial->adjustment->lower);
15963 gtk_widget_queue_draw (GTK_WIDGET (dial));
15967 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
15972 g_return_if_fail (adjustment != NULL);
15973 g_return_if_fail (data != NULL);
15975 dial = GTK_DIAL (data);
15977 if ((dial->old_value != adjustment->value) ||
15978 (dial->old_lower != adjustment->lower) ||
15979 (dial->old_upper != adjustment->upper))
15981 gtk_dial_update (dial);
15983 dial->old_value = adjustment->value;
15984 dial->old_lower = adjustment->lower;
15985 dial->old_upper = adjustment->upper;
15990 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
15995 g_return_if_fail (adjustment != NULL);
15996 g_return_if_fail (data != NULL);
15998 dial = GTK_DIAL (data);
16000 if (dial->old_value != adjustment->value)
16002 gtk_dial_update (dial);
16004 dial->old_value = adjustment->value;
16007 <!-- example-end -->
16012 <!-- ----------------------------------------------------------------- -->
16014 <title>dial_test.c</title>
16016 <programlisting role="C">
16017 <!-- example-start gtkdial dial_test.c -->
16019 #include <stdio.h>
16020 #include <stdlib.h>
16021 #include <gtk/gtk.h>
16022 #include "gtkdial.h"
16024 void value_changed( GtkAdjustment *adjustment,
16029 sprintf(buffer,"%4.2f",adjustment->value);
16030 gtk_label_set_text (GTK_LABEL (label), buffer);
16033 int main( int argc,
16037 GtkAdjustment *adjustment;
16043 gtk_init (&argc, &argv);
16045 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
16047 gtk_window_set_title (GTK_WINDOW (window), "Dial");
16049 g_signal_connect (G_OBJECT (window), "destroy",
16050 G_CALLBACK (exit), NULL);
16052 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
16054 vbox = gtk_vbox_new (FALSE, 5);
16055 gtk_container_add (GTK_CONTAINER (window), vbox);
16056 gtk_widget_show (vbox);
16058 frame = gtk_frame_new (NULL);
16059 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
16060 gtk_container_add (GTK_CONTAINER (vbox), frame);
16061 gtk_widget_show (frame);
16063 adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0, 0, 100, 0.01, 0.1, 0));
16065 dial = gtk_dial_new (adjustment);
16066 gtk_dial_set_update_policy (GTK_DIAL (dial), GTK_UPDATE_DELAYED);
16067 /* gtk_widget_set_size_request (dial, 100, 100); */
16069 gtk_container_add (GTK_CONTAINER (frame), dial);
16070 gtk_widget_show (dial);
16072 label = gtk_label_new ("0.00");
16073 gtk_box_pack_end (GTK_BOX (vbox), label, 0, 0, 0);
16074 gtk_widget_show (label);
16076 g_signal_connect (G_OBJECT (adjustment), "value_changed",
16077 G_CALLBACK (value_changed), label);
16079 gtk_widget_show (window);
16085 <!-- example-end -->
16091 <!-- ----------------------------------------------------------------- -->
16092 <sect1 id="sec-Scribble">
16093 <title>Scribble</title>
16095 <!-- ----------------------------------------------------------------- -->
16097 <title>scribble-simple.c</title>
16099 <programlisting role="C">
16100 <!-- example-start scribble-simple scribble-simple.c -->
16102 /* GTK - The GIMP Toolkit
16103 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
16105 * This library is free software; you can redistribute it and/or
16106 * modify it under the terms of the GNU Library General Public
16107 * License as published by the Free Software Foundation; either
16108 * version 2 of the License, or (at your option) any later version.
16110 * This library is distributed in the hope that it will be useful,
16111 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16112 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16113 * Library General Public License for more details.
16115 * You should have received a copy of the GNU Library General Public
16116 * License along with this library; if not, write to the
16117 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16118 * Boston, MA 02111-1307, USA.
16121 #include <gtk/gtk.h>
16123 /* Backing pixmap for drawing area */
16124 static GdkPixmap *pixmap = NULL;
16126 /* Create a new backing pixmap of the appropriate size */
16127 static gint configure_event( GtkWidget *widget,
16128 GdkEventConfigure *event )
16131 g_object_unref (pixmap);
16133 pixmap = gdk_pixmap_new (widget->window,
16134 widget->allocation.width,
16135 widget->allocation.height,
16137 gdk_draw_rectangle (pixmap,
16138 widget->style->white_gc,
16141 widget->allocation.width,
16142 widget->allocation.height);
16147 /* Redraw the screen from the backing pixmap */
16148 static gint expose_event( GtkWidget *widget,
16149 GdkEventExpose *event )
16151 gdk_draw_drawable (widget->window,
16152 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
16154 event->area.x, event->area.y,
16155 event->area.x, event->area.y,
16156 event->area.width, event->area.height);
16161 /* Draw a rectangle on the screen */
16162 static void draw_brush( GtkWidget *widget,
16166 GdkRectangle update_rect;
16168 update_rect.x = x - 5;
16169 update_rect.y = y - 5;
16170 update_rect.width = 10;
16171 update_rect.height = 10;
16172 gdk_draw_rectangle (pixmap,
16173 widget->style->black_gc,
16175 update_rect.x, update_rect.y,
16176 update_rect.width, update_rect.height);
16177 gtk_widget_queue_draw_area (widget,
16178 update_rect.x, update_rect.y,
16179 update_rect.width, update_rect.height);
16182 static gint button_press_event( GtkWidget *widget,
16183 GdkEventButton *event )
16185 if (event->button == 1 && pixmap != NULL)
16186 draw_brush (widget, event->x, event->y);
16191 static gint motion_notify_event( GtkWidget *widget,
16192 GdkEventMotion *event )
16195 GdkModifierType state;
16197 if (event->is_hint)
16198 gdk_window_get_pointer (event->window, &x, &y, &state);
16203 state = event->state;
16206 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
16207 draw_brush (widget, x, y);
16217 int main( int argc,
16221 GtkWidget *drawing_area;
16226 gtk_init (&argc, &argv);
16228 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
16229 gtk_widget_set_name (window, "Test Input");
16231 vbox = gtk_vbox_new (FALSE, 0);
16232 gtk_container_add (GTK_CONTAINER (window), vbox);
16233 gtk_widget_show (vbox);
16235 g_signal_connect (G_OBJECT (window), "destroy",
16236 G_CALLBACK (quit), NULL);
16238 /* Create the drawing area */
16240 drawing_area = gtk_drawing_area_new ();
16241 gtk_widget_set_size_request (GTK_WIDGET (drawing_area), 200, 200);
16242 gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
16244 gtk_widget_show (drawing_area);
16246 /* Signals used to handle backing pixmap */
16248 g_signal_connect (G_OBJECT (drawing_area), "expose_event",
16249 G_CALLBACK (expose_event), NULL);
16250 g_signal_connect (G_OBJECT (drawing_area),"configure_event",
16251 G_CALLBACK (configure_event), NULL);
16253 /* Event signals */
16255 g_signal_connect (G_OBJECT (drawing_area), "motion_notify_event",
16256 G_CALLBACK (motion_notify_event), NULL);
16257 g_signal_connect (G_OBJECT (drawing_area), "button_press_event",
16258 G_CALLBACK (button_press_event), NULL);
16260 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
16261 | GDK_LEAVE_NOTIFY_MASK
16262 | GDK_BUTTON_PRESS_MASK
16263 | GDK_POINTER_MOTION_MASK
16264 | GDK_POINTER_MOTION_HINT_MASK);
16266 /* .. And a quit button */
16267 button = gtk_button_new_with_label ("Quit");
16268 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
16270 g_signal_connect_swapped (G_OBJECT (button), "clicked",
16271 G_CALLBACK (gtk_widget_destroy),
16273 gtk_widget_show (button);
16275 gtk_widget_show (window);
16281 <!-- example-end -->
16286 <!-- ----------------------------------------------------------------- -->
16288 <title>scribble-xinput.c</title>
16290 <programlisting role="C">
16291 <!-- example-start scribble-xinput scribble-xinput.c -->
16293 /* GTK - The GIMP Toolkit
16294 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
16296 * This library is free software; you can redistribute it and/or
16297 * modify it under the terms of the GNU Library General Public
16298 * License as published by the Free Software Foundation; either
16299 * version 2 of the License, or (at your option) any later version.
16301 * This library is distributed in the hope that it will be useful,
16302 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16303 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16304 * Library General Public License for more details.
16306 * You should have received a copy of the GNU Library General Public
16307 * License along with this library; if not, write to the
16308 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16309 * Boston, MA 02111-1307, USA.
16312 #include <gtk/gtk.h>
16314 /* Backing pixmap for drawing area */
16315 static GdkPixmap *pixmap = NULL;
16317 /* Create a new backing pixmap of the appropriate size */
16319 configure_event (GtkWidget *widget, GdkEventConfigure *event)
16322 g_object_unref (pixmap);
16324 pixmap = gdk_pixmap_new (widget->window,
16325 widget->allocation.width,
16326 widget->allocation.height,
16328 gdk_draw_rectangle (pixmap,
16329 widget->style->white_gc,
16332 widget->allocation.width,
16333 widget->allocation.height);
16338 /* Redraw the screen from the backing pixmap */
16340 expose_event (GtkWidget *widget, GdkEventExpose *event)
16342 gdk_draw_drawable (widget->window,
16343 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
16345 event->area.x, event->area.y,
16346 event->area.x, event->area.y,
16347 event->area.width, event->area.height);
16352 /* Draw a rectangle on the screen, size depending on pressure,
16353 and color on the type of device */
16355 draw_brush (GtkWidget *widget, GdkInputSource source,
16356 gdouble x, gdouble y, gdouble pressure)
16359 GdkRectangle update_rect;
16363 case GDK_SOURCE_MOUSE:
16364 gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
16366 case GDK_SOURCE_PEN:
16367 gc = widget->style->black_gc;
16369 case GDK_SOURCE_ERASER:
16370 gc = widget->style->white_gc;
16373 gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
16376 update_rect.x = x - 10 * pressure;
16377 update_rect.y = y - 10 * pressure;
16378 update_rect.width = 20 * pressure;
16379 update_rect.height = 20 * pressure;
16380 gdk_draw_rectangle (pixmap, gc, TRUE,
16381 update_rect.x, update_rect.y,
16382 update_rect.width, update_rect.height);
16383 gtk_widget_queue_draw_area (widget,
16384 update_rect.x, update_rect.y,
16385 update_rect.width, update_rect.height);
16389 print_button_press (GdkDevice *device)
16391 g_print ("Button press on device '%s'\n", device->name);
16395 button_press_event (GtkWidget *widget, GdkEventButton *event)
16397 print_button_press (event->device);
16399 if (event->button == 1 && pixmap != NULL) {
16401 gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_PRESSURE, &pressure);
16402 draw_brush (widget, event->device->source, event->x, event->y, pressure);
16409 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
16413 GdkModifierType state;
16415 if (event->is_hint)
16417 gdk_device_get_state (event->device, event->window, NULL, &state);
16418 gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_X, &x);
16419 gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_Y, &y);
16420 gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_PRESSURE, &pressure);
16426 gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_PRESSURE, &pressure);
16427 state = event->state;
16430 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
16431 draw_brush (widget, event->device->source, x, y, pressure);
16437 input_dialog_destroy (GtkWidget *w, gpointer data)
16439 *((GtkWidget **)data) = NULL;
16443 create_input_dialog ()
16445 static GtkWidget *inputd = NULL;
16449 inputd = gtk_input_dialog_new();
16451 g_signal_connect (G_OBJECT (inputd), "destroy",
16452 G_CALLBACK (input_dialog_destroy), &inputd);
16453 g_signal_connect_swapped (G_OBJECT (GTK_INPUT_DIALOG (inputd)->close_button),
16455 G_CALLBACK (gtk_widget_hide),
16457 gtk_widget_hide (GTK_INPUT_DIALOG (inputd)->save_button);
16459 gtk_widget_show (inputd);
16463 if (!GTK_WIDGET_MAPPED (inputd))
16464 gtk_widget_show (inputd);
16466 gdk_window_raise (inputd->window);
16477 main (int argc, char *argv[])
16480 GtkWidget *drawing_area;
16485 gtk_init (&argc, &argv);
16487 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
16488 gtk_widget_set_name (window, "Test Input");
16490 vbox = gtk_vbox_new (FALSE, 0);
16491 gtk_container_add (GTK_CONTAINER (window), vbox);
16492 gtk_widget_show (vbox);
16494 g_signal_connect (G_OBJECT (window), "destroy",
16495 G_CALLBACK (quit), NULL);
16497 /* Create the drawing area */
16499 drawing_area = gtk_drawing_area_new ();
16500 gtk_widget_set_size_request (GTK_WIDGET (drawing_area), 200, 200);
16501 gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
16503 gtk_widget_show (drawing_area);
16505 /* Signals used to handle backing pixmap */
16507 g_signal_connect (G_OBJECT (drawing_area), "expose_event",
16508 G_CALLBACK (expose_event), NULL);
16509 g_signal_connect (G_OBJECT(drawing_area),"configure_event",
16510 G_CALLBACK (configure_event), NULL);
16512 /* Event signals */
16514 g_signal_connect (G_OBJECT (drawing_area), "motion_notify_event",
16515 G_CALLBACK (motion_notify_event), NULL);
16516 g_signal_connect (G_OBJECT (drawing_area), "button_press_event",
16517 G_CALLBACK (button_press_event), NULL);
16519 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
16520 | GDK_LEAVE_NOTIFY_MASK
16521 | GDK_BUTTON_PRESS_MASK
16522 | GDK_POINTER_MOTION_MASK
16523 | GDK_POINTER_MOTION_HINT_MASK);
16525 /* The following call enables tracking and processing of extension
16526 events for the drawing area */
16527 gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
16529 /* .. And some buttons */
16530 button = gtk_button_new_with_label ("Input Dialog");
16531 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
16533 g_signal_connect (G_OBJECT (button), "clicked",
16534 G_CALLBACK (create_input_dialog), NULL);
16535 gtk_widget_show (button);
16537 button = gtk_button_new_with_label ("Quit");
16538 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
16540 g_signal_connect_swapped (G_OBJECT (button), "clicked",
16541 G_CALLBACK (gtk_widget_destroy),
16543 gtk_widget_show (button);
16545 gtk_widget_show (window);
16551 <!-- example-end -->