1 <!doctype linuxdoc system>
3 <!-- This is the tutorial marked up in SGML
4 (just to show how to write a comment)
8 <title>GTK v1.2 Tutorial
10 Tony Gale <tt><htmlurl url="mailto:gale@gtk.org"
11 name="<gale@gtk.org>"></tt>,
12 Ian Main <tt><htmlurl url="mailto:imain@gtk.org"
13 name="<imain@gtk.org>"></tt>
16 This is a tutorial on how to use GTK (the GIMP Toolkit) through its C
20 <!-- Table of contents -->
21 <!-- Older versions of this tutorial did not have a table of contents,
22 but the tutorial is now so large that having one is very useful. -->
26 <!-- ***************************************************************** -->
28 <!-- ***************************************************************** -->
30 GTK (GIMP Toolkit) is a library for creating graphical user
31 interfaces. It is licensed using the LGPL license, so you can develop
32 open software, free software, or even commercial non-free software
33 using GTK without having to spend anything for licenses or royalties.
35 It's called the GIMP toolkit because it was originally written for
36 developing the General Image Manipulation Program (GIMP), but GTK has
37 now been used in a large number of software projects, including the
38 GNU Network Object Model Environment (GNOME) project. GTK is built on
39 top of GDK (GIMP Drawing Kit) which is basically a wrapper around the
40 low-level functions for accessing the underlying windowing functions
41 (Xlib in the case of the X windows system). The primary authors of GTK
45 <item> Peter Mattis <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
46 name="petm@xcf.berkeley.edu"></tt>
47 <item> Spencer Kimball <tt><htmlurl url="mailto:spencer@xcf.berkeley.edu"
48 name="spencer@xcf.berkeley.edu"></tt>
49 <item> Josh MacDonald <tt><htmlurl url="mailto:jmacd@xcf.berkeley.edu"
50 name="jmacd@xcf.berkeley.edu"></tt>
53 GTK is essentially an object oriented application programmers
54 interface (API). Although written completely in C, it is implemented
55 using the idea of classes and callback functions (pointers to
58 There is also a third component called GLib which contains a few
59 replacements for some standard calls, as well as some additional
60 functions for handling linked lists, etc. The replacement functions
61 are used to increase GTK's portability, as some of the functions
62 implemented here are not available or are nonstandard on other unixes
63 such as g_strerror(). Some also contain enhancements to the libc
64 versions, such as g_malloc that has enhanced debugging utilities.
66 This tutorial describes the C interface to GTK. There are GTK
67 bindings for many other languages including C++, Guile, Perl, Python,
68 TOM, Ada95, Objective C, Free Pascal, and Eiffel. If you intend to
69 use another language's bindings to GTK, look at that binding's
70 documentation first. In some cases that documentation may describe
71 some important conventions (which you should know first) and then
72 refer you back to this tutorial. There are also some cross-platform
73 APIs (such as wxWindows and V) which use GTK as one of their target
74 platforms; again, consult their documentation first.
76 If you're developing your GTK application in C++, a few extra notes
77 are in order. There's a C++ binding to GTK called GTK--, which
78 provides a more C++-like interface to GTK; you should probably look
79 into this instead. If you don't like that approach for whatever
80 reason, there are two alternatives for using GTK. First, you can use
81 only the C subset of C++ when interfacing with GTK and then use the C
82 interface as described in this tutorial. Second, you can use GTK and
83 C++ together by declaring all callbacks as static functions in C++
84 classes, and again calling GTK using its C interface. If you choose
85 this last approach, you can include as the callback's data value a
86 pointer to the object to be manipulated (the so-called "this" value).
87 Selecting between these options is simply a matter of preference,
88 since in all three approaches you get C++ and GTK. None of these
89 approaches requires the use of a specialized preprocessor, so no
90 matter what you choose you can use standard C++ with GTK.
92 This tutorial is an attempt to document as much as possible of GTK,
93 but it is by no means complete. This tutorial assumes a good
94 understanding of C, and how to create C programs. It would be a great
95 benefit for the reader to have previous X programming experience, but
96 it shouldn't be necessary. If you are learning GTK as your first
97 widget set, please comment on how you found this tutorial, and what
98 you had trouble with. There are also C++, Objective C, ADA, Guile and
99 other language bindings available, but I don't follow these.
101 This document is a "work in progress". Please look for updates on
102 <htmlurl url="http://www.gtk.org/" name="http://www.gtk.org/">.
104 I would very much like to hear of any problems you have learning GTK
105 from this document, and would appreciate input as to how it may be
106 improved. Please see the section on <ref id="sec_Contributing"
107 name="Contributing"> for further information.
109 <!-- ***************************************************************** -->
110 <sect>Getting Started
111 <!-- ***************************************************************** -->
114 The first thing to do, of course, is download the GTK source and
115 install it. You can always get the latest version from ftp.gtk.org in
116 /pub/gtk. You can also view other sources of GTK information on
117 <htmlurl url="http://www.gtk.org/" name="http://www.gtk.org/">. GTK
118 uses GNU autoconf for configuration. Once untar'd, type ./configure
119 --help to see a list of options.
121 The GTK source distribution also contains the complete source to all
122 of the examples used in this tutorial, along with Makefiles to aid
125 To begin our introduction to GTK, we'll start with the simplest
126 program possible. This program will create a 200x200 pixel window and
127 has no way of exiting except to be killed by using the shell.
130 /* example-start base base.c */
139 gtk_init (&argc, &argv);
141 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
142 gtk_widget_show (window);
151 You can compile the above program with gcc using:
153 gcc base.c -o base `gtk-config --cflags --libs`
156 The meaning of the unusual compilation options is explained below in
157 <ref id="sec_compiling" name="Compiling Hello World">.
159 All programs will of course include gtk/gtk.h which declares the
160 variables, functions, structures, etc. that will be used in your GTK
166 gtk_init (&argc, &argv);
169 calls the function gtk_init(gint *argc, gchar ***argv) which will be
170 called in all GTK applications. This sets up a few things for us such
171 as the default visual and color map and then proceeds to call
172 gdk_init(gint *argc, gchar ***argv). This function initializes the
173 library for use, sets up default signal handlers, and checks the
174 arguments passed to your application on the command line, looking for
175 one of the following:
178 <item> <tt/--gtk-module/
179 <item> <tt/--g-fatal-warnings/
180 <item> <tt/--gtk-debug/
181 <item> <tt/--gtk-no-debug/
182 <item> <tt/--gdk-debug/
183 <item> <tt/--gdk-no-debug/
184 <item> <tt/--display/
186 <item> <tt/--no-xshm/
191 It removes these from the argument list, leaving anything it does not
192 recognize for your application to parse or ignore. This creates a set
193 of standard arguments accepted by all GTK applications.
195 The next two lines of code create and display a window.
198 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
199 gtk_widget_show (window);
202 The <tt/GTK_WINDOW_TOPLEVEL/ argument specifies that we want the
203 window to undergo window manager decoration and placement. Rather than
204 create a window of 0x0 size, a window without children is set to
205 200x200 by default so you can still manipulate it.
207 The gtk_widget_show() function lets GTK know that we are done setting
208 the attributes of this widget, and that it can display it.
210 The last line enters the GTK main processing loop.
216 gtk_main() is another call you will see in every GTK application.
217 When control reaches this point, GTK will sleep waiting for X events
218 (such as button or key presses), timeouts, or file IO notifications to
219 occur. In our simple example, however, events are ignored.
221 <!-- ----------------------------------------------------------------- -->
222 <sect1>Hello World in GTK
224 Now for a program with a widget (a button). It's the classic
225 hello world a la GTK.
228 /* example-start helloworld helloworld.c */
232 /* This is a callback function. The data arguments are ignored
233 * in this example. More on callbacks below. */
234 void hello( GtkWidget *widget,
237 g_print ("Hello World\n");
240 gint delete_event( GtkWidget *widget,
244 /* If you return FALSE in the "delete_event" signal handler,
245 * GTK will emit the "destroy" signal. Returning TRUE means
246 * you don't want the window to be destroyed.
247 * This is useful for popping up 'are you sure you want to quit?'
250 g_print ("delete event occurred\n");
252 /* Change TRUE to FALSE and the main window will be destroyed with
253 * a "delete_event". */
258 /* Another callback */
259 void destroy( GtkWidget *widget,
268 /* GtkWidget is the storage type for widgets */
272 /* This is called in all GTK applications. Arguments are parsed
273 * from the command line and are returned to the application. */
274 gtk_init(&argc, &argv);
276 /* create a new window */
277 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
279 /* When the window is given the "delete_event" signal (this is given
280 * by the window manager, usually by the "close" option, or on the
281 * titlebar), we ask it to call the delete_event () function
282 * as defined above. The data passed to the callback
283 * function is NULL and is ignored in the callback function. */
284 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
285 GTK_SIGNAL_FUNC (delete_event), NULL);
287 /* Here we connect the "destroy" event to a signal handler.
288 * This event occurs when we call gtk_widget_destroy() on the window,
289 * or if we return FALSE in the "delete_event" callback. */
290 gtk_signal_connect (GTK_OBJECT (window), "destroy",
291 GTK_SIGNAL_FUNC (destroy), NULL);
293 /* Sets the border width of the window. */
294 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
296 /* Creates a new button with the label "Hello World". */
297 button = gtk_button_new_with_label ("Hello World");
299 /* When the button receives the "clicked" signal, it will call the
300 * function hello() passing it NULL as its argument. The hello()
301 * function is defined above. */
302 gtk_signal_connect (GTK_OBJECT (button), "clicked",
303 GTK_SIGNAL_FUNC (hello), NULL);
305 /* This will cause the window to be destroyed by calling
306 * gtk_widget_destroy(window) when "clicked". Again, the destroy
307 * signal could come from here, or the window manager. */
308 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
309 GTK_SIGNAL_FUNC (gtk_widget_destroy),
310 GTK_OBJECT (window));
312 /* This packs the button into the window (a gtk container). */
313 gtk_container_add (GTK_CONTAINER (window), button);
315 /* The final step is to display this newly created widget. */
316 gtk_widget_show (button);
319 gtk_widget_show (window);
321 /* All GTK applications must have a gtk_main(). Control ends here
322 * and waits for an event to occur (like a key press or
331 <!-- ----------------------------------------------------------------- -->
332 <sect1>Compiling Hello World <label id="sec_compiling">
337 gcc -Wall -g helloworld.c -o helloworld `gtk-config --cflags` \
341 This uses the program <tt/gtk-config/, which comes with GTK. This
342 program "knows" what compiler switches are needed to compile programs
343 that use GTK. <tt/gtk-config --cflags/ will output a list of include
344 directories for the compiler to look in, and <tt>gtk-config --libs</>
345 will output the list of libraries for the compiler to link with and
346 the directories to find them in. In the aboce example they could have
347 been combined into a single instance, such as
348 <tt/`gtk-config --cflags --libs`/.
350 Note that the type of single quote used in the compile command above
353 The libraries that are usually linked in are:
355 <item>The GTK library (-lgtk), the widget library, based on top of GDK.
356 <item>The GDK library (-lgdk), the Xlib wrapper.
357 <item>The gmodule library (-lgmodule), which is used to load run time
359 <item>The GLib library (-lglib), containing miscellaneous functions;
360 only g_print() is used in this particular example. GTK is built on top
361 of glib so you will always require this library. See the section on
362 <ref id="sec_glib" name="GLib"> for details.
363 <item>The Xlib library (-lX11) which is used by GDK.
364 <item>The Xext library (-lXext). This contains code for shared memory
365 pixmaps and other X extensions.
366 <item>The math library (-lm). This is used by GTK for various purposes.
369 <!-- ----------------------------------------------------------------- -->
370 <sect1>Theory of Signals and Callbacks
372 Before we look in detail at <em>helloworld</em>, we'll discuss signals
373 and callbacks. GTK is an event driven toolkit, which means it will
374 sleep in gtk_main until an event occurs and control is passed to the
375 appropriate function.
377 This passing of control is done using the idea of "signals". (Note
378 that these signals are not the same as the Unix system signals, and
379 are not implemented using them, although the terminology is almost
380 identical.) When an event occurs, such as the press of a mouse button,
381 the appropriate signal will be "emitted" by the widget that was
382 pressed. This is how GTK does most of its useful work. There are
383 signals that all widgets inherit, such as "destroy", and there are
384 signals that are widget specific, such as "toggled" on a toggle
387 To make a button perform an action, we set up a signal handler to
388 catch these signals and call the appropriate function. This is done by
389 using a function such as:
392 gint gtk_signal_connect( GtkObject *object,
395 gpointer func_data );
398 where the first argument is the widget which will be emitting the
399 signal, and the second the name of the signal you wish to catch. The
400 third is the function you wish to be called when it is caught, and the
401 fourth, the data you wish to have passed to this function.
403 The function specified in the third argument is called a "callback
404 function", and should generally be of the form
407 void callback_func( GtkWidget *widget,
408 gpointer callback_data );
411 where the first argument will be a pointer to the widget that emitted
412 the signal, and the second a pointer to the data given as the last
413 argument to the gtk_signal_connect() function as shown above.
415 Note that the above form for a signal callback function declaration is
416 only a general guide, as some widget specific signals generate
417 different calling parameters. For example, the CList "select_row"
418 signal provides both row and column parameters.
420 Another call used in the <em>helloworld</em> example, is:
423 gint gtk_signal_connect_object( GtkObject *object,
426 GtkObject *slot_object );
429 gtk_signal_connect_object() is the same as gtk_signal_connect() except
430 that the callback function only uses one argument, a pointer to a GTK
431 object. So when using this function to connect signals, the callback
432 should be of the form
435 void callback_func( GtkObject *object );
438 where the object is usually a widget. We usually don't setup callbacks
439 for gtk_signal_connect_object however. They are usually used to call a
440 GTK function that accepts a single widget or object as an argument, as
441 is the case in our <em>helloworld</em> example.
443 The purpose of having two functions to connect signals is simply to
444 allow the callbacks to have a different number of arguments. Many
445 functions in the GTK library accept only a single GtkWidget pointer as
446 an argument, so you want to use the gtk_signal_connect_object() for
447 these, whereas for your functions, you may need to have additional
448 data supplied to the callbacks.
450 <!-- ----------------------------------------------------------------- -->
453 In addition to the signal mechanism described above, there is a set
454 of <em>events</em> that reflect the X event mechanism. Callbacks may
455 also be attached to these events. These events are:
459 <item> button_press_event
460 <item> button_release_event
461 <item> motion_notify_event
465 <item> key_press_event
466 <item> key_release_event
467 <item> enter_notify_event
468 <item> leave_notify_event
469 <item> configure_event
470 <item> focus_in_event
471 <item> focus_out_event
474 <item> property_notify_event
475 <item> selection_clear_event
476 <item> selection_request_event
477 <item> selection_notify_event
478 <item> proximity_in_event
479 <item> proximity_out_event
480 <item> drag_begin_event
481 <item> drag_request_event
482 <item> drag_end_event
483 <item> drop_enter_event
484 <item> drop_leave_event
485 <item> drop_data_available_event
489 In order to connect a callback function to one of these events, you
490 use the function gtk_signal_connect, as described above, using one of
491 the above event names as the <tt/name/ parameter. The callback
492 function for events has a slightly different form than that for
496 void callback_func( GtkWidget *widget,
498 gpointer callback_data );
501 GdkEvent is a C <tt/union/ structure whose type will depend upon which
502 of the above events has occurred. In order for us to tell which event
503 has been issued each of the possible alternatives has a <tt/type/
504 parameter which reflects the event being issued. The other components
505 of the event structure will depend upon the type of the
506 event. Possible values for the type are:
528 GDK_SELECTION_REQUEST
538 GDK_VISIBILITY_NOTIFY
540 GDK_OTHER_EVENT /* Deprecated, use filters instead */
543 So, to connect a callback function to one of these events we would use
547 gtk_signal_connect( GTK_OBJECT(button), "button_press_event",
548 GTK_SIGNAL_FUNC(button_press_callback),
552 This assumes that <tt/button/ is a Button widget. Now, when the
553 mouse is over the button and a mouse button is pressed, the function
554 <tt/button_press_callback/ will be called. This function may be
558 static gint button_press_callback( GtkWidget *widget,
559 GdkEventButton *event,
563 Note that we can declare the second argument as type
564 <tt/GdkEventButton/ as we know what type of event will occur for this
565 function to be called.
567 The value returned from this function indicates whether the event
568 should be propagated further by the GTK event handling
569 mechanism. Returning TRUE indicates that the event has been handled,
570 and that it should not propagate further. Returning FALSE continues
571 the normal event handling. See the section on
572 <ref id="sec_Adv_Events_and_Signals"
573 name="Advanced Event and Signal Handling"> for more details on this
576 For details on the GdkEvent data types, see the appendix entitled
577 <ref id="sec_GDK_Event_Types" name="GDK Event Types">.
579 <!-- ----------------------------------------------------------------- -->
580 <sect1>Stepping Through Hello World
582 Now that we know the theory behind this, let's clarify by walking
583 through the example <em>helloworld</em> program.
585 Here is the callback function that will be called when the button is
586 "clicked". We ignore both the widget and the data in this example, but
587 it is not hard to do things with them. The next example will use the
588 data argument to tell us which button was pressed.
591 void hello( GtkWidget *widget,
594 g_print ("Hello World\n");
598 The next callback is a bit special. The "delete_event" occurs when the
599 window manager sends this event to the application. We have a choice
600 here as to what to do about these events. We can ignore them, make
601 some sort of response, or simply quit the application.
603 The value you return in this callback lets GTK know what action to
604 take. By returning TRUE, we let it know that we don't want to have
605 the "destroy" signal emitted, keeping our application running. By
606 returning FALSE, we ask that "destroy" be emitted, which in turn will
607 call our "destroy" signal handler.
610 gint delete_event( GtkWidget *widget,
614 g_print ("delete event occurred\n");
620 Here is another callback function which causes the program to quit by
621 calling gtk_main_quit(). This function tells GTK that it is to exit
622 from gtk_main when control is returned to it.
625 void destroy( GtkWidget *widget,
632 I assume you know about the main() function... yes, as with other
633 applications, all GTK applications will also have one of these.
641 This next part declares pointers to a structure of type
642 GtkWidget. These are used below to create a window and a button.
649 Here is our gtk_init again. As before, this initializes the toolkit,
650 and parses the arguments found on the command line. Any argument it
651 recognizes from the command line, it removes from the list, and
652 modifies argc and argv to make it look like they never existed,
653 allowing your application to parse the remaining arguments.
656 gtk_init (&argc, &argv);
659 Create a new window. This is fairly straightforward. Memory is
660 allocated for the GtkWidget *window structure so it now points to a
661 valid structure. It sets up a new window, but it is not displayed
662 until we call gtk_widget_show(window) near the end of our program.
665 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
668 Here are two examples of connecting a signal handler to an object, in
669 this case, the window. Here, the "delete_event" and "destroy" signals
670 are caught. The first is emitted when we use the window manager to
671 kill the window, or when we use the gtk_widget_destroy() call passing
672 in the window widget as the object to destroy. The second is emitted
673 when, in the "delete_event" handler, we return FALSE.
675 The <tt/GTK_OBJECT/ and <tt/GTK_SIGNAL_FUNC/ are macros that perform
676 type casting and checking for us, as well as aid the readability of
680 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
681 GTK_SIGNAL_FUNC (delete_event), NULL);
682 gtk_signal_connect (GTK_OBJECT (window), "destroy",
683 GTK_SIGNAL_FUNC (destroy), NULL);
686 This next function is used to set an attribute of a container object.
687 This just sets the window so it has a blank area along the inside of
688 it 10 pixels wide where no widgets will go. There are other similar
689 functions which we will look at in the section on
690 <ref id="sec_setting_widget_attributes" name="Setting Widget Attributes">
692 And again, <tt/GTK_CONTAINER/ is a macro to perform type casting.
695 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
698 This call creates a new button. It allocates space for a new GtkWidget
699 structure in memory, initializes it, and makes the button pointer
700 point to it. It will have the label "Hello World" on it when
704 button = gtk_button_new_with_label ("Hello World");
707 Here, we take this button, and make it do something useful. We attach
708 a signal handler to it so when it emits the "clicked" signal, our
709 hello() function is called. The data is ignored, so we simply pass in
710 NULL to the hello() callback function. Obviously, the "clicked" signal
711 is emitted when we click the button with our mouse pointer.
714 gtk_signal_connect (GTK_OBJECT (button), "clicked",
715 GTK_SIGNAL_FUNC (hello), NULL);
718 We are also going to use this button to exit our program. This will
719 illustrate how the "destroy" signal may come from either the window
720 manager, or our program. When the button is "clicked", same as above,
721 it calls the first hello() callback function, and then this one in the
722 order they are set up. You may have as many callback functions as you
723 need, and all will be executed in the order you connected
724 them. Because the gtk_widget_destroy() function accepts only a
725 GtkWidget *widget as an argument, we use the
726 gtk_signal_connect_object() function here instead of straight
727 gtk_signal_connect().
730 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
731 GTK_SIGNAL_FUNC (gtk_widget_destroy),
732 GTK_OBJECT (window));
735 This is a packing call, which will be explained in depth later on in
736 <ref id="sec_packing_widgets" name="Packing Widgets">. But it is
737 fairly easy to understand. It simply tells GTK that the button is to
738 be placed in the window where it will be displayed. Note that a GTK
739 container can only contain one widget. There are other widgets, that
740 are described later, which are designed to layout multiple widgets in
744 gtk_container_add (GTK_CONTAINER (window), button);
747 Now we have everything set up the way we want it to be. With all the
748 signal handlers in place, and the button placed in the window where it
749 should be, we ask GTK to "show" the widgets on the screen. The window
750 widget is shown last so the whole window will pop up at once rather
751 than seeing the window pop up, and then the button form inside of
752 it. Although with such a simple example, you'd never notice.
755 gtk_widget_show (button);
757 gtk_widget_show (window);
760 And of course, we call gtk_main() which waits for events to come from
761 the X server and will call on the widgets to emit signals when these
768 And the final return. Control returns here after gtk_quit() is called.
774 Now, when we click the mouse button on a GTK button, the widget emits
775 a "clicked" signal. In order for us to use this information, our
776 program sets up a signal handler to catch that signal, which
777 dispatches the function of our choice. In our example, when the button
778 we created is "clicked", the hello() function is called with a NULL
779 argument, and then the next handler for this signal is called. This
780 calls the gtk_widget_destroy() function, passing it the window widget
781 as its argument, destroying the window widget. This causes the window
782 to emit the "destroy" signal, which is caught, and calls our destroy()
783 callback function, which simply exits GTK.
785 Another course of events is to use the window manager to kill the
786 window, which will cause the "delete_event" to be emitted. This will
787 call our "delete_event" handler. If we return TRUE here, the window
788 will be left as is and nothing will happen. Returning FALSE will cause
789 GTK to emit the "destroy" signal which of course calls the "destroy"
790 callback, exiting GTK.
792 <!-- ***************************************************************** -->
794 <!-- ***************************************************************** -->
796 <!-- ----------------------------------------------------------------- -->
799 There are a few things you probably noticed in the previous examples
800 that need explaining. The gint, gchar, etc. that you see are typedefs
801 to int and char, respectively, that are part of the GLlib system. This
802 is done to get around that nasty dependency on the size of simple data
803 types when doing calculations.
805 A good example is "gint32" which will be typedef'd to a 32 bit integer
806 for any given platform, whether it be the 64 bit alpha, or the 32 bit
807 i386. The typedefs are very straightforward and intuitive. They are
808 all defined in glib/glib.h (which gets included from gtk.h).
810 You'll also notice GTK's ability to use GtkWidget when the function
811 calls for an Object. GTK is an object oriented design, and a widget
814 <!-- ----------------------------------------------------------------- -->
815 <sect1>More on Signal Handlers
817 Lets take another look at the gtk_signal_connect declaration.
820 gint gtk_signal_connect( GtkObject *object,
823 gpointer func_data );
826 Notice the gint return value? This is a tag that identifies your
827 callback function. As stated above, you may have as many callbacks per
828 signal and per object as you need, and each will be executed in turn,
829 in the order they were attached.
831 This tag allows you to remove this callback from the list by using:
834 void gtk_signal_disconnect( GtkObject *object,
838 So, by passing in the widget you wish to remove the handler from, and
839 the tag returned by one of the signal_connect functions, you can
840 disconnect a signal handler.
842 Another function to remove all the signal handers from an object is:
845 void gtk_signal_handlers_destroy( GtkObject *object );
848 This call is fairly self explanatory. It simply removes all the
849 current signal handlers from the object passed in as the first
852 <!-- ----------------------------------------------------------------- -->
853 <sect1>An Upgraded Hello World
855 Let's take a look at a slightly improved <em>helloworld</em> with
856 better examples of callbacks. This will also introduce us to our next
857 topic, packing widgets.
860 /* example-start helloworld2 helloworld2.c */
864 /* Our new improved callback. The data passed to this function
865 * is printed to stdout. */
866 void callback( GtkWidget *widget,
869 g_print ("Hello again - %s was pressed\n", (char *) data);
872 /* another callback */
873 void delete_event( GtkWidget *widget,
883 /* GtkWidget is the storage type for widgets */
888 /* This is called in all GTK applications. Arguments are parsed
889 * from the command line and are returned to the application. */
890 gtk_init (&argc, &argv);
892 /* Create a new window */
893 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
895 /* This is a new call, which just sets the title of our
896 * new window to "Hello Buttons!" */
897 gtk_window_set_title (GTK_WINDOW (window), "Hello Buttons!");
899 /* Here we just set a handler for delete_event that immediately
901 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
902 GTK_SIGNAL_FUNC (delete_event), NULL);
904 /* Sets the border width of the window. */
905 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
907 /* We create a box to pack widgets into. This is described in detail
908 * in the "packing" section. The box is not really visible, it
909 * is just used as a tool to arrange widgets. */
910 box1 = gtk_hbox_new(FALSE, 0);
912 /* Put the box into the main window. */
913 gtk_container_add (GTK_CONTAINER (window), box1);
915 /* Creates a new button with the label "Button 1". */
916 button = gtk_button_new_with_label ("Button 1");
918 /* Now when the button is clicked, we call the "callback" function
919 * with a pointer to "button 1" as its argument */
920 gtk_signal_connect (GTK_OBJECT (button), "clicked",
921 GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");
923 /* Instead of gtk_container_add, we pack this button into the invisible
924 * box, which has been packed into the window. */
925 gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
927 /* Always remember this step, this tells GTK that our preparation for
928 * this button is complete, and it can now be displayed. */
929 gtk_widget_show(button);
931 /* Do these same steps again to create a second button */
932 button = gtk_button_new_with_label ("Button 2");
934 /* Call the same callback function with a different argument,
935 * passing a pointer to "button 2" instead. */
936 gtk_signal_connect (GTK_OBJECT (button), "clicked",
937 GTK_SIGNAL_FUNC (callback), (gpointer) "button 2");
939 gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
941 /* The order in which we show the buttons is not really important, but I
942 * recommend showing the window last, so it all pops up at once. */
943 gtk_widget_show(button);
945 gtk_widget_show(box1);
947 gtk_widget_show (window);
949 /* Rest in gtk_main and wait for the fun to begin! */
957 Compile this program using the same linking arguments as our first
958 example. You'll notice this time there is no easy way to exit the
959 program, you have to use your window manager or command line to kill
960 it. A good exercise for the reader would be to insert a third "Quit"
961 button that will exit the program. You may also wish to play with the
962 options to gtk_box_pack_start() while reading the next section. Try
963 resizing the window, and observe the behavior.
965 Just as a side note, there is another useful define for
966 gtk_window_new() - <tt/GTK_WINDOW_DIALOG/. This interacts with the
967 window manager a little differently and should be used for transient
970 <!-- ***************************************************************** -->
971 <sect>Packing Widgets <label id="sec_packing_widgets">
972 <!-- ***************************************************************** -->
974 When creating an application, you'll want to put more than one widget
975 inside a window. Our first <em>helloworld</em> example only used one
976 widget so we could simply use a gtk_container_add call to "pack" the
977 widget into the window. But when you want to put more than one widget
978 into a window, how do you control where that widget is positioned?
979 This is where packing comes in.
981 <!-- ----------------------------------------------------------------- -->
982 <sect1>Theory of Packing Boxes
984 Most packing is done by creating boxes as in the example above. These
985 are invisible widget containers that we can pack our widgets into
986 which come in two forms, a horizontal box, and a vertical box. When
987 packing widgets into a horizontal box, the objects are inserted
988 horizontally from left to right or right to left depending on the call
989 used. In a vertical box, widgets are packed from top to bottom or vice
990 versa. You may use any combination of boxes inside or beside other
991 boxes to create the desired effect.
993 To create a new horizontal box, we use a call to gtk_hbox_new(), and
994 for vertical boxes, gtk_vbox_new(). The gtk_box_pack_start() and
995 gtk_box_pack_end() functions are used to place objects inside of these
996 containers. The gtk_box_pack_start() function will start at the top
997 and work its way down in a vbox, and pack left to right in an hbox.
998 gtk_box_pack_end() will do the opposite, packing from bottom to top in
999 a vbox, and right to left in an hbox. Using these functions allows us
1000 to right justify or left justify our widgets and may be mixed in any
1001 way to achieve the desired effect. We will use gtk_box_pack_start() in
1002 most of our examples. An object may be another container or a
1003 widget. In fact, many widgets are actually containers themselves,
1004 including the button, but we usually only use a label inside a button.
1006 By using these calls, GTK knows where you want to place your widgets
1007 so it can do automatic resizing and other nifty things. There are also
1008 a number of options as to how your widgets should be packed. As you
1009 can imagine, this method gives us a quite a bit of flexibility when
1010 placing and creating widgets.
1012 <!-- ----------------------------------------------------------------- -->
1013 <sect1>Details of Boxes
1015 Because of this flexibility, packing boxes in GTK can be confusing at
1016 first. There are a lot of options, and it's not immediately obvious how
1017 they all fit together. In the end, however, there are basically five
1022 <IMG SRC="gtk_tut_packbox1.gif" VSPACE="15" HSPACE="10" WIDTH="528"
1023 HEIGHT="235" ALT="Box Packing Example Image">
1027 Each line contains one horizontal box (hbox) with several buttons. The
1028 call to gtk_box_pack is shorthand for the call to pack each of the
1029 buttons into the hbox. Each of the buttons is packed into the hbox the
1030 same way (i.e., same arguments to the gtk_box_pack_start() function).
1032 This is the declaration of the gtk_box_pack_start function.
1035 void gtk_box_pack_start( GtkBox *box,
1042 The first argument is the box you are packing the object into, the
1043 second is the object. The objects will all be buttons for now, so
1044 we'll be packing buttons into boxes.
1046 The expand argument to gtk_box_pack_start() and gtk_box_pack_end()
1047 controls whether the widgets are laid out in the box to fill in all
1048 the extra space in the box so the box is expanded to fill the area
1049 allotted to it (TRUE); or the box is shrunk to just fit the widgets
1050 (FALSE). Setting expand to FALSE will allow you to do right and left
1051 justification of your widgets. Otherwise, they will all expand to fit
1052 into the box, and the same effect could be achieved by using only one
1053 of gtk_box_pack_start or gtk_box_pack_end.
1055 The fill argument to the gtk_box_pack functions control whether the
1056 extra space is allocated to the objects themselves (TRUE), or as extra
1057 padding in the box around these objects (FALSE). It only has an effect
1058 if the expand argument is also TRUE.
1060 When creating a new box, the function looks like this:
1063 GtkWidget *gtk_hbox_new (gint homogeneous,
1067 The homogeneous argument to gtk_hbox_new (and the same for
1068 gtk_vbox_new) controls whether each object in the box has the same
1069 size (i.e., the same width in an hbox, or the same height in a
1070 vbox). If it is set, the gtk_box_pack routines function essentially
1071 as if the <tt/expand/ argument was always turned on.
1073 What's the difference between spacing (set when the box is created)
1074 and padding (set when elements are packed)? Spacing is added between
1075 objects, and padding is added on either side of an object. The
1076 following figure should make it clearer:
1080 <IMG ALIGN="center" SRC="gtk_tut_packbox2.gif" WIDTH="509"
1081 HEIGHT="213" VSPACE="15" HSPACE="10"
1082 ALT="Box Packing Example Image">
1086 Here is the code used to create the above images. I've commented it
1087 fairly heavily so I hope you won't have any problems following
1088 it. Compile it yourself and play with it.
1090 <!-- ----------------------------------------------------------------- -->
1091 <sect1>Packing Demonstration Program
1094 /* example-start packbox packbox.c */
1097 #include "gtk/gtk.h"
1099 void delete_event( GtkWidget *widget,
1106 /* Make a new hbox filled with button-labels. Arguments for the
1107 * variables we're interested are passed in to this function.
1108 * We do not show the box, but do show everything inside. */
1109 GtkWidget *make_box( gint homogeneous,
1119 /* Create a new hbox with the appropriate homogeneous
1120 * and spacing settings */
1121 box = gtk_hbox_new (homogeneous, spacing);
1123 /* Create a series of buttons with the appropriate settings */
1124 button = gtk_button_new_with_label ("gtk_box_pack");
1125 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1126 gtk_widget_show (button);
1128 button = gtk_button_new_with_label ("(box,");
1129 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1130 gtk_widget_show (button);
1132 button = gtk_button_new_with_label ("button,");
1133 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1134 gtk_widget_show (button);
1136 /* Create a button with the label depending on the value of
1139 button = gtk_button_new_with_label ("TRUE,");
1141 button = gtk_button_new_with_label ("FALSE,");
1143 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1144 gtk_widget_show (button);
1146 /* This is the same as the button creation for "expand"
1147 * above, but uses the shorthand form. */
1148 button = gtk_button_new_with_label (fill ? "TRUE," : "FALSE,");
1149 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1150 gtk_widget_show (button);
1152 sprintf (padstr, "%d);", padding);
1154 button = gtk_button_new_with_label (padstr);
1155 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1156 gtk_widget_show (button);
1168 GtkWidget *separator;
1173 /* Our init, don't forget this! :) */
1174 gtk_init (&argc, &argv);
1177 fprintf (stderr, "usage: packbox num, where num is 1, 2, or 3.\n");
1178 /* This just does cleanup in GTK and exits with an exit status of 1. */
1182 which = atoi (argv[1]);
1184 /* Create our window */
1185 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1187 /* You should always remember to connect the delete_event signal
1188 * to the main window. This is very important for proper intuitive
1190 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
1191 GTK_SIGNAL_FUNC (delete_event), NULL);
1192 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
1194 /* We create a vertical box (vbox) to pack the horizontal boxes into.
1195 * This allows us to stack the horizontal boxes filled with buttons one
1196 * on top of the other in this vbox. */
1197 box1 = gtk_vbox_new (FALSE, 0);
1199 /* which example to show. These correspond to the pictures above. */
1202 /* create a new label. */
1203 label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1205 /* Align the label to the left side. We'll discuss this function and
1206 * others in the section on Widget Attributes. */
1207 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1209 /* Pack the label into the vertical box (vbox box1). Remember that
1210 * widgets added to a vbox will be packed one on top of the other in
1212 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1214 /* Show the label */
1215 gtk_widget_show (label);
1217 /* Call our make box function - homogeneous = FALSE, spacing = 0,
1218 * expand = FALSE, fill = FALSE, padding = 0 */
1219 box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1220 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1221 gtk_widget_show (box2);
1223 /* Call our make box function - homogeneous = FALSE, spacing = 0,
1224 * expand = FALSE, fill = FALSE, padding = 0 */
1225 box2 = make_box (FALSE, 0, TRUE, FALSE, 0);
1226 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1227 gtk_widget_show (box2);
1229 /* Args are: homogeneous, spacing, expand, fill, padding */
1230 box2 = make_box (FALSE, 0, TRUE, TRUE, 0);
1231 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1232 gtk_widget_show (box2);
1234 /* Creates a separator, we'll learn more about these later,
1235 * but they are quite simple. */
1236 separator = gtk_hseparator_new ();
1238 /* Pack the separator into the vbox. Remember each of these
1239 * widgets is being packed into a vbox, so they'll be stacked
1241 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1242 gtk_widget_show (separator);
1244 /* Create another new label, and show it. */
1245 label = gtk_label_new ("gtk_hbox_new (TRUE, 0);");
1246 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1247 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1248 gtk_widget_show (label);
1250 /* Args are: homogeneous, spacing, expand, fill, padding */
1251 box2 = make_box (TRUE, 0, TRUE, FALSE, 0);
1252 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1253 gtk_widget_show (box2);
1255 /* Args are: homogeneous, spacing, expand, fill, padding */
1256 box2 = make_box (TRUE, 0, TRUE, TRUE, 0);
1257 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1258 gtk_widget_show (box2);
1260 /* Another new separator. */
1261 separator = gtk_hseparator_new ();
1262 /* The last 3 arguments to gtk_box_pack_start are:
1263 * expand, fill, padding. */
1264 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1265 gtk_widget_show (separator);
1271 /* Create a new label, remember box1 is a vbox as created
1272 * near the beginning of main() */
1273 label = gtk_label_new ("gtk_hbox_new (FALSE, 10);");
1274 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1275 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1276 gtk_widget_show (label);
1278 /* Args are: homogeneous, spacing, expand, fill, padding */
1279 box2 = make_box (FALSE, 10, TRUE, FALSE, 0);
1280 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1281 gtk_widget_show (box2);
1283 /* Args are: homogeneous, spacing, expand, fill, padding */
1284 box2 = make_box (FALSE, 10, TRUE, TRUE, 0);
1285 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1286 gtk_widget_show (box2);
1288 separator = gtk_hseparator_new ();
1289 /* The last 3 arguments to gtk_box_pack_start are:
1290 * expand, fill, padding. */
1291 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1292 gtk_widget_show (separator);
1294 label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1295 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1296 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1297 gtk_widget_show (label);
1299 /* Args are: homogeneous, spacing, expand, fill, padding */
1300 box2 = make_box (FALSE, 0, TRUE, FALSE, 10);
1301 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1302 gtk_widget_show (box2);
1304 /* Args are: homogeneous, spacing, expand, fill, padding */
1305 box2 = make_box (FALSE, 0, TRUE, TRUE, 10);
1306 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1307 gtk_widget_show (box2);
1309 separator = gtk_hseparator_new ();
1310 /* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */
1311 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1312 gtk_widget_show (separator);
1317 /* This demonstrates the ability to use gtk_box_pack_end() to
1318 * right justify widgets. First, we create a new box as before. */
1319 box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1321 /* Create the label that will be put at the end. */
1322 label = gtk_label_new ("end");
1323 /* Pack it using gtk_box_pack_end(), so it is put on the right
1324 * side of the hbox created in the make_box() call. */
1325 gtk_box_pack_end (GTK_BOX (box2), label, FALSE, FALSE, 0);
1326 /* Show the label. */
1327 gtk_widget_show (label);
1329 /* Pack box2 into box1 (the vbox remember ? :) */
1330 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1331 gtk_widget_show (box2);
1333 /* A separator for the bottom. */
1334 separator = gtk_hseparator_new ();
1335 /* This explicitly sets the separator to 400 pixels wide by 5 pixels
1336 * high. This is so the hbox we created will also be 400 pixels wide,
1337 * and the "end" label will be separated from the other labels in the
1338 * hbox. Otherwise, all the widgets in the hbox would be packed as
1339 * close together as possible. */
1340 gtk_widget_set_usize (separator, 400, 5);
1341 /* pack the separator into the vbox (box1) created near the start
1343 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1344 gtk_widget_show (separator);
1347 /* Create another new hbox.. remember we can use as many as we need! */
1348 quitbox = gtk_hbox_new (FALSE, 0);
1350 /* Our quit button. */
1351 button = gtk_button_new_with_label ("Quit");
1353 /* Setup the signal to terminate the program when the button is clicked */
1354 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
1355 GTK_SIGNAL_FUNC (gtk_main_quit),
1356 GTK_OBJECT (window));
1357 /* Pack the button into the quitbox.
1358 * The last 3 arguments to gtk_box_pack_start are:
1359 * expand, fill, padding. */
1360 gtk_box_pack_start (GTK_BOX (quitbox), button, TRUE, FALSE, 0);
1361 /* pack the quitbox into the vbox (box1) */
1362 gtk_box_pack_start (GTK_BOX (box1), quitbox, FALSE, FALSE, 0);
1364 /* Pack the vbox (box1) which now contains all our widgets, into the
1366 gtk_container_add (GTK_CONTAINER (window), box1);
1368 /* And show everything left */
1369 gtk_widget_show (button);
1370 gtk_widget_show (quitbox);
1372 gtk_widget_show (box1);
1373 /* Showing the window last so everything pops up at once. */
1374 gtk_widget_show (window);
1376 /* And of course, our main function. */
1379 /* Control returns here when gtk_main_quit() is called, but not when
1380 * gtk_exit is used. */
1387 <!-- ----------------------------------------------------------------- -->
1388 <sect1>Packing Using Tables
1390 Let's take a look at another way of packing - Tables. These can be
1391 extremely useful in certain situations.
1393 Using tables, we create a grid that we can place widgets in. The
1394 widgets may take up as many spaces as we specify.
1396 The first thing to look at, of course, is the gtk_table_new function:
1399 GtkWidget *gtk_table_new( gint rows,
1404 The first argument is the number of rows to make in the table, while
1405 the second, obviously, is the number of columns.
1407 The homogeneous argument has to do with how the table's boxes are
1408 sized. If homogeneous is TRUE, the table boxes are resized to the size
1409 of the largest widget in the table. If homogeneous is FALSE, the size
1410 of a table boxes is dictated by the tallest widget in its same row,
1411 and the widest widget in its column.
1413 The rows and columns are laid out from 0 to n, where n was the number
1414 specified in the call to gtk_table_new. So, if you specify rows = 2
1415 and columns = 2, the layout would look something like this:
1419 0+----------+----------+
1421 1+----------+----------+
1423 2+----------+----------+
1426 Note that the coordinate system starts in the upper left hand corner.
1427 To place a widget into a box, use the following function:
1430 void gtk_table_attach( GtkTable *table,
1442 The first argument ("table") is the table you've created and the
1443 second ("child") the widget you wish to place in the table.
1445 The left and right attach arguments specify where to place the widget,
1446 and how many boxes to use. If you want a button in the lower right
1447 table entry of our 2x2 table, and want it to fill that entry ONLY,
1448 left_attach would be = 1, right_attach = 2, top_attach = 1,
1451 Now, if you wanted a widget to take up the whole top row of our 2x2
1452 table, you'd use left_attach = 0, right_attach = 2, top_attach = 0,
1455 The xoptions and yoptions are used to specify packing options and may
1456 be bitwise OR'ed together to allow multiple options.
1460 <item><tt/GTK_FILL/ - If the table box is larger than the widget, and
1461 <tt/GTK_FILL/ is specified, the widget will expand to use all the room
1464 <item><tt/GTK_SHRINK/ - If the table widget was allocated less space
1465 then was requested (usually by the user resizing the window), then the
1466 widgets would normally just be pushed off the bottom of the window and
1467 disappear. If <tt/GTK_SHRINK/ is specified, the widgets will shrink
1470 <item><tt/GTK_EXPAND/ - This will cause the table to expand to use up
1471 any remaining space in the window.
1474 Padding is just like in boxes, creating a clear area around the widget
1475 specified in pixels.
1477 gtk_table_attach() has a LOT of options. So, there's a shortcut:
1480 void gtk_table_attach_defaults( GtkTable *table,
1485 gint bottom_attach );
1488 The X and Y options default to <tt/GTK_FILL | GTK_EXPAND/, and X and Y
1489 padding are set to 0. The rest of the arguments are identical to the
1492 We also have gtk_table_set_row_spacing() and
1493 gtk_table_set_col_spacing(). These places spacing between the rows at
1494 the specified row or column.
1497 void gtk_table_set_row_spacing( GtkTable *table,
1505 void gtk_table_set_col_spacing ( GtkTable *table,
1510 Note that for columns, the space goes to the right of the column, and
1511 for rows, the space goes below the row.
1513 You can also set a consistent spacing of all rows and/or columns with:
1516 void gtk_table_set_row_spacings( GtkTable *table,
1523 void gtk_table_set_col_spacings( GtkTable *table,
1527 Note that with these calls, the last row and last column do not get
1530 <!-- ----------------------------------------------------------------- -->
1531 <sect1>Table Packing Example
1533 Here we make a window with three buttons in a 2x2 table.
1534 The first two buttons will be placed in the upper row.
1535 A third, quit button, is placed in the lower row, spanning both columns.
1536 Which means it should look something like this:
1540 <IMG SRC="gtk_tut_table.gif" VSPACE="15" HSPACE="10"
1541 ALT="Table Packing Example Image" WIDTH="180" HEIGHT="120">
1545 Here's the source code:
1548 /* example-start table table.c */
1550 #include <gtk/gtk.h>
1553 * The data passed to this function is printed to stdout */
1554 void callback( GtkWidget *widget,
1557 g_print ("Hello again - %s was pressed\n", (char *) data);
1560 /* This callback quits the program */
1561 void delete_event( GtkWidget *widget,
1575 gtk_init (&argc, &argv);
1577 /* Create a new window */
1578 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1580 /* Set the window title */
1581 gtk_window_set_title (GTK_WINDOW (window), "Table");
1583 /* Set a handler for delete_event that immediately
1585 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
1586 GTK_SIGNAL_FUNC (delete_event), NULL);
1588 /* Sets the border width of the window. */
1589 gtk_container_set_border_width (GTK_CONTAINER (window), 20);
1591 /* Create a 2x2 table */
1592 table = gtk_table_new (2, 2, TRUE);
1594 /* Put the table in the main window */
1595 gtk_container_add (GTK_CONTAINER (window), table);
1597 /* Create first button */
1598 button = gtk_button_new_with_label ("button 1");
1600 /* When the button is clicked, we call the "callback" function
1601 * with a pointer to "button 1" as its argument */
1602 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1603 GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");
1606 /* Insert button 1 into the upper left quadrant of the table */
1607 gtk_table_attach_defaults (GTK_TABLE(table), button, 0, 1, 0, 1);
1609 gtk_widget_show (button);
1611 /* Create second button */
1613 button = gtk_button_new_with_label ("button 2");
1615 /* When the button is clicked, we call the "callback" function
1616 * with a pointer to "button 2" as its argument */
1617 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1618 GTK_SIGNAL_FUNC (callback), (gpointer) "button 2");
1619 /* Insert button 2 into the upper right quadrant of the table */
1620 gtk_table_attach_defaults (GTK_TABLE(table), button, 1, 2, 0, 1);
1622 gtk_widget_show (button);
1624 /* Create "Quit" button */
1625 button = gtk_button_new_with_label ("Quit");
1627 /* When the button is clicked, we call the "delete_event" function
1628 * and the program exits */
1629 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1630 GTK_SIGNAL_FUNC (delete_event), NULL);
1632 /* Insert the quit button into the both
1633 * lower quadrants of the table */
1634 gtk_table_attach_defaults (GTK_TABLE(table), button, 0, 2, 1, 2);
1636 gtk_widget_show (button);
1638 gtk_widget_show (table);
1639 gtk_widget_show (window);
1648 <!-- ***************************************************************** -->
1649 <sect>Widget Overview
1650 <!-- ***************************************************************** -->
1652 The general steps to creating a widget in GTK are:
1654 <item> gtk_*_new - one of various functions to create a new widget.
1655 These are all detailed in this section.
1657 <item> Connect all signals and events we wish to use to the
1658 appropriate handlers.
1660 <item> Set the attributes of the widget.
1662 <item> Pack the widget into a container using the appropriate call
1663 such as gtk_container_add() or gtk_box_pack_start().
1665 <item> gtk_widget_show() the widget.
1668 gtk_widget_show() lets GTK know that we are done setting the
1669 attributes of the widget, and it is ready to be displayed. You may
1670 also use gtk_widget_hide to make it disappear again. The order in
1671 which you show the widgets is not important, but I suggest showing the
1672 window last so the whole window pops up at once rather than seeing the
1673 individual widgets come up on the screen as they're formed. The
1674 children of a widget (a window is a widget too) will not be displayed
1675 until the window itself is shown using the gtk_widget_show() function.
1677 <!-- ----------------------------------------------------------------- -->
1680 You'll notice as you go on that GTK uses a type casting system. This
1681 is always done using macros that both test the ability to cast the
1682 given item, and perform the cast. Some common ones you will see are:
1687 GTK_SIGNAL_FUNC(function)
1688 GTK_CONTAINER(container)
1693 These are all used to cast arguments in functions. You'll see them in the
1694 examples, and can usually tell when to use them simply by looking at the
1695 function's declaration.
1697 As you can see below in the class hierarchy, all GtkWidgets are
1698 derived from the Object base class. This means you can use a widget
1699 in any place the function asks for an object - simply use the
1700 <tt/GTK_OBJECT()/ macro.
1705 gtk_signal_connect( GTK_OBJECT(button), "clicked",
1706 GTK_SIGNAL_FUNC(callback_function), callback_data);
1709 This casts the button into an object, and provides a cast for the
1710 function pointer to the callback.
1712 Many widgets are also containers. If you look in the class hierarchy
1713 below, you'll notice that many widgets derive from the Container
1714 class. Any one of these widgets may be used with the
1715 <tt/GTK_CONTAINER/ macro to pass them to functions that ask for
1718 Unfortunately, these macros are not extensively covered in the
1719 tutorial, but I recommend taking a look through the GTK header
1720 files. It can be very educational. In fact, it's not difficult to
1721 learn how a widget works just by looking at the function declarations.
1723 <!-- ----------------------------------------------------------------- -->
1724 <sect1>Widget Hierarchy
1726 For your reference, here is the class hierarchy tree used to implement widgets.
1733 | | | +GtkAccelLabel
1742 | | | | `GtkAspectFrame
1744 | | | | +GtkToggleButton
1745 | | | | | `GtkCheckButton
1746 | | | | | `GtkRadioButton
1747 | | | | `GtkOptionMenu
1749 | | | | +GtkMenuItem
1750 | | | | | +GtkCheckMenuItem
1751 | | | | | | `GtkRadioMenuItem
1752 | | | | | `GtkTearoffMenuItem
1753 | | | | +GtkListItem
1754 | | | | `GtkTreeItem
1756 | | | | +GtkColorSelectionDialog
1758 | | | | | `GtkInputDialog
1759 | | | | +GtkDrawWindow
1760 | | | | +GtkFileSelection
1761 | | | | +GtkFontSelectionDialog
1765 | | | +GtkScrolledWindow
1769 | | | | +GtkHButtonBox
1770 | | | | `GtkVButtonBox
1772 | | | | +GtkColorSelection
1773 | | | | `GtkGammaCurve
1781 | | | `GtkFontSelection
1800 | | | `GtkSpinButton
1824 <!-- ----------------------------------------------------------------- -->
1825 <sect1>Widgets Without Windows
1827 The following widgets do not have an associated window. If you want to
1828 capture events, you'll have to use the EventBox. See the section on
1829 the <ref id="sec_EventBox" name="EventBox"> widget.
1851 We'll further our exploration of GTK by examining each widget in turn,
1852 creating a few simple functions to display them. Another good source
1853 is the testgtk.c program that comes with GTK. It can be found in
1856 <!-- ***************************************************************** -->
1857 <sect>The Button Widget
1858 <!-- ***************************************************************** -->
1860 <!-- ----------------------------------------------------------------- -->
1861 <sect1>Normal Buttons
1863 We've almost seen all there is to see of the button widget. It's
1864 pretty simple. There are however two ways to create a button. You can
1865 use the gtk_button_new_with_label() to create a button with a label,
1866 or use gtk_button_new() to create a blank button. It's then up to you
1867 to pack a label or pixmap into this new button. To do this, create a
1868 new box, and then pack your objects into this box using the usual
1869 gtk_box_pack_start, and then use gtk_container_add to pack the box
1872 Here's an example of using gtk_button_new to create a button with a
1873 picture and a label in it. I've broken up the code to create a box
1874 from the rest so you can use it in your programs. There are further
1875 examples of using pixmaps later in the tutorial.
1878 /* example-start buttons buttons.c */
1880 #include <gtk/gtk.h>
1882 /* Create a new hbox with an image and a label packed into it
1883 * and return the box. */
1885 GtkWidget *xpm_label_box( GtkWidget *parent,
1886 gchar *xpm_filename,
1891 GtkWidget *pixmapwid;
1896 /* Create box for xpm and label */
1897 box1 = gtk_hbox_new (FALSE, 0);
1898 gtk_container_set_border_width (GTK_CONTAINER (box1), 2);
1900 /* Get the style of the button to get the
1901 * background color. */
1902 style = gtk_widget_get_style(parent);
1904 /* Now on to the xpm stuff */
1905 pixmap = gdk_pixmap_create_from_xpm (parent->window, &mask,
1906 &style->bg[GTK_STATE_NORMAL],
1908 pixmapwid = gtk_pixmap_new (pixmap, mask);
1910 /* Create a label for the button */
1911 label = gtk_label_new (label_text);
1913 /* Pack the pixmap and label into the box */
1914 gtk_box_pack_start (GTK_BOX (box1),
1915 pixmapwid, FALSE, FALSE, 3);
1917 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 3);
1919 gtk_widget_show(pixmapwid);
1920 gtk_widget_show(label);
1925 /* Our usual callback function */
1926 void callback( GtkWidget *widget,
1929 g_print ("Hello again - %s was pressed\n", (char *) data);
1936 /* GtkWidget is the storage type for widgets */
1941 gtk_init (&argc, &argv);
1943 /* Create a new window */
1944 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1946 gtk_window_set_title (GTK_WINDOW (window), "Pixmap'd Buttons!");
1948 /* It's a good idea to do this for all windows. */
1949 gtk_signal_connect (GTK_OBJECT (window), "destroy",
1950 GTK_SIGNAL_FUNC (gtk_exit), NULL);
1952 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
1953 GTK_SIGNAL_FUNC (gtk_exit), NULL);
1956 /* Sets the border width of the window. */
1957 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
1958 gtk_widget_realize(window);
1960 /* Create a new button */
1961 button = gtk_button_new ();
1963 /* Connect the "clicked" signal of the button to our callback */
1964 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1965 GTK_SIGNAL_FUNC (callback), (gpointer) "cool button");
1967 /* This calls our box creating function */
1968 box1 = xpm_label_box(window, "info.xpm", "cool button");
1970 /* Pack and show all our widgets */
1971 gtk_widget_show(box1);
1973 gtk_container_add (GTK_CONTAINER (button), box1);
1975 gtk_widget_show(button);
1977 gtk_container_add (GTK_CONTAINER (window), button);
1979 gtk_widget_show (window);
1981 /* Rest in gtk_main and wait for the fun to begin! */
1989 The xpm_label_box function could be used to pack xpm's and labels into
1990 any widget that can be a container.
1992 Notice in <tt/xpm_label_box/ how there is a call to
1993 <tt/gtk_widget_get_style/. Every widget has a "style", consisting of
1994 foreground and background colors for a variety of situations, font
1995 selection, and other graphics data relevant to a widget. These style
1996 values are defaulted in each widget, and are required by many GDK
1997 function calls, such as <tt/gdk_pixmap_create_from_xpm/, which here is
1998 given the "normal" background color. The style data of widgets may
1999 be customized, using <ref id="sec_gtkrc_files" name="GTK's rc files">.
2001 Also notice the call to <tt/gtk_widget_realize/ after setting the
2002 window's border width. This function uses GDK to create the X
2003 windows related to the widget. The function is automatically called
2004 when you invoke <tt/gtk_widget_show/ for a widget, and so has not been
2005 shown in earlier examples. But the call to
2006 <tt/gdk_pixmap_create_from_xpm/ requires that its <tt/window/ argument
2007 refer to a real X window, so it is necessary to realize the widget
2008 before this GDK call.
2010 The Button widget has the following signals:
2013 <item><tt/pressed/ - emitted when pointer button is pressed within
2015 <item><tt/released/ - emitted when pointer button is released within
2017 <item><tt/clicked/ - emitted when pointer button is pressed and then
2018 released within Button widget
2019 <item><tt/enter/ - emitted when pointer enters Button widget
2020 <item><tt/leave/ - emitted when pointer leaves Button widget
2023 <!-- ----------------------------------------------------------------- -->
2024 <sect1> Toggle Buttons
2026 Toggle buttons are derived from normal buttons and are very similar,
2027 except they will always be in one of two states, alternated by a
2028 click. They may be depressed, and when you click again, they will pop
2029 back up. Click again, and they will pop back down.
2031 Toggle buttons are the basis for check buttons and radio buttons, as
2032 such, many of the calls used for toggle buttons are inherited by radio
2033 and check buttons. I will point these out when we come to them.
2035 Creating a new toggle button:
2038 GtkWidget *gtk_toggle_button_new( void );
2040 GtkWidget *gtk_toggle_button_new_with_label( gchar *label );
2043 As you can imagine, these work identically to the normal button widget
2044 calls. The first creates a blank toggle button, and the second, a
2045 button with a label widget already packed into it.
2047 To retrieve the state of the toggle widget, including radio and check
2048 buttons, we use a construct as shown in our example below. This tests
2049 the state of the toggle, by accessing the <tt/active/ field of the
2050 toggle widget's structure, after first using the
2051 <tt/GTK_TOGGLE_BUTTON/ macro to cast the widget pointer into a toggle
2052 widget pointer. The signal of interest to us emitted by toggle
2053 buttons (the toggle button, check button, and radio button widgets) is
2054 the "toggled" signal. To check the state of these buttons, set up a
2055 signal handler to catch the toggled signal, and access the structure
2056 to determine its state. The callback will look something like:
2059 void toggle_button_callback (GtkWidget *widget, gpointer data)
2061 if (GTK_TOGGLE_BUTTON (widget)->active)
2063 /* If control reaches here, the toggle button is down */
2067 /* If control reaches here, the toggle button is up */
2072 To force the state of a toggle button, and its children, the radio and
2073 check buttons, use this function:
2076 void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,
2080 The above call can be used to set the state of the toggle button, and
2081 its children the radio and check buttons. Passing in your created
2082 button as the first argument, and a TRUE or FALSE for the second state
2083 argument to specify whether it should be down (depressed) or up
2084 (released). Default is up, or FALSE.
2086 Note that when you use the gtk_toggle_button_set_active() function, and
2087 the state is actually changed, it causes the "clicked" signal to be
2088 emitted from the button.
2091 void gtk_toggle_button_toggled (GtkToggleButton *toggle_button);
2094 This simply toggles the button, and emits the "toggled" signal.
2096 <!-- ----------------------------------------------------------------- -->
2097 <sect1> Check Buttons
2099 Check buttons inherit many properties and functions from the the
2100 toggle buttons above, but look a little different. Rather than being
2101 buttons with text inside them, they are small squares with the text to
2102 the right of them. These are often used for toggling options on and
2103 off in applications.
2105 The two creation functions are similar to those of the normal button.
2108 GtkWidget *gtk_check_button_new( void );
2110 GtkWidget *gtk_check_button_new_with_label ( gchar *label );
2113 The new_with_label function creates a check button with a label beside
2116 Checking the state of the check button is identical to that of the
2119 <!-- ----------------------------------------------------------------- -->
2120 <sect1> Radio Buttons <label id="sec_Radio_Buttons">
2122 Radio buttons are similar to check buttons except they are grouped so
2123 that only one may be selected/depressed at a time. This is good for
2124 places in your application where you need to select from a short list
2127 Creating a new radio button is done with one of these calls:
2130 GtkWidget *gtk_radio_button_new( GSList *group );
2132 GtkWidget *gtk_radio_button_new_with_label( GSList *group,
2136 You'll notice the extra argument to these calls. They require a group
2137 to perform their duty properly. The first call to
2138 gtk_radio_button_new_with_label or gtk_radio_button_new_with_label
2139 should pass NULL as the first argument. Then create a group using:
2142 GSList *gtk_radio_button_group( GtkRadioButton *radio_button );
2145 The important thing to remember is that gtk_radio_button_group must be
2146 called for each new button added to the group, with the previous
2147 button passed in as an argument. The result is then passed into the
2148 next call to gtk_radio_button_new or
2149 gtk_radio_button_new_with_label. This allows a chain of buttons to be
2150 established. The example below should make this clear.
2152 You can shorten this slightly by using the following syntax, which
2153 removes the need for a variable to hold the list of buttons. This form
2154 is used in the example to create the third button:
2157 button2 = gtk_radio_button_new_with_label(
2158 gtk_radio_button_group (GTK_RADIO_BUTTON (button1)),
2162 It is also a good idea to explicitly set which button should be the
2163 default depressed button with:
2166 void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,
2170 This is described in the section on toggle buttons, and works in
2171 exactly the same way. Once the radio buttons are grouped together,
2172 only one of the group may be active at a time. If the user clicks on
2173 one radio button, and then on another, the first radio button will
2174 first emit a "toggled" signal (to report becoming inactive), and then
2175 the second will emit its "toggled" signal (to report becoming active).
2177 The following example creates a radio button group with three buttons.
2180 /* example-start radiobuttons radiobuttons.c */
2182 #include <gtk/gtk.h>
2185 void close_application( GtkWidget *widget,
2195 GtkWidget *window = NULL;
2199 GtkWidget *separator;
2202 gtk_init(&argc,&argv);
2204 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2206 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
2207 GTK_SIGNAL_FUNC(close_application),
2210 gtk_window_set_title (GTK_WINDOW (window), "radio buttons");
2211 gtk_container_set_border_width (GTK_CONTAINER (window), 0);
2213 box1 = gtk_vbox_new (FALSE, 0);
2214 gtk_container_add (GTK_CONTAINER (window), box1);
2215 gtk_widget_show (box1);
2217 box2 = gtk_vbox_new (FALSE, 10);
2218 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2219 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2220 gtk_widget_show (box2);
2222 button = gtk_radio_button_new_with_label (NULL, "button1");
2223 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2224 gtk_widget_show (button);
2226 group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
2227 button = gtk_radio_button_new_with_label(group, "button2");
2228 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2229 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2230 gtk_widget_show (button);
2232 button = gtk_radio_button_new_with_label(
2233 gtk_radio_button_group (GTK_RADIO_BUTTON (button)),
2235 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2236 gtk_widget_show (button);
2238 separator = gtk_hseparator_new ();
2239 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
2240 gtk_widget_show (separator);
2242 box2 = gtk_vbox_new (FALSE, 10);
2243 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2244 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
2245 gtk_widget_show (box2);
2247 button = gtk_button_new_with_label ("close");
2248 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2249 GTK_SIGNAL_FUNC(close_application),
2250 GTK_OBJECT (window));
2251 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2252 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
2253 gtk_widget_grab_default (button);
2254 gtk_widget_show (button);
2255 gtk_widget_show (window);
2264 <!-- TODO: check out gtk_radio_button_new_from_widget function - TRG -->
2266 <!-- ***************************************************************** -->
2267 <sect> Adjustments <label id="sec_Adjustment">
2268 <!-- ***************************************************************** -->
2270 GTK has various widgets that can be visually adjusted by the user
2271 using the mouse or the keyboard, such as the range widgets, described
2272 in the <ref id="sec_Range_Widgets" name="Range Widgets">
2273 section. There are also a few widgets that display some adjustable
2274 portion of a larger area of data, such as the text widget and the
2277 Obviously, an application needs to be able to react to changes the
2278 user makes in range widgets. One way to do this would be to have each
2279 widget emit its own type of signal when its adjustment changes, and
2280 either pass the new value to the signal handler, or require it to look
2281 inside the widget's data structure in order to ascertain the value.
2282 But you may also want to connect the adjustments of several widgets
2283 together, so that adjusting one adjusts the others. The most obvious
2284 example of this is connecting a scrollbar to a panning viewport or a
2285 scrolling text area. If each widget has its own way of setting or
2286 getting the adjustment value, then the programmer may have to write
2287 their own signal handlers to translate between the output of one
2288 widget's signal and the "input" of another's adjustment setting
2291 GTK solves this problem using the Adjustment object, which is not a
2292 widget but a way for widgets to store and pass adjustment information
2293 in an abstract and flexible form. The most obvious use of Adjustment
2294 is to store the configuration parameters and values of range widgets,
2295 such as scrollbars and scale controls. However, since Adjustments are
2296 derived from Object, they have some special powers beyond those of
2297 normal data structures. Most importantly, they can emit signals, just
2298 like widgets, and these signals can be used not only to allow your
2299 program to react to user input on adjustable widgets, but also to
2300 propagate adjustment values transparently between adjustable widgets.
2302 You will see how adjustments fit in when you see the other widgets
2303 that incorporate them:
2304 <ref id="sec_ProgressBar" name="Progress Bars">,
2305 <ref id="sec_Viewports" name="Viewports">,
2306 <ref id="sec_ScrolledWindow" name="Scrolled Windows">, and others.
2308 <sect1> Creating an Adjustment
2310 Many of the widgets which use adjustment objects do so automatically,
2311 but some cases will be shown in later examples where you may need to
2312 create one yourself. You create an adjustment using:
2315 GtkObject *gtk_adjustment_new( gfloat value,
2318 gfloat step_increment,
2319 gfloat page_increment,
2323 The <tt/value/ argument is the initial value you want to give to the
2324 adjustment, usually corresponding to the topmost or leftmost position
2325 of an adjustable widget. The <tt/lower/ argument specifies the lowest
2326 value which the adjustment can hold. The <tt/step_increment/ argument
2327 specifies the "smaller" of the two increments by which the user can
2328 change the value, while the <tt/page_increment/ is the "larger" one.
2329 The <tt/page_size/ argument usually corresponds somehow to the visible
2330 area of a panning widget. The <tt/upper/ argument is used to represent
2331 the bottom most or right most coordinate in a panning widget's
2332 child. Therefore it is <em/not/ always the largest number that
2333 <tt/value/ can take, since the <tt/page_size/ of such widgets is
2336 <!-- ----------------------------------------------------------------- -->
2337 <sect1> Using Adjustments the Easy Way
2339 The adjustable widgets can be roughly divided into those which use and
2340 require specific units for these values and those which treat them as
2341 arbitrary numbers. The group which treats the values as arbitrary
2342 numbers includes the range widgets (scrollbars and scales, the
2343 progress bar widget, and the spin button widget). These widgets are
2344 all the widgets which are typically "adjusted" directly by the user
2345 with the mouse or keyboard. They will treat the <tt/lower/ and
2346 <tt/upper/ values of an adjustment as a range within which the user
2347 can manipulate the adjustment's <tt/value/. By default, they will only
2348 modify the <tt/value/ of an adjustment.
2350 The other group includes the text widget, the viewport widget, the
2351 compound list widget, and the scrolled window widget. All of these
2352 widgets use pixel values for their adjustments. These are also all
2353 widgets which are typically "adjusted" indirectly using scrollbars.
2354 While all widgets which use adjustments can either create their own
2355 adjustments or use ones you supply, you'll generally want to let this
2356 particular category of widgets create its own adjustments. Usually,
2357 they will eventually override all the values except the <tt/value/
2358 itself in whatever adjustments you give them, but the results are, in
2359 general, undefined (meaning, you'll have to read the source code to
2360 find out, and it may be different from widget to widget).
2362 Now, you're probably thinking, since text widgets and viewports insist
2363 on setting everything except the <tt/value/ of their adjustments,
2364 while scrollbars will <em/only/ touch the adjustment's <tt/value/, if
2365 you <em/share/ an adjustment object between a scrollbar and a text
2366 widget, manipulating the scrollbar will automagically adjust the text
2367 widget? Of course it will! Just like this:
2370 /* creates its own adjustments */
2371 text = gtk_text_new (NULL, NULL);
2372 /* uses the newly-created adjustment for the scrollbar as well */
2373 vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
2377 <!-- ----------------------------------------------------------------- -->
2378 <sect1> Adjustment Internals
2380 Ok, you say, that's nice, but what if I want to create my own handlers
2381 to respond when the user adjusts a range widget or a spin button, and
2382 how do I get at the value of the adjustment in these handlers? To
2383 answer these questions and more, let's start by taking a look at
2384 <tt>struct _GtkAdjustment</tt> itself:
2387 struct _GtkAdjustment
2394 gfloat step_increment;
2395 gfloat page_increment;
2400 The first thing you should know is that there aren't any handy-dandy
2401 macros or accessor functions for getting the <tt/value/ out of an
2402 Adjustment, so you'll have to (horror of horrors) do it like a
2403 <em/real/ C programmer. Don't worry - the <tt>GTK_ADJUSTMENT
2404 (Object)</tt> macro does run-time type checking (as do all the GTK
2405 type-casting macros, actually).
2407 Since, when you set the <tt/value/ of an adjustment, you generally
2408 want the change to be reflected by every widget that uses this
2409 adjustment, GTK provides this convenience function to do this:
2412 void gtk_adjustment_set_value( GtkAdjustment *adjustment,
2416 As mentioned earlier, Adjustment is a subclass of Object just
2417 like all the various widgets, and thus it is able to emit signals.
2418 This is, of course, why updates happen automagically when you share an
2419 adjustment object between a scrollbar and another adjustable widget;
2420 all adjustable widgets connect signal handlers to their adjustment's
2421 <tt/value_changed/ signal, as can your program. Here's the definition
2422 of this signal in <tt/struct _GtkAdjustmentClass/:
2425 void (* value_changed) (GtkAdjustment *adjustment);
2428 The various widgets that use the Adjustment object will emit this
2429 signal on an adjustment whenever they change its value. This happens
2430 both when user input causes the slider to move on a range widget, as
2431 well as when the program explicitly changes the value with
2432 <tt/gtk_adjustment_set_value()/. So, for example, if you have a scale
2433 widget, and you want to change the rotation of a picture whenever its
2434 value changes, you would create a callback like this:
2437 void cb_rotate_picture (GtkAdjustment *adj, GtkWidget *picture)
2439 set_picture_rotation (picture, adj->value);
2443 and connect it to the scale widget's adjustment like this:
2446 gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
2447 GTK_SIGNAL_FUNC (cb_rotate_picture), picture);
2450 What about when a widget reconfigures the <tt/upper/ or <tt/lower/
2451 fields of its adjustment, such as when a user adds more text to a text
2452 widget? In this case, it emits the <tt/changed/ signal, which looks
2456 void (* changed) (GtkAdjustment *adjustment);
2459 Range widgets typically connect a handler to this signal, which
2460 changes their appearance to reflect the change - for example, the size
2461 of the slider in a scrollbar will grow or shrink in inverse proportion
2462 to the difference between the <tt/lower/ and <tt/upper/ values of its
2465 You probably won't ever need to attach a handler to this signal,
2466 unless you're writing a new type of range widget. However, if you
2467 change any of the values in a Adjustment directly, you should emit
2468 this signal on it to reconfigure whatever widgets are using it, like
2472 gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");
2475 Now go forth and adjust!
2479 <!-- ***************************************************************** -->
2480 <sect> Range Widgets<label id="sec_Range_Widgets">
2481 <!-- ***************************************************************** -->
2484 The category of range widgets includes the ubiquitous scrollbar widget
2485 and the less common "scale" widget. Though these two types of widgets
2486 are generally used for different purposes, they are quite similar in
2487 function and implementation. All range widgets share a set of common
2488 graphic elements, each of which has its own X window and receives
2489 events. They all contain a "trough" and a "slider" (what is sometimes
2490 called a "thumbwheel" in other GUI environments). Dragging the slider
2491 with the pointer moves it back and forth within the trough, while
2492 clicking in the trough advances the slider towards the location of the
2493 click, either completely, or by a designated amount, depending on
2494 which mouse button is used.
2496 As mentioned in <ref id="sec_Adjustment" name="Adjustments"> above,
2497 all range widgets are associated with an adjustment object, from which
2498 they calculate the length of the slider and its position within the
2499 trough. When the user manipulates the slider, the range widget will
2500 change the value of the adjustment.
2502 <!-- ----------------------------------------------------------------- -->
2503 <sect1> Scrollbar Widgets
2505 These are your standard, run-of-the-mill scrollbars. These should be
2506 used only for scrolling some other widget, such as a list, a text box,
2507 or a viewport (and it's generally easier to use the scrolled window
2508 widget in most cases). For other purposes, you should use scale
2509 widgets, as they are friendlier and more featureful.
2511 There are separate types for horizontal and vertical scrollbars.
2512 There really isn't much to say about these. You create them with the
2513 following functions, defined in <tt><gtk/gtkhscrollbar.h></tt>
2514 and <tt><gtk/gtkvscrollbar.h></tt>:
2517 GtkWidget *gtk_hscrollbar_new( GtkAdjustment *adjustment );
2519 GtkWidget *gtk_vscrollbar_new( GtkAdjustment *adjustment );
2522 and that's about it (if you don't believe me, look in the header
2523 files!). The <tt/adjustment/ argument can either be a pointer to an
2524 existing Adjustment, or NULL, in which case one will be created for
2525 you. Specifying NULL might actually be useful in this case, if you
2526 wish to pass the newly-created adjustment to the constructor function
2527 of some other widget which will configure it for you, such as a text
2531 <!-- ----------------------------------------------------------------- -->
2532 <sect1> Scale Widgets
2534 Scale widgets are used to allow the user to visually select and
2535 manipulate a value within a specific range. You might want to use a
2536 scale widget, for example, to adjust the magnification level on a
2537 zoomed preview of a picture, or to control the brightness of a color,
2538 or to specify the number of minutes of inactivity before a screensaver
2539 takes over the screen.
2541 <!-- ----------------------------------------------------------------- -->
2542 <sect2>Creating a Scale Widget
2544 As with scrollbars, there are separate widget types for horizontal and
2545 vertical scale widgets. (Most programmers seem to favour horizontal
2546 scale widgets.) Since they work essentially the same way, there's no
2547 need to treat them separately here. The following functions, defined
2548 in <tt><gtk/gtkvscale.h></tt> and
2549 <tt><gtk/gtkhscale.h></tt>, create vertical and horizontal scale
2550 widgets, respectively:
2554 GtkWidget *gtk_vscale_new( GtkAdjustment *adjustment );
2556 GtkWidget *gtk_hscale_new( GtkAdjustment *adjustment );
2560 The <tt/adjustment/ argument can either be an adjustment which has
2561 already been created with <tt/gtk_adjustment_new()/, or <tt/NULL/, in
2562 which case, an anonymous Adjustment is created with all of its
2563 values set to <tt/0.0/ (which isn't very useful in this case). In
2564 order to avoid confusing yourself, you probably want to create your
2565 adjustment with a <tt/page_size/ of <tt/0.0/ so that its <tt/upper/
2566 value actually corresponds to the highest value the user can select.
2567 (If you're <em/already/ thoroughly confused, read the section on <ref
2568 id="sec_Adjustment" name="Adjustments"> again for an explanation of
2569 what exactly adjustments do and how to create and manipulate them.)
2571 <!-- ----------------------------------------------------------------- -->
2572 <sect2> Functions and Signals (well, functions, at least)
2574 Scale widgets can display their current value as a number beside the
2575 trough. The default behaviour is to show the value, but you can change
2576 this with this function:
2579 void gtk_scale_set_draw_value( GtkScale *scale,
2583 As you might have guessed, <tt/draw_value/ is either <tt/TRUE/ or
2584 <tt/FALSE/, with predictable consequences for either one.
2586 The value displayed by a scale widget is rounded to one decimal point
2587 by default, as is the <tt/value/ field in its GtkAdjustment. You can
2592 void gtk_scale_set_digits( GtkScale *scale,
2597 where <tt/digits/ is the number of decimal places you want. You can
2598 set <tt/digits/ to anything you like, but no more than 13 decimal
2599 places will actually be drawn on screen.
2601 Finally, the value can be drawn in different positions
2602 relative to the trough:
2606 void gtk_scale_set_value_pos( GtkScale *scale,
2607 GtkPositionType pos );
2611 The argument <tt/pos/ is of type <tt>GtkPositionType</tt>, which is
2612 defined in <tt><gtk/gtkenums.h></tt>, and can take one of the
2622 If you position the value on the "side" of the trough (e.g., on the
2623 top or bottom of a horizontal scale widget), then it will follow the
2624 slider up and down the trough.
2626 All the preceding functions are defined in
2627 <tt><gtk/gtkscale.h></tt>. The header files for all GTK widgets
2628 are automatically included when you include
2629 <tt><gtk/gtk.h></tt>. But you should look over the header files
2630 of all widgets that interest you,
2635 <!-- ----------------------------------------------------------------- -->
2636 <sect1> Common Range Functions <label id="sec_Range_Functions">
2638 The Range widget class is fairly complicated internally, but, like
2639 all the "base class" widgets, most of its complexity is only
2640 interesting if you want to hack on it. Also, almost all of the
2641 functions and signals it defines are only really used in writing
2642 derived widgets. There are, however, a few useful functions that are
2643 defined in <tt><gtk/gtkrange.h></tt> and will work on all range
2646 <!-- ----------------------------------------------------------------- -->
2647 <sect2> Setting the Update Policy
2649 The "update policy" of a range widget defines at what points during
2650 user interaction it will change the <tt/value/ field of its
2651 Adjustment and emit the "value_changed" signal on this
2652 Adjustment. The update policies, defined in
2653 <tt><gtk/gtkenums.h></tt> as type <tt>enum GtkUpdateType</tt>,
2657 <item>GTK_UPDATE_POLICY_CONTINUOUS - This is the default. The
2658 "value_changed" signal is emitted continuously, i.e., whenever the
2659 slider is moved by even the tiniest amount.
2661 <item>GTK_UPDATE_POLICY_DISCONTINUOUS - The "value_changed" signal is
2662 only emitted once the slider has stopped moving and the user has
2663 released the mouse button.
2665 <item>GTK_UPDATE_POLICY_DELAYED - The "value_changed" signal is emitted
2666 when the user releases the mouse button, or if the slider stops moving
2667 for a short period of time.
2671 The update policy of a range widget can be set by casting it using the
2672 <tt>GTK_RANGE (Widget)</tt> macro and passing it to this function:
2675 void gtk_range_set_update_policy( GtkRange *range,
2676 GtkUpdateType policy) ;
2679 <!-- ----------------------------------------------------------------- -->
2680 <sect2>Getting and Setting Adjustments
2682 Getting and setting the adjustment for a range widget "on the fly" is
2683 done, predictably, with:
2686 GtkAdjustment* gtk_range_get_adjustment( GtkRange *range );
2688 void gtk_range_set_adjustment( GtkRange *range,
2689 GtkAdjustment *adjustment );
2692 <tt/gtk_range_get_adjustment()/ returns a pointer to the adjustment to
2693 which <tt/range/ is connected.
2695 <tt/gtk_range_set_adjustment()/ does absolutely nothing if you pass it
2696 the adjustment that <tt/range/ is already using, regardless of whether
2697 you changed any of its fields or not. If you pass it a new
2698 Adjustment, it will unreference the old one if it exists (possibly
2699 destroying it), connect the appropriate signals to the new one, and
2700 call the private function <tt/gtk_range_adjustment_changed()/, which
2701 will (or at least, is supposed to...) recalculate the size and/or
2702 position of the slider and redraw if necessary. As mentioned in the
2703 section on adjustments, if you wish to reuse the same Adjustment,
2704 when you modify its values directly, you should emit the "changed"
2705 signal on it, like this:
2708 gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");
2713 <!-- ----------------------------------------------------------------- -->
2714 <sect1> Key and Mouse bindings
2716 All of the GTK range widgets react to mouse clicks in more or less
2717 the same way. Clicking button-1 in the trough will cause its
2718 adjustment's <tt/page_increment/ to be added or subtracted from its
2719 <tt/value/, and the slider to be moved accordingly. Clicking mouse
2720 button-2 in the trough will jump the slider to the point at which the
2721 button was clicked. Clicking any button on a scrollbar's arrows will
2722 cause its adjustment's value to change <tt/step_increment/ at a time.
2724 It may take a little while to get used to, but by default, scrollbars
2725 as well as scale widgets can take the keyboard focus in GTK. If you
2726 think your users will find this too confusing, you can always disable
2727 this by unsetting the <tt/GTK_CAN_FOCUS/ flag on the scrollbar, like
2731 GTK_WIDGET_UNSET_FLAGS (scrollbar, GTK_CAN_FOCUS);
2734 The key bindings (which are, of course, only active when the widget
2735 has focus) are slightly different between horizontal and vertical
2736 range widgets, for obvious reasons. They are also not quite the same
2737 for scale widgets as they are for scrollbars, for somewhat less
2738 obvious reasons (possibly to avoid confusion between the keys for
2739 horizontal and vertical scrollbars in scrolled windows, where both
2740 operate on the same area).
2742 <sect2> Vertical Range Widgets
2744 All vertical range widgets can be operated with the up and down arrow
2745 keys, as well as with the <tt/Page Up/ and <tt/Page Down/ keys. The
2746 arrows move the slider up and down by <tt/step_increment/, while
2747 <tt/Page Up/ and <tt/Page Down/ move it by <tt/page_increment/.
2749 The user can also move the slider all the way to one end or the other
2750 of the trough using the keyboard. With the VScale widget, this is
2751 done with the <tt/Home/ and <tt/End/ keys, whereas with the
2752 VScrollbar widget, this is done by typing <tt>Control-Page Up</tt>
2753 and <tt>Control-Page Down</tt>.
2755 <!-- ----------------------------------------------------------------- -->
2756 <sect2> Horizontal Range Widgets
2758 The left and right arrow keys work as you might expect in these
2759 widgets, moving the slider back and forth by <tt/step_increment/. The
2760 <tt/Home/ and <tt/End/ keys move the slider to the ends of the trough.
2761 For the HScale widget, moving the slider by <tt/page_increment/ is
2762 accomplished with <tt>Control-Left</tt> and <tt>Control-Right</tt>,
2763 while for HScrollbar, it's done with <tt>Control-Home</tt> and
2764 <tt>Control-End</tt>.
2768 <!-- ----------------------------------------------------------------- -->
2769 <sect1> Example<label id="sec_Range_Example">
2771 This example is a somewhat modified version of the "range controls"
2772 test from <tt/testgtk.c/. It basically puts up a window with three
2773 range widgets all connected to the same adjustment, and a couple of
2774 controls for adjusting some of the parameters mentioned above and in
2775 the section on adjustments, so you can see how they affect the way
2776 these widgets work for the user.
2779 /* example-start rangewidgets rangewidgets.c */
2781 #include <gtk/gtk.h>
2783 GtkWidget *hscale, *vscale;
2785 void cb_pos_menu_select( GtkWidget *item,
2786 GtkPositionType pos )
2788 /* Set the value position on both scale widgets */
2789 gtk_scale_set_value_pos (GTK_SCALE (hscale), pos);
2790 gtk_scale_set_value_pos (GTK_SCALE (vscale), pos);
2793 void cb_update_menu_select( GtkWidget *item,
2794 GtkUpdateType policy )
2796 /* Set the update policy for both scale widgets */
2797 gtk_range_set_update_policy (GTK_RANGE (hscale), policy);
2798 gtk_range_set_update_policy (GTK_RANGE (vscale), policy);
2801 void cb_digits_scale( GtkAdjustment *adj )
2803 /* Set the number of decimal places to which adj->value is rounded */
2804 gtk_scale_set_digits (GTK_SCALE (hscale), (gint) adj->value);
2805 gtk_scale_set_digits (GTK_SCALE (vscale), (gint) adj->value);
2808 void cb_page_size( GtkAdjustment *get,
2809 GtkAdjustment *set )
2811 /* Set the page size and page increment size of the sample
2812 * adjustment to the value specified by the "Page Size" scale */
2813 set->page_size = get->value;
2814 set->page_increment = get->value;
2815 /* Now emit the "changed" signal to reconfigure all the widgets that
2816 * are attached to this adjustment */
2817 gtk_signal_emit_by_name (GTK_OBJECT (set), "changed");
2820 void cb_draw_value( GtkToggleButton *button )
2822 /* Turn the value display on the scale widgets off or on depending
2823 * on the state of the checkbutton */
2824 gtk_scale_set_draw_value (GTK_SCALE (hscale), button->active);
2825 gtk_scale_set_draw_value (GTK_SCALE (vscale), button->active);
2828 /* Convenience functions */
2830 GtkWidget *make_menu_item( gchar *name,
2831 GtkSignalFunc callback,
2836 item = gtk_menu_item_new_with_label (name);
2837 gtk_signal_connect (GTK_OBJECT (item), "activate",
2839 gtk_widget_show (item);
2844 void scale_set_default_values( GtkScale *scale )
2846 gtk_range_set_update_policy (GTK_RANGE (scale),
2847 GTK_UPDATE_CONTINUOUS);
2848 gtk_scale_set_digits (scale, 1);
2849 gtk_scale_set_value_pos (scale, GTK_POS_TOP);
2850 gtk_scale_set_draw_value (scale, TRUE);
2853 /* makes the sample window */
2855 void create_range_controls( void )
2858 GtkWidget *box1, *box2, *box3;
2860 GtkWidget *scrollbar;
2861 GtkWidget *separator;
2862 GtkWidget *opt, *menu, *item;
2865 GtkObject *adj1, *adj2;
2867 /* Standard window-creating stuff */
2868 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2869 gtk_signal_connect (GTK_OBJECT (window), "destroy",
2870 GTK_SIGNAL_FUNC(gtk_main_quit),
2872 gtk_window_set_title (GTK_WINDOW (window), "range controls");
2874 box1 = gtk_vbox_new (FALSE, 0);
2875 gtk_container_add (GTK_CONTAINER (window), box1);
2876 gtk_widget_show (box1);
2878 box2 = gtk_hbox_new (FALSE, 10);
2879 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2880 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2881 gtk_widget_show (box2);
2883 /* value, lower, upper, step_increment, page_increment, page_size */
2884 /* Note that the page_size value only makes a difference for
2885 * scrollbar widgets, and the highest value you'll get is actually
2886 * (upper - page_size). */
2887 adj1 = gtk_adjustment_new (0.0, 0.0, 101.0, 0.1, 1.0, 1.0);
2889 vscale = gtk_vscale_new (GTK_ADJUSTMENT (adj1));
2890 scale_set_default_values (GTK_SCALE (vscale));
2891 gtk_box_pack_start (GTK_BOX (box2), vscale, TRUE, TRUE, 0);
2892 gtk_widget_show (vscale);
2894 box3 = gtk_vbox_new (FALSE, 10);
2895 gtk_box_pack_start (GTK_BOX (box2), box3, TRUE, TRUE, 0);
2896 gtk_widget_show (box3);
2898 /* Reuse the same adjustment */
2899 hscale = gtk_hscale_new (GTK_ADJUSTMENT (adj1));
2900 gtk_widget_set_usize (GTK_WIDGET (hscale), 200, 30);
2901 scale_set_default_values (GTK_SCALE (hscale));
2902 gtk_box_pack_start (GTK_BOX (box3), hscale, TRUE, TRUE, 0);
2903 gtk_widget_show (hscale);
2905 /* Reuse the same adjustment again */
2906 scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adj1));
2907 /* Notice how this causes the scales to always be updated
2908 * continuously when the scrollbar is moved */
2909 gtk_range_set_update_policy (GTK_RANGE (scrollbar),
2910 GTK_UPDATE_CONTINUOUS);
2911 gtk_box_pack_start (GTK_BOX (box3), scrollbar, TRUE, TRUE, 0);
2912 gtk_widget_show (scrollbar);
2914 box2 = gtk_hbox_new (FALSE, 10);
2915 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2916 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2917 gtk_widget_show (box2);
2919 /* A checkbutton to control whether the value is displayed or not */
2920 button = gtk_check_button_new_with_label("Display value on scale widgets");
2921 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2922 gtk_signal_connect (GTK_OBJECT (button), "toggled",
2923 GTK_SIGNAL_FUNC(cb_draw_value), NULL);
2924 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2925 gtk_widget_show (button);
2927 box2 = gtk_hbox_new (FALSE, 10);
2928 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2930 /* An option menu to change the position of the value */
2931 label = gtk_label_new ("Scale Value Position:");
2932 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
2933 gtk_widget_show (label);
2935 opt = gtk_option_menu_new();
2936 menu = gtk_menu_new();
2938 item = make_menu_item ("Top",
2939 GTK_SIGNAL_FUNC(cb_pos_menu_select),
2940 GINT_TO_POINTER (GTK_POS_TOP));
2941 gtk_menu_append (GTK_MENU (menu), item);
2943 item = make_menu_item ("Bottom", GTK_SIGNAL_FUNC (cb_pos_menu_select),
2944 GINT_TO_POINTER (GTK_POS_BOTTOM));
2945 gtk_menu_append (GTK_MENU (menu), item);
2947 item = make_menu_item ("Left", GTK_SIGNAL_FUNC (cb_pos_menu_select),
2948 GINT_TO_POINTER (GTK_POS_LEFT));
2949 gtk_menu_append (GTK_MENU (menu), item);
2951 item = make_menu_item ("Right", GTK_SIGNAL_FUNC (cb_pos_menu_select),
2952 GINT_TO_POINTER (GTK_POS_RIGHT));
2953 gtk_menu_append (GTK_MENU (menu), item);
2955 gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
2956 gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
2957 gtk_widget_show (opt);
2959 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2960 gtk_widget_show (box2);
2962 box2 = gtk_hbox_new (FALSE, 10);
2963 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2965 /* Yet another option menu, this time for the update policy of the
2967 label = gtk_label_new ("Scale Update Policy:");
2968 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
2969 gtk_widget_show (label);
2971 opt = gtk_option_menu_new();
2972 menu = gtk_menu_new();
2974 item = make_menu_item ("Continuous",
2975 GTK_SIGNAL_FUNC (cb_update_menu_select),
2976 GINT_TO_POINTER (GTK_UPDATE_CONTINUOUS));
2977 gtk_menu_append (GTK_MENU (menu), item);
2979 item = make_menu_item ("Discontinuous",
2980 GTK_SIGNAL_FUNC (cb_update_menu_select),
2981 GINT_TO_POINTER (GTK_UPDATE_DISCONTINUOUS));
2982 gtk_menu_append (GTK_MENU (menu), item);
2984 item = make_menu_item ("Delayed",
2985 GTK_SIGNAL_FUNC (cb_update_menu_select),
2986 GINT_TO_POINTER (GTK_UPDATE_DELAYED));
2987 gtk_menu_append (GTK_MENU (menu), item);
2989 gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
2990 gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
2991 gtk_widget_show (opt);
2993 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2994 gtk_widget_show (box2);
2996 box2 = gtk_hbox_new (FALSE, 10);
2997 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2999 /* An HScale widget for adjusting the number of digits on the
3001 label = gtk_label_new ("Scale Digits:");
3002 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
3003 gtk_widget_show (label);
3005 adj2 = gtk_adjustment_new (1.0, 0.0, 5.0, 1.0, 1.0, 0.0);
3006 gtk_signal_connect (GTK_OBJECT (adj2), "value_changed",
3007 GTK_SIGNAL_FUNC (cb_digits_scale), NULL);
3008 scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
3009 gtk_scale_set_digits (GTK_SCALE (scale), 0);
3010 gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
3011 gtk_widget_show (scale);
3013 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3014 gtk_widget_show (box2);
3016 box2 = gtk_hbox_new (FALSE, 10);
3017 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3019 /* And, one last HScale widget for adjusting the page size of the
3021 label = gtk_label_new ("Scrollbar Page Size:");
3022 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
3023 gtk_widget_show (label);
3025 adj2 = gtk_adjustment_new (1.0, 1.0, 101.0, 1.0, 1.0, 0.0);
3026 gtk_signal_connect (GTK_OBJECT (adj2), "value_changed",
3027 GTK_SIGNAL_FUNC (cb_page_size), adj1);
3028 scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
3029 gtk_scale_set_digits (GTK_SCALE (scale), 0);
3030 gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
3031 gtk_widget_show (scale);
3033 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3034 gtk_widget_show (box2);
3036 separator = gtk_hseparator_new ();
3037 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
3038 gtk_widget_show (separator);
3040 box2 = gtk_vbox_new (FALSE, 10);
3041 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3042 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
3043 gtk_widget_show (box2);
3045 button = gtk_button_new_with_label ("Quit");
3046 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
3047 GTK_SIGNAL_FUNC(gtk_main_quit),
3049 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
3050 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
3051 gtk_widget_grab_default (button);
3052 gtk_widget_show (button);
3054 gtk_widget_show (window);
3060 gtk_init(&argc, &argv);
3062 create_range_controls();
3072 You will notice that the program does not call <tt/gtk_signal_connect/
3073 for the "delete_event", but only for the "destroy" signal. This will
3074 still perform the desired function, because an unhandled
3075 "delete_event" will result in a "destroy" signal being given to the
3081 <!-- ***************************************************************** -->
3082 <sect> Miscellaneous Widgets
3083 <!-- ***************************************************************** -->
3085 <!-- ----------------------------------------------------------------- -->
3088 Labels are used a lot in GTK, and are relatively simple. Labels emit
3089 no signals as they do not have an associated X window. If you need to
3090 catch signals, or do clipping, place it inside a <ref id="sec_EventBox"
3091 name="EventBox"> widget or a Button widget.
3093 To create a new label, use:
3096 GtkWidget *gtk_label_new( char *str );
3099 The sole argument is the string you wish the label to display.
3101 To change the label's text after creation, use the function:
3104 void gtk_label_set_text( GtkLabel *label,
3108 The first argument is the label you created previously (cast
3109 using the <tt/GTK_LABEL()/ macro), and the second is the new string.
3111 The space needed for the new string will be automatically adjusted if
3112 needed. You can produce multi-line labels by putting line breaks in
3115 To retrieve the current string, use:
3118 void gtk_label_get( GtkLabel *label,
3122 The first argument is the label you've created, and the second,
3123 the return for the string. Do not free the return string, as it is
3124 used internally by GTK.
3126 The label text can be justified using:
3129 void gtk_label_set_justify( GtkLabel *label,
3130 GtkJustification jtype );
3133 Values for <tt/jtype/ are:
3137 GTK_JUSTIFY_CENTER (the default)
3141 The label widget is also capable of line wrapping the text
3142 automatically. This can be activated using:
3145 void gtk_label_set_line_wrap (GtkLabel *label,
3149 The <tt/wrap/ argument takes a TRUE or FALSE value.
3151 If you want your label underlined, then you can set a pattern on the
3155 void gtk_label_set_pattern (GtkLabel *label,
3156 const gchar *pattern);
3159 The pattern argument indicates how the underlining should look. It
3160 consists of a string of underscore and space characters. An underscore
3161 indicates that the corresponding character in the label should be
3162 underlined. For example, the string <verb/"__ __"/ would underline the
3163 first two characters and eight and ninth characters.
3165 Below is a short example to illustrate these functions. This example
3166 makes use of the Frame widget to better demonstrate the label
3167 styles. You can ignore this for now as the <ref id="sec_Frames"
3168 name="Frame"> widget is explained later on.
3171 /* example-start label label.c */
3173 #include <gtk/gtk.h>
3178 static GtkWidget *window = NULL;
3184 /* Initialise GTK */
3185 gtk_init(&argc, &argv);
3187 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3188 gtk_signal_connect (GTK_OBJECT (window), "destroy",
3189 GTK_SIGNAL_FUNC(gtk_main_quit),
3192 gtk_window_set_title (GTK_WINDOW (window), "Label");
3193 vbox = gtk_vbox_new (FALSE, 5);
3194 hbox = gtk_hbox_new (FALSE, 5);
3195 gtk_container_add (GTK_CONTAINER (window), hbox);
3196 gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
3197 gtk_container_set_border_width (GTK_CONTAINER (window), 5);
3199 frame = gtk_frame_new ("Normal Label");
3200 label = gtk_label_new ("This is a Normal label");
3201 gtk_container_add (GTK_CONTAINER (frame), label);
3202 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3204 frame = gtk_frame_new ("Multi-line Label");
3205 label = gtk_label_new ("This is a Multi-line label.\nSecond line\n" \
3207 gtk_container_add (GTK_CONTAINER (frame), label);
3208 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3210 frame = gtk_frame_new ("Left Justified Label");
3211 label = gtk_label_new ("This is a Left-Justified\n" \
3212 "Multi-line label.\nThird line");
3213 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
3214 gtk_container_add (GTK_CONTAINER (frame), label);
3215 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3217 frame = gtk_frame_new ("Right Justified Label");
3218 label = gtk_label_new ("This is a Right-Justified\nMulti-line label.\n" \
3219 "Fourth line, (j/k)");
3220 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT);
3221 gtk_container_add (GTK_CONTAINER (frame), label);
3222 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3224 vbox = gtk_vbox_new (FALSE, 5);
3225 gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
3226 frame = gtk_frame_new ("Line wrapped label");
3227 label = gtk_label_new ("This is an example of a line-wrapped label. It " \
3228 "should not be taking up the entire " /* big space to test spacing */\
3229 "width allocated to it, but automatically " \
3230 "wraps the words to fit. " \
3231 "The time has come, for all good men, to come to " \
3232 "the aid of their party. " \
3233 "The sixth sheik's six sheep's sick.\n" \
3234 " It supports multiple paragraphs correctly, " \
3235 "and correctly adds "\
3236 "many extra spaces. ");
3237 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
3238 gtk_container_add (GTK_CONTAINER (frame), label);
3239 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3241 frame = gtk_frame_new ("Filled, wrapped label");
3242 label = gtk_label_new ("This is an example of a line-wrapped, filled label. " \
3243 "It should be taking "\
3244 "up the entire width allocated to it. " \
3245 "Here is a sentence to prove "\
3246 "my point. Here is another sentence. "\
3247 "Here comes the sun, do de do de do.\n"\
3248 " This is a new paragraph.\n"\
3249 " This is another newer, longer, better " \
3250 "paragraph. It is coming to an end, "\
3252 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_FILL);
3253 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
3254 gtk_container_add (GTK_CONTAINER (frame), label);
3255 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3257 frame = gtk_frame_new ("Underlined label");
3258 label = gtk_label_new ("This label is underlined!\n"
3259 "This one is underlined in quite a funky fashion");
3260 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
3261 gtk_label_set_pattern (GTK_LABEL (label),
3262 "_________________________ _ _________ _ ______ __ _______ ___");
3263 gtk_container_add (GTK_CONTAINER (frame), label);
3264 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3266 gtk_widget_show_all (window);
3275 <!-- ----------------------------------------------------------------- -->
3278 The Arrow widget draws an arrowhead, facing in a number of possible
3279 directions and having a number of possible styles. It can be very
3280 useful when placed on a button in many applications. Like the Label
3281 widget, it emits no signals.
3283 There are only two functions for manipulating an Arrow widget:
3286 GtkWidget *gtk_arrow_new( GtkArrowType arrow_type,
3287 GtkShadowType shadow_type );
3289 void gtk_arrow_set( GtkArrow *arrow,
3290 GtkArrowType arrow_type,
3291 GtkShadowType shadow_type );
3294 The first creates a new arrow widget with the indicated type and
3295 appearance. The second allows these values to be altered
3296 retrospectively. The <tt/arrow_type/ argument may take one of the
3306 These values obviously indicate the direction in which the arrow will
3307 point. The <tt/shadow_type/ argument may take one of these values:
3311 GTK_SHADOW_OUT (the default)
3312 GTK_SHADOW_ETCHED_IN
3313 GTK_SHADOW_ETCHED_OUT
3316 Here's a brief example to illustrate their use.
3319 /* example-start arrow arrow.c */
3321 #include <gtk/gtk.h>
3323 /* Create an Arrow widget with the specified parameters
3324 * and pack it into a button */
3325 GtkWidget *create_arrow_button( GtkArrowType arrow_type,
3326 GtkShadowType shadow_type )
3331 button = gtk_button_new();
3332 arrow = gtk_arrow_new (arrow_type, shadow_type);
3334 gtk_container_add (GTK_CONTAINER (button), arrow);
3336 gtk_widget_show(button);
3337 gtk_widget_show(arrow);
3345 /* GtkWidget is the storage type for widgets */
3350 /* Initialize the toolkit */
3351 gtk_init (&argc, &argv);
3353 /* Create a new window */
3354 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3356 gtk_window_set_title (GTK_WINDOW (window), "Arrow Buttons");
3358 /* It's a good idea to do this for all windows. */
3359 gtk_signal_connect (GTK_OBJECT (window), "destroy",
3360 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
3362 /* Sets the border width of the window. */
3363 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
3365 /* Create a box to hold the arrows/buttons */
3366 box = gtk_hbox_new (FALSE, 0);
3367 gtk_container_set_border_width (GTK_CONTAINER (box), 2);
3368 gtk_container_add (GTK_CONTAINER (window), box);
3370 /* Pack and show all our widgets */
3371 gtk_widget_show(box);
3373 button = create_arrow_button(GTK_ARROW_UP, GTK_SHADOW_IN);
3374 gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3376 button = create_arrow_button(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
3377 gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3379 button = create_arrow_button(GTK_ARROW_LEFT, GTK_SHADOW_ETCHED_IN);
3380 gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3382 button = create_arrow_button(GTK_ARROW_RIGHT, GTK_SHADOW_ETCHED_OUT);
3383 gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3385 gtk_widget_show (window);
3387 /* Rest in gtk_main and wait for the fun to begin! */
3395 <!-- ----------------------------------------------------------------- -->
3396 <sect1>The Tooltips Object
3398 These are the little text strings that pop up when you leave your
3399 pointer over a button or other widget for a few seconds. They are easy
3400 to use, so I will just explain them without giving an example. If you
3401 want to see some code, take a look at the testgtk.c program
3402 distributed with GTK.
3404 Widgets that do not receive events (widgets that do not have their
3405 own window) will not work with tooltips.
3407 The first call you will use creates a new tooltip. You only need to do
3408 this once for a set of tooltips as the <tt/GtkTooltips/ object this
3409 function returns can be used to create multiple tooltips.
3412 GtkTooltips *gtk_tooltips_new( void );
3415 Once you have created a new tooltip, and the widget you wish to use it
3416 on, simply use this call to set it:
3419 void gtk_tooltips_set_tip( GtkTooltips *tooltips,
3421 const gchar *tip_text,
3422 const gchar *tip_private );
3425 The first argument is the tooltip you've already created, followed by
3426 the widget you wish to have this tooltip pop up for, and the text you
3427 wish it to say. The last argument is a text string that can be used as
3428 an identifier when using GtkTipsQuery to implement context sensitive
3429 help. For now, you can set it to NULL.
3431 <!-- TODO: sort out what how to do the context sensitive help -->
3433 Here's a short example:
3436 GtkTooltips *tooltips;
3441 tooltips = gtk_tooltips_new ();
3442 button = gtk_button_new_with_label ("button 1");
3446 gtk_tooltips_set_tip (tooltips, button, "This is button 1", NULL);
3449 There are other calls that can be used with tooltips. I will just list
3450 them with a brief description of what they do.
3453 void gtk_tooltips_enable( GtkTooltips *tooltips );
3456 Enable a disabled set of tooltips.
3459 void gtk_tooltips_disable( GtkTooltips *tooltips );
3462 Disable an enabled set of tooltips.
3465 void gtk_tooltips_set_delay( GtkTooltips *tooltips,
3470 Sets how many milliseconds you have to hold your pointer over the
3471 widget before the tooltip will pop up. The default is 500
3472 milliseconds (half a second).
3475 void gtk_tooltips_set_colors( GtkTooltips *tooltips,
3476 GdkColor *background,
3477 GdkColor *foreground );
3480 Set the foreground and background color of the tooltips.
3482 And that's all the functions associated with tooltips. More than
3483 you'll ever want to know :-)
3485 <!-- ----------------------------------------------------------------- -->
3486 <sect1> Progress Bars <label id="sec_ProgressBar">
3488 Progress bars are used to show the status of an operation. They are
3489 pretty easy to use, as you will see with the code below. But first
3490 lets start out with the calls to create a new progress bar.
3492 There are two ways to create a progress bar, one simple that takes
3493 no arguments, and one that takes an Adjustment object as an
3494 argument. If the former is used, the progress bar creates its own
3498 GtkWidget *gtk_progress_bar_new( void );
3500 GtkWidget *gtk_progress_bar_new_with_adjustment( GtkAdjustment *adjustment );
3503 The second method has the advantage that we can use the adjustment
3504 object to specify our own range parameters for the progress bar.
3506 The adjustment of a progress object can be changed dynamically using:
3509 void gtk_progress_set_adjustment( GtkProgress *progress,
3510 GtkAdjustment *adjustment );
3513 Now that the progress bar has been created we can use it.
3516 void gtk_progress_bar_update( GtkProgressBar *pbar,
3517 gfloat percentage );
3520 The first argument is the progress bar you wish to operate on, and the
3521 second argument is the amount "completed", meaning the amount the
3522 progress bar has been filled from 0-100%. This is passed to the
3523 function as a real number ranging from 0 to 1.
3525 GTK v1.2 has added new functionality to the progress bar that enables
3526 it to display its value in different ways, and to inform the user of
3527 its current value and its range.
3529 A progress bar may be set to one of a number of orientations using the
3533 void gtk_progress_bar_set_orientation( GtkProgressBar *pbar,
3534 GtkProgressBarOrientation orientation );
3537 The <tt/orientation/ argument may take one of the following
3538 values to indicate the direction in which the progress bar moves:
3541 GTK_PROGRESS_LEFT_TO_RIGHT
3542 GTK_PROGRESS_RIGHT_TO_LEFT
3543 GTK_PROGRESS_BOTTOM_TO_TOP
3544 GTK_PROGRESS_TOP_TO_BOTTOM
3547 When used as a measure of how far a process has progressed, the
3548 ProgressBar can be set to display its value in either a continuous
3549 or discrete mode. In continuous mode, the progress bar is updated for
3550 each value. In discrete mode, the progress bar is updated in a number
3551 of discrete blocks. The number of blocks is also configurable.
3553 The style of a progress bar can be set using the following function.
3556 void gtk_progress_bar_set_bar_style( GtkProgressBar *pbar,
3557 GtkProgressBarStyle style );
3560 The <tt/style/ parameter can take one of two values:
3563 GTK_PROGRESS_CONTINUOUS
3564 GTK_PROGRESS_DISCRETE
3567 The number of discrete blocks can be set by calling
3570 void gtk_progress_bar_set_discrete_blocks( GtkProgressBar *pbar,
3574 As well as indicating the amount of progress that has occured, the
3575 progress bar may be set to just indicate that there is some
3576 activity. This can be useful in situations where progress cannot be
3577 measured against a value range. Activity mode is not effected by the
3578 bar style that is described above, and overrides it. This mode is
3579 either TRUE or FALSE, and is selected by the following function.
3582 void gtk_progress_set_activity_mode( GtkProgress *progress,
3583 guint activity_mode );
3586 The step size of the activity indicator, and the number of blocks are
3587 set using the following functions.
3590 void gtk_progress_bar_set_activity_step( GtkProgressBar *pbar,
3593 void gtk_progress_bar_set_activity_blocks( GtkProgressBar *pbar,
3597 When in continuous mode, the progress bar can also display a
3598 configurable text string within its trough, using the following
3602 void gtk_progress_set_format_string( GtkProgress *progress,
3606 The <tt/format/ argument is similiar to one that would be used in a C
3607 <tt/printf/ statement. The following directives may be used within the
3611 <item> %p - percentage
3613 <item> %l - lower range value
3614 <item> %u - upper range value
3617 The displaying of this text string can be toggled using:
3620 void gtk_progress_set_show_text( GtkProgress *progress,
3624 The <tt/show_text/ argument is a boolean TRUE/FALSE value. The
3625 appearance of the text can be modified further using:
3628 void gtk_progress_set_text_alignment( GtkProgress *progress,
3633 The <tt/x_align/ and <tt/y_align/ arguments take values between 0.0
3634 and 1.0. Their values indicate the position of the text string within
3635 the trough. Values of 0.0 for both would place the string in the top
3636 left hand corner; values of 0.5 (the default) centres the text, and
3637 values of 1.0 places the text in the lower right hand corner.
3639 The current text setting of a progress object can be retrieved using
3640 the current or a specified adjustment value using the following two
3641 functions. The character string returned by these functions should be
3642 freed by the application (using the g_free() function). These
3643 functions return the formatted string that would be displayed within
3647 gchar *gtk_progress_get_current_text( GtkProgress *progress );
3649 gchar *gtk_progress_get_text_from_value( GtkProgress *progress,
3653 There is yet another way to change the range and value of a progress
3654 object using the following function:
3657 void gtk_progress_configure( GtkProgress *progress,
3663 This function provides quite a simple interface to the range and value
3664 of a progress object.
3666 The remaining functions can be used to get and set the current value
3667 of a progess object in various types and formats:
3670 void gtk_progress_set_percentage( GtkProgress *progress,
3671 gfloat percentage );
3673 void gtk_progress_set_value( GtkProgress *progress,
3676 gfloat gtk_progress_get_value( GtkProgress *progress );
3678 gfloat gtk_progress_get_current_percentage( GtkProgress *progress );
3680 gfloat gtk_progress_get_percentage_from_value( GtkProgress *progress,
3684 These functions are pretty self explanatory. The last function uses
3685 the the adjustment of the specified progess object to compute the
3686 percentage value of the given range value.
3688 Progress Bars are usually used with timeouts or other such functions
3689 (see section on <ref id="sec_timeouts" name="Timeouts, I/O and Idle
3690 Functions">) to give the illusion of multitasking. All will employ the
3691 gtk_progress_bar_update function in the same manner.
3693 Here is an example of the progress bar, updated using timeouts. This
3694 code also shows you how to reset the Progress Bar.
3697 /* example-start progressbar progressbar.c */
3699 #include <gtk/gtk.h>
3701 typedef struct _ProgressData {
3707 /* Update the value of the progress bar so that we get
3709 gint progress_timeout( gpointer data )
3714 /* Calculate the value of the progress bar using the
3715 * value range set in the adjustment object */
3717 new_val = gtk_progress_get_value( GTK_PROGRESS(data) ) + 1;
3719 adj = GTK_PROGRESS (data)->adjustment;
3720 if (new_val > adj->upper)
3721 new_val = adj->lower;
3723 /* Set the new value */
3724 gtk_progress_set_value (GTK_PROGRESS (data), new_val);
3726 /* As this is a timeout function, return TRUE so that it
3727 * continues to get called */
3731 /* Callback that toggles the text display within the progress
3733 void toggle_show_text( GtkWidget *widget,
3734 ProgressData *pdata )
3736 gtk_progress_set_show_text (GTK_PROGRESS (pdata->pbar),
3737 GTK_TOGGLE_BUTTON (widget)->active);
3740 /* Callback that toggles the activity mode of the progress
3742 void toggle_activity_mode( GtkWidget *widget,
3743 ProgressData *pdata )
3745 gtk_progress_set_activity_mode (GTK_PROGRESS (pdata->pbar),
3746 GTK_TOGGLE_BUTTON (widget)->active);
3749 /* Callback that toggles the continuous mode of the progress
3751 void set_continuous_mode( GtkWidget *widget,
3752 ProgressData *pdata )
3754 gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
3755 GTK_PROGRESS_CONTINUOUS);
3758 /* Callback that toggles the discrete mode of the progress
3760 void set_discrete_mode( GtkWidget *widget,
3761 ProgressData *pdata )
3763 gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
3764 GTK_PROGRESS_DISCRETE);
3767 /* Clean up allocated memory and remove the timer */
3768 void destroy_progress( GtkWidget *widget,
3769 ProgressData *pdata)
3771 gtk_timeout_remove (pdata->timer);
3773 pdata->window = NULL;
3781 ProgressData *pdata;
3783 GtkWidget *separator;
3790 gtk_init (&argc, &argv);
3792 /* Allocate memory for the data that is passwd to the callbacks */
3793 pdata = g_malloc( sizeof(ProgressData) );
3795 pdata->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3796 gtk_window_set_policy (GTK_WINDOW (pdata->window), FALSE, FALSE, TRUE);
3798 gtk_signal_connect (GTK_OBJECT (pdata->window), "destroy",
3799 GTK_SIGNAL_FUNC (destroy_progress),
3801 gtk_window_set_title (GTK_WINDOW (pdata->window), "GtkProgressBar");
3802 gtk_container_set_border_width (GTK_CONTAINER (pdata->window), 0);
3804 vbox = gtk_vbox_new (FALSE, 5);
3805 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
3806 gtk_container_add (GTK_CONTAINER (pdata->window), vbox);
3807 gtk_widget_show(vbox);
3809 /* Create a centering alignment object */
3810 align = gtk_alignment_new (0.5, 0.5, 0, 0);
3811 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 5);
3812 gtk_widget_show(align);
3814 /* Create a Adjusment object to hold the range of the
3816 adj = (GtkAdjustment *) gtk_adjustment_new (0, 1, 150, 0, 0, 0);
3818 /* Create the GtkProgressBar using the adjustment */
3819 pdata->pbar = gtk_progress_bar_new_with_adjustment (adj);
3821 /* Set the format of the string that can be displayed in the
3822 * trough of the progress bar:
3825 * %l - lower range value
3826 * %u - upper range value */
3827 gtk_progress_set_format_string (GTK_PROGRESS (pdata->pbar),
3828 "%v from [%l-%u] (=%p%%)");
3829 gtk_container_add (GTK_CONTAINER (align), pdata->pbar);
3830 gtk_widget_show(pdata->pbar);
3832 /* Add a timer callback to update the value of the progress bar */
3833 pdata->timer = gtk_timeout_add (100, progress_timeout, pdata->pbar);
3835 separator = gtk_hseparator_new ();
3836 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
3837 gtk_widget_show(separator);
3839 /* rows, columns, homogeneous */
3840 table = gtk_table_new (2, 3, FALSE);
3841 gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0);
3842 gtk_widget_show(table);
3844 /* Add a check button to select displaying of the trough text */
3845 check = gtk_check_button_new_with_label ("Show text");
3846 gtk_table_attach (GTK_TABLE (table), check, 0, 1, 0, 1,
3847 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3849 gtk_signal_connect (GTK_OBJECT (check), "clicked",
3850 GTK_SIGNAL_FUNC (toggle_show_text),
3852 gtk_widget_show(check);
3854 /* Add a check button to toggle activity mode */
3855 check = gtk_check_button_new_with_label ("Activity mode");
3856 gtk_table_attach (GTK_TABLE (table), check, 0, 1, 1, 2,
3857 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3859 gtk_signal_connect (GTK_OBJECT (check), "clicked",
3860 GTK_SIGNAL_FUNC (toggle_activity_mode),
3862 gtk_widget_show(check);
3864 separator = gtk_vseparator_new ();
3865 gtk_table_attach (GTK_TABLE (table), separator, 1, 2, 0, 2,
3866 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3868 gtk_widget_show(separator);
3870 /* Add a radio button to select continuous display mode */
3871 button = gtk_radio_button_new_with_label (NULL, "Continuous");
3872 gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1,
3873 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3875 gtk_signal_connect (GTK_OBJECT (button), "clicked",
3876 GTK_SIGNAL_FUNC (set_continuous_mode),
3878 gtk_widget_show (button);
3880 /* Add a radio button to select discrete display mode */
3881 button = gtk_radio_button_new_with_label(
3882 gtk_radio_button_group (GTK_RADIO_BUTTON (button)),
3884 gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2,
3885 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3887 gtk_signal_connect (GTK_OBJECT (button), "clicked",
3888 GTK_SIGNAL_FUNC (set_discrete_mode),
3890 gtk_widget_show (button);
3892 separator = gtk_hseparator_new ();
3893 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
3894 gtk_widget_show(separator);
3896 /* Add a button to exit the program */
3897 button = gtk_button_new_with_label ("close");
3898 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
3899 (GtkSignalFunc) gtk_widget_destroy,
3900 GTK_OBJECT (pdata->window));
3901 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
3903 /* This makes it so the button is the default. */
3904 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
3906 /* This grabs this button to be the default button. Simply hitting
3907 * the "Enter" key will cause this button to activate. */
3908 gtk_widget_grab_default (button);
3909 gtk_widget_show(button);
3911 gtk_widget_show (pdata->window);
3920 <!-- ----------------------------------------------------------------- -->
3923 The Dialog widget is very simple, and is actually just a window with a
3924 few things pre-packed into it for you. The structure for a Dialog is:
3932 GtkWidget *action_area;
3936 So you see, it simply creates a window, and then packs a vbox into the
3937 top, which contains a separator and then an hbox called the
3940 The Dialog widget can be used for pop-up messages to the user, and
3941 other similar tasks. It is really basic, and there is only one
3942 function for the dialog box, which is:
3945 GtkWidget *gtk_dialog_new( void );
3948 So to create a new dialog box, use,
3952 window = gtk_dialog_new ();
3955 This will create the dialog box, and it is now up to you to use it.
3956 You could pack a button in the action_area by doing something like this:
3960 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area),
3961 button, TRUE, TRUE, 0);
3962 gtk_widget_show (button);
3965 And you could add to the vbox area by packing, for instance, a label
3966 in it, try something like this:
3969 label = gtk_label_new ("Dialogs are groovy");
3970 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox),
3971 label, TRUE, TRUE, 0);
3972 gtk_widget_show (label);
3975 As an example in using the dialog box, you could put two buttons in
3976 the action_area, a Cancel button and an Ok button, and a label in the
3977 vbox area, asking the user a question or giving an error etc. Then
3978 you could attach a different signal to each of the buttons and perform
3979 the operation the user selects.
3981 If the simple functionality provided by the default vertical and
3982 horizontal boxes in the two areas doesn't give you enough control for
3983 your application, then you can simply pack another layout widget into
3984 the boxes provided. For example, you could pack a table into the
3987 <!-- ----------------------------------------------------------------- -->
3988 <sect1> Pixmaps <label id="sec_Pixmaps">
3990 Pixmaps are data structures that contain pictures. These pictures can
3991 be used in various places, but most commonly as icons on the X
3992 desktop, or as cursors.
3994 A pixmap which only has 2 colors is called a bitmap, and there are a
3995 few additional routines for handling this common special case.
3997 To understand pixmaps, it would help to understand how X window
3998 system works. Under X, applications do not need to be running on the
3999 same computer that is interacting with the user. Instead, the various
4000 applications, called "clients", all communicate with a program which
4001 displays the graphics and handles the keyboard and mouse. This
4002 program which interacts directly with the user is called a "display
4003 server" or "X server." Since the communication might take place over
4004 a network, it's important to keep some information with the X server.
4005 Pixmaps, for example, are stored in the memory of the X server. This
4006 means that once pixmap values are set, they don't need to keep getting
4007 transmitted over the network; instead a command is sent to "display
4008 pixmap number XYZ here." Even if you aren't using X with GTK
4009 currently, using constructs such as Pixmaps will make your programs
4010 work acceptably under X.
4012 To use pixmaps in GTK, we must first build a GdkPixmap structure using
4013 routines from the GDK layer. Pixmaps can either be created from
4014 in-memory data, or from data read from a file. We'll go through each
4015 of the calls to create a pixmap.
4018 GdkPixmap *gdk_bitmap_create_from_data( GdkWindow *window,
4024 This routine is used to create a single-plane pixmap (2 colors) from
4025 data in memory. Each bit of the data represents whether that pixel is
4026 off or on. Width and height are in pixels. The GdkWindow pointer is to
4027 the current window, since a pixmap's resources are meaningful only in
4028 the context of the screen where it is to be displayed.
4031 GdkPixmap *gdk_pixmap_create_from_data( GdkWindow *window,
4040 This is used to create a pixmap of the given depth (number of colors) from
4041 the bitmap data specified. <tt/fg/ and <tt/bg/ are the foreground and
4042 background color to use.
4045 GdkPixmap *gdk_pixmap_create_from_xpm( GdkWindow *window,
4047 GdkColor *transparent_color,
4048 const gchar *filename );
4051 XPM format is a readable pixmap representation for the X Window
4052 System. It is widely used and many different utilities are available
4053 for creating image files in this format. The file specified by
4054 filename must contain an image in that format and it is loaded into
4055 the pixmap structure. The mask specifies which bits of the pixmap are
4056 opaque. All other bits are colored using the color specified by
4057 transparent_color. An example using this follows below.
4060 GdkPixmap *gdk_pixmap_create_from_xpm_d( GdkWindow *window,
4062 GdkColor *transparent_color,
4066 Small images can be incorporated into a program as data in the XPM
4067 format. A pixmap is created using this data, instead of reading it
4068 from a file. An example of such data is
4072 static const char * xpm_data[] = {
4075 ". c #000000000000",
4076 "X c #FFFFFFFFFFFF",
4095 When we're done using a pixmap and not likely to reuse it again soon,
4096 it is a good idea to release the resource using
4097 gdk_pixmap_unref(). Pixmaps should be considered a precious resource,
4098 because they take up memory in the end-user's X server process. Even
4099 though the X client you write may run on a powerful "server" computer,
4100 the user may be running the X server on a small personal computer.
4102 Once we've created a pixmap, we can display it as a GTK widget. We
4103 must create a GTK pixmap widget to contain the GDK pixmap. This is
4107 GtkWidget *gtk_pixmap_new( GdkPixmap *pixmap,
4111 The other pixmap widget calls are
4114 guint gtk_pixmap_get_type( void );
4116 void gtk_pixmap_set( GtkPixmap *pixmap,
4120 void gtk_pixmap_get( GtkPixmap *pixmap,
4125 gtk_pixmap_set is used to change the pixmap that the widget is currently
4126 managing. Val is the pixmap created using GDK.
4128 The following is an example of using a pixmap in a button.
4131 /* example-start pixmap pixmap.c */
4133 #include <gtk/gtk.h>
4136 /* XPM data of Open-File icon */
4137 static const char * xpm_data[] = {
4140 ". c #000000000000",
4141 "X c #FFFFFFFFFFFF",
4160 /* when invoked (via signal delete_event), terminates the application.
4162 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
4167 /* is invoked when the button is clicked. It just prints a message.
4169 void button_clicked( GtkWidget *widget, gpointer data ) {
4170 printf( "button clicked\n" );
4173 int main( int argc, char *argv[] )
4175 /* GtkWidget is the storage type for widgets */
4176 GtkWidget *window, *pixmapwid, *button;
4181 /* create the main window, and attach delete_event signal to terminating
4183 gtk_init( &argc, &argv );
4184 window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
4185 gtk_signal_connect( GTK_OBJECT (window), "delete_event",
4186 GTK_SIGNAL_FUNC (close_application), NULL );
4187 gtk_container_set_border_width( GTK_CONTAINER (window), 10 );
4188 gtk_widget_show( window );
4190 /* now for the pixmap from gdk */
4191 style = gtk_widget_get_style( window );
4192 pixmap = gdk_pixmap_create_from_xpm_d( window->window, &mask,
4193 &style->bg[GTK_STATE_NORMAL],
4194 (gchar **)xpm_data );
4196 /* a pixmap widget to contain the pixmap */
4197 pixmapwid = gtk_pixmap_new( pixmap, mask );
4198 gtk_widget_show( pixmapwid );
4200 /* a button to contain the pixmap widget */
4201 button = gtk_button_new();
4202 gtk_container_add( GTK_CONTAINER(button), pixmapwid );
4203 gtk_container_add( GTK_CONTAINER(window), button );
4204 gtk_widget_show( button );
4206 gtk_signal_connect( GTK_OBJECT(button), "clicked",
4207 GTK_SIGNAL_FUNC(button_clicked), NULL );
4209 /* show the window */
4217 To load a file from an XPM data file called icon0.xpm in the current
4218 directory, we would have created the pixmap thus
4221 /* load a pixmap from a file */
4222 pixmap = gdk_pixmap_create_from_xpm( window->window, &mask,
4223 &style->bg[GTK_STATE_NORMAL],
4225 pixmapwid = gtk_pixmap_new( pixmap, mask );
4226 gtk_widget_show( pixmapwid );
4227 gtk_container_add( GTK_CONTAINER(window), pixmapwid );
4230 A disadvantage of using pixmaps is that the displayed object is always
4231 rectangular, regardless of the image. We would like to create desktops
4232 and applications with icons that have more natural shapes. For
4233 example, for a game interface, we would like to have round buttons to
4234 push. The way to do this is using shaped windows.
4236 A shaped window is simply a pixmap where the background pixels are
4237 transparent. This way, when the background image is multi-colored, we
4238 don't overwrite it with a rectangular, non-matching border around our
4239 icon. The following example displays a full wheelbarrow image on the
4243 /* example-start wheelbarrow wheelbarrow.c */
4245 #include <gtk/gtk.h>
4248 static char * WheelbarrowFull_xpm[] = {
4251 ". c #DF7DCF3CC71B",
4252 "X c #965875D669A6",
4253 "o c #71C671C671C6",
4254 "O c #A699A289A699",
4255 "+ c #965892489658",
4256 "@ c #8E38410330C2",
4257 "# c #D75C7DF769A6",
4258 "$ c #F7DECF3CC71B",
4259 "% c #96588A288E38",
4260 "& c #A69992489E79",
4261 "* c #8E3886178E38",
4262 "= c #104008200820",
4263 "- c #596510401040",
4264 "; c #C71B30C230C2",
4265 ": c #C71B9A699658",
4266 "> c #618561856185",
4267 ", c #20811C712081",
4268 "< c #104000000000",
4269 "1 c #861720812081",
4270 "2 c #DF7D4D344103",
4271 "3 c #79E769A671C6",
4272 "4 c #861782078617",
4273 "5 c #41033CF34103",
4274 "6 c #000000000000",
4275 "7 c #49241C711040",
4276 "8 c #492445144924",
4277 "9 c #082008200820",
4278 "0 c #69A618611861",
4279 "q c #B6DA71C65144",
4280 "w c #410330C238E3",
4281 "e c #CF3CBAEAB6DA",
4282 "r c #71C6451430C2",
4283 "t c #EFBEDB6CD75C",
4284 "y c #28A208200820",
4285 "u c #186110401040",
4286 "i c #596528A21861",
4287 "p c #71C661855965",
4288 "a c #A69996589658",
4289 "s c #30C228A230C2",
4290 "d c #BEFBA289AEBA",
4291 "f c #596545145144",
4292 "g c #30C230C230C2",
4293 "h c #8E3882078617",
4294 "j c #208118612081",
4295 "k c #38E30C300820",
4296 "l c #30C2208128A2",
4297 "z c #38E328A238E3",
4298 "x c #514438E34924",
4299 "c c #618555555965",
4300 "v c #30C2208130C2",
4301 "b c #38E328A230C2",
4302 "n c #28A228A228A2",
4303 "m c #41032CB228A2",
4304 "M c #104010401040",
4305 "N c #492438E34103",
4306 "B c #28A2208128A2",
4307 "V c #A699596538E3",
4308 "C c #30C21C711040",
4309 "Z c #30C218611040",
4310 "A c #965865955965",
4311 "S c #618534D32081",
4312 "D c #38E31C711040",
4313 "F c #082000000820",
4322 "ty> 459@>+&& ",
4324 "%$;=* *3:.Xa.dfg> ",
4325 "Oh$;ya *3d.a8j,Xe.d3g8+ ",
4326 " Oh$;ka *3d$a8lz,,xxc:.e3g54 ",
4327 " Oh$;kO *pd$%svbzz,sxxxxfX..&wn> ",
4328 " Oh$@mO *3dthwlsslszjzxxxxxxx3:td8M4 ",
4329 " Oh$@g& *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B* ",
4330 " Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5& ",
4331 " Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM* ",
4332 " OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
4333 " 2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
4334 " :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
4335 " +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
4336 " *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&en",
4337 " p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>",
4338 " OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ",
4339 " 3206Bwxxszx%et.eaAp77m77mmmf3&eeeg* ",
4340 " @26MvzxNzvlbwfpdettttttttttt.c,n& ",
4341 " *;16=lsNwwNwgsvslbwwvccc3pcfu<o ",
4342 " p;<69BvwwsszslllbBlllllllu<5+ ",
4343 " OS0y6FBlvvvzvzss,u=Blllj=54 ",
4344 " c1-699Blvlllllu7k96MMMg4 ",
4345 " *10y8n6FjvllllB<166668 ",
4346 " S-kg+>666<M<996-y6n<8* ",
4347 " p71=4 m69996kD8Z-66698&& ",
4348 " &i0ycm6n4 ogk17,0<6666g ",
4349 " N-k-<> >=01-kuu666> ",
4350 " ,6ky& &46-10ul,66, ",
4351 " Ou0<> o66y<ulw<66& ",
4352 " *kk5 >66By7=xu664 ",
4353 " <<M4 466lj<Mxu66o ",
4354 " *>> +66uv,zN666* ",
4364 /* When invoked (via signal delete_event), terminates the application */
4365 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
4369 int main (int argc, char *argv[])
4371 /* GtkWidget is the storage type for widgets */
4372 GtkWidget *window, *pixmap, *fixed;
4373 GdkPixmap *gdk_pixmap;
4378 /* Create the main window, and attach delete_event signal to terminate
4379 * the application. Note that the main window will not have a titlebar
4380 * since we're making it a popup. */
4381 gtk_init (&argc, &argv);
4382 window = gtk_window_new( GTK_WINDOW_POPUP );
4383 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
4384 GTK_SIGNAL_FUNC (close_application), NULL);
4385 gtk_widget_show (window);
4387 /* Now for the pixmap and the pixmap widget */
4388 style = gtk_widget_get_default_style();
4389 gc = style->black_gc;
4390 gdk_pixmap = gdk_pixmap_create_from_xpm_d( window->window, &mask,
4391 &style->bg[GTK_STATE_NORMAL],
4392 WheelbarrowFull_xpm );
4393 pixmap = gtk_pixmap_new( gdk_pixmap, mask );
4394 gtk_widget_show( pixmap );
4396 /* To display the pixmap, we use a fixed widget to place the pixmap */
4397 fixed = gtk_fixed_new();
4398 gtk_widget_set_usize( fixed, 200, 200 );
4399 gtk_fixed_put( GTK_FIXED(fixed), pixmap, 0, 0 );
4400 gtk_container_add( GTK_CONTAINER(window), fixed );
4401 gtk_widget_show( fixed );
4403 /* This masks out everything except for the image itself */
4404 gtk_widget_shape_combine_mask( window, mask, 0, 0 );
4406 /* show the window */
4407 gtk_widget_set_uposition( window, 20, 400 );
4408 gtk_widget_show( window );
4416 To make the wheelbarrow image sensitive, we could attach the button
4417 press event signal to make it do something. The following few lines
4418 would make the picture sensitive to a mouse button being pressed which
4419 makes the application terminate.
4422 gtk_widget_set_events( window,
4423 gtk_widget_get_events( window ) |
4424 GDK_BUTTON_PRESS_MASK );
4426 gtk_signal_connect( GTK_OBJECT(window), "button_press_event",
4427 GTK_SIGNAL_FUNC(close_application), NULL );
4430 <!-- ----------------------------------------------------------------- -->
4433 Ruler widgets are used to indicate the location of the mouse pointer
4434 in a given window. A window can have a vertical ruler spanning across
4435 the width and a horizontal ruler spanning down the height. A small
4436 triangular indicator on the ruler shows the exact location of the
4437 pointer relative to the ruler.
4439 A ruler must first be created. Horizontal and vertical rulers are
4443 GtkWidget *gtk_hruler_new( void ); /* horizontal ruler */
4445 GtkWidget *gtk_vruler_new( void ); /* vertical ruler */
4448 Once a ruler is created, we can define the unit of measurement. Units
4449 of measure for rulers can be<tt/GTK_PIXELS/, <tt/GTK_INCHES/ or
4450 <tt/GTK_CENTIMETERS/. This is set using
4453 void gtk_ruler_set_metric( GtkRuler *ruler,
4454 GtkMetricType metric );
4457 The default measure is <tt/GTK_PIXELS/.
4460 gtk_ruler_set_metric( GTK_RULER(ruler), GTK_PIXELS );
4463 Other important characteristics of a ruler are how to mark the units
4464 of scale and where the position indicator is initially placed. These
4465 are set for a ruler using
4468 void gtk_ruler_set_range( GtkRuler *ruler,
4475 The lower and upper arguments define the extent of the ruler, and
4476 max_size is the largest possible number that will be displayed.
4477 Position defines the initial position of the pointer indicator within
4480 A vertical ruler can span an 800 pixel wide window thus
4483 gtk_ruler_set_range( GTK_RULER(vruler), 0, 800, 0, 800);
4486 The markings displayed on the ruler will be from 0 to 800, with a
4487 number for every 100 pixels. If instead we wanted the ruler to range
4488 from 7 to 16, we would code
4491 gtk_ruler_set_range( GTK_RULER(vruler), 7, 16, 0, 20);
4494 The indicator on the ruler is a small triangular mark that indicates
4495 the position of the pointer relative to the ruler. If the ruler is
4496 used to follow the mouse pointer, the motion_notify_event signal
4497 should be connected to the motion_notify_event method of the ruler.
4498 To follow all mouse movements within a window area, we would use
4501 #define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
4503 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4504 (GtkSignalFunc)EVENT_METHOD(ruler, motion_notify_event),
4505 GTK_OBJECT(ruler) );
4508 The following example creates a drawing area with a horizontal ruler
4509 above it and a vertical ruler to the left of it. The size of the
4510 drawing area is 600 pixels wide by 400 pixels high. The horizontal
4511 ruler spans from 7 to 13 with a mark every 100 pixels, while the
4512 vertical ruler spans from 0 to 400 with a mark every 100 pixels.
4513 Placement of the drawing area and the rulers is done using a table.
4516 /* example-start rulers rulers.c */
4518 #include <gtk/gtk.h>
4520 #define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
4525 /* This routine gets control when the close button is clicked */
4526 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
4530 /* The main routine */
4531 int main( int argc, char *argv[] ) {
4532 GtkWidget *window, *table, *area, *hrule, *vrule;
4534 /* Initialize GTK and create the main window */
4535 gtk_init( &argc, &argv );
4537 window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
4538 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
4539 GTK_SIGNAL_FUNC( close_application ), NULL);
4540 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
4542 /* Create a table for placing the ruler and the drawing area */
4543 table = gtk_table_new( 3, 2, FALSE );
4544 gtk_container_add( GTK_CONTAINER(window), table );
4546 area = gtk_drawing_area_new();
4547 gtk_drawing_area_size( (GtkDrawingArea *)area, XSIZE, YSIZE );
4548 gtk_table_attach( GTK_TABLE(table), area, 1, 2, 1, 2,
4549 GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0 );
4550 gtk_widget_set_events( area, GDK_POINTER_MOTION_MASK |
4551 GDK_POINTER_MOTION_HINT_MASK );
4553 /* The horizontal ruler goes on top. As the mouse moves across the
4554 * drawing area, a motion_notify_event is passed to the
4555 * appropriate event handler for the ruler. */
4556 hrule = gtk_hruler_new();
4557 gtk_ruler_set_metric( GTK_RULER(hrule), GTK_PIXELS );
4558 gtk_ruler_set_range( GTK_RULER(hrule), 7, 13, 0, 20 );
4559 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4560 (GtkSignalFunc)EVENT_METHOD(hrule,
4561 motion_notify_event),
4562 GTK_OBJECT(hrule) );
4563 /* GTK_WIDGET_CLASS(GTK_OBJECT(hrule)->klass)->motion_notify_event, */
4564 gtk_table_attach( GTK_TABLE(table), hrule, 1, 2, 0, 1,
4565 GTK_EXPAND|GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0 );
4567 /* The vertical ruler goes on the left. As the mouse moves across
4568 * the drawing area, a motion_notify_event is passed to the
4569 * appropriate event handler for the ruler. */
4570 vrule = gtk_vruler_new();
4571 gtk_ruler_set_metric( GTK_RULER(vrule), GTK_PIXELS );
4572 gtk_ruler_set_range( GTK_RULER(vrule), 0, YSIZE, 10, YSIZE );
4573 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4575 GTK_WIDGET_CLASS(GTK_OBJECT(vrule)->klass)->
4576 motion_notify_event,
4577 GTK_OBJECT(vrule) );
4578 gtk_table_attach( GTK_TABLE(table), vrule, 0, 1, 1, 2,
4579 GTK_FILL, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0 );
4581 /* Now show everything */
4582 gtk_widget_show( area );
4583 gtk_widget_show( hrule );
4584 gtk_widget_show( vrule );
4585 gtk_widget_show( table );
4586 gtk_widget_show( window );
4594 <!-- ----------------------------------------------------------------- -->
4597 Statusbars are simple widgets used to display a text message. They
4598 keep a stack of the messages pushed onto them, so that popping the
4599 current message will re-display the previous text message.
4601 In order to allow different parts of an application to use the same
4602 statusbar to display messages, the statusbar widget issues Context
4603 Identifiers which are used to identify different "users". The message
4604 on top of the stack is the one displayed, no matter what context it is
4605 in. Messages are stacked in last-in-first-out order, not context
4608 A statusbar is created with a call to:
4611 GtkWidget *gtk_statusbar_new( void );
4614 A new Context Identifier is requested using a call to the following
4615 function with a short textual description of the context:
4618 guint gtk_statusbar_get_context_id( GtkStatusbar *statusbar,
4619 const gchar *context_description );
4622 There are three functions that can operate on statusbars:
4625 guint gtk_statusbar_push( GtkStatusbar *statusbar,
4629 void gtk_statusbar_pop( GtkStatusbar *statusbar)
4632 void gtk_statusbar_remove( GtkStatusbar *statusbar,
4637 The first, gtk_statusbar_push, is used to add a new message to the
4638 statusbar. It returns a Message Identifier, which can be passed later
4639 to the function gtk_statusbar_remove to remove the message with the
4640 given Message and Context Identifiers from the statusbar's stack.
4642 The function gtk_statusbar_pop removes the message highest in the
4643 stack with the given Context Identifier.
4645 The following example creates a statusbar and two buttons, one for
4646 pushing items onto the statusbar, and one for popping the last item
4650 /* example-start statusbar statusbar.c */
4652 #include <gtk/gtk.h>
4655 GtkWidget *status_bar;
4657 void push_item (GtkWidget *widget, gpointer data)
4659 static int count = 1;
4662 g_snprintf(buff, 20, "Item %d", count++);
4663 gtk_statusbar_push( GTK_STATUSBAR(status_bar), GPOINTER_TO_INT(data), buff);
4668 void pop_item (GtkWidget *widget, gpointer data)
4670 gtk_statusbar_pop( GTK_STATUSBAR(status_bar), GPOINTER_TO_INT(data) );
4674 int main (int argc, char *argv[])
4683 gtk_init (&argc, &argv);
4685 /* create a new window */
4686 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4687 gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
4688 gtk_window_set_title(GTK_WINDOW (window), "GTK Statusbar Example");
4689 gtk_signal_connect(GTK_OBJECT (window), "delete_event",
4690 (GtkSignalFunc) gtk_exit, NULL);
4692 vbox = gtk_vbox_new(FALSE, 1);
4693 gtk_container_add(GTK_CONTAINER(window), vbox);
4694 gtk_widget_show(vbox);
4696 status_bar = gtk_statusbar_new();
4697 gtk_box_pack_start (GTK_BOX (vbox), status_bar, TRUE, TRUE, 0);
4698 gtk_widget_show (status_bar);
4700 context_id = gtk_statusbar_get_context_id(
4701 GTK_STATUSBAR(status_bar), "Statusbar example");
4703 button = gtk_button_new_with_label("push item");
4704 gtk_signal_connect(GTK_OBJECT(button), "clicked",
4705 GTK_SIGNAL_FUNC (push_item), GINT_TO_POINTER(context_id) );
4706 gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 2);
4707 gtk_widget_show(button);
4709 button = gtk_button_new_with_label("pop last item");
4710 gtk_signal_connect(GTK_OBJECT(button), "clicked",
4711 GTK_SIGNAL_FUNC (pop_item), GINT_TO_POINTER(context_id) );
4712 gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 2);
4713 gtk_widget_show(button);
4715 /* always display the window as the last step so it all splashes on
4716 * the screen at once. */
4717 gtk_widget_show(window);
4726 <!-- ----------------------------------------------------------------- -->
4729 The Entry widget allows text to be typed and displayed in a single line
4730 text box. The text may be set with function calls that allow new text
4731 to replace, prepend or append the current contents of the Entry widget.
4733 There are two functions for creating Entry widgets:
4736 GtkWidget *gtk_entry_new( void );
4738 GtkWidget *gtk_entry_new_with_max_length( guint16 max );
4741 The first just creates a new Entry widget, whilst the second creates a
4742 new Entry and sets a limit on the length of the text within the Entry.
4744 There are several functions for altering the text which is currently
4745 within the Entry widget.
4748 void gtk_entry_set_text( GtkEntry *entry,
4749 const gchar *text );
4751 void gtk_entry_append_text( GtkEntry *entry,
4752 const gchar *text );
4754 void gtk_entry_prepend_text( GtkEntry *entry,
4755 const gchar *text );
4758 The function gtk_entry_set_text sets the contents of the Entry widget,
4759 replacing the current contents. The functions gtk_entry_append_text
4760 and gtk_entry_prepend_text allow the current contents to be appended
4763 The next function allows the current insertion point to be set.
4766 void gtk_entry_set_position( GtkEntry *entry,
4770 The contents of the Entry can be retrieved by using a call to the
4771 following function. This is useful in the callback functions described below.
4774 gchar *gtk_entry_get_text( GtkEntry *entry );
4777 The value returned by this function is used internally, and must not
4778 be freed using either free() or g_free()
4780 If we don't want the contents of the Entry to be changed by someone typing
4781 into it, we can change its editable state.
4784 void gtk_entry_set_editable( GtkEntry *entry,
4785 gboolean editable );
4788 The function above allows us to toggle the editable state of the
4789 Entry widget by passing in a TRUE or FALSE value for the <tt/editable/
4792 If we are using the Entry where we don't want the text entered to be
4793 visible, for example when a password is being entered, we can use the
4794 following function, which also takes a boolean flag.
4797 void gtk_entry_set_visibility( GtkEntry *entry,
4801 A region of the text may be set as selected by using the following
4802 function. This would most often be used after setting some default
4803 text in an Entry, making it easy for the user to remove it.
4806 void gtk_entry_select_region( GtkEntry *entry,
4811 If we want to catch when the user has entered text, we can connect to
4812 the <tt/activate/ or <tt/changed/ signal. Activate is raised when the
4813 user hits the enter key within the Entry widget. Changed is raised
4814 when the text changes at all, e.g., for every character entered or
4817 The following code is an example of using an Entry widget.
4820 /* example-start entry entry.c */
4822 #include <gtk/gtk.h>
4824 void enter_callback(GtkWidget *widget, GtkWidget *entry)
4827 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
4828 printf("Entry contents: %s\n", entry_text);
4831 void entry_toggle_editable (GtkWidget *checkbutton,
4834 gtk_entry_set_editable(GTK_ENTRY(entry),
4835 GTK_TOGGLE_BUTTON(checkbutton)->active);
4838 void entry_toggle_visibility (GtkWidget *checkbutton,
4841 gtk_entry_set_visibility(GTK_ENTRY(entry),
4842 GTK_TOGGLE_BUTTON(checkbutton)->active);
4845 int main (int argc, char *argv[])
4849 GtkWidget *vbox, *hbox;
4854 gtk_init (&argc, &argv);
4856 /* create a new window */
4857 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4858 gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
4859 gtk_window_set_title(GTK_WINDOW (window), "GTK Entry");
4860 gtk_signal_connect(GTK_OBJECT (window), "delete_event",
4861 (GtkSignalFunc) gtk_exit, NULL);
4863 vbox = gtk_vbox_new (FALSE, 0);
4864 gtk_container_add (GTK_CONTAINER (window), vbox);
4865 gtk_widget_show (vbox);
4867 entry = gtk_entry_new_with_max_length (50);
4868 gtk_signal_connect(GTK_OBJECT(entry), "activate",
4869 GTK_SIGNAL_FUNC(enter_callback),
4871 gtk_entry_set_text (GTK_ENTRY (entry), "hello");
4872 gtk_entry_append_text (GTK_ENTRY (entry), " world");
4873 gtk_entry_select_region (GTK_ENTRY (entry),
4874 0, GTK_ENTRY(entry)->text_length);
4875 gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0);
4876 gtk_widget_show (entry);
4878 hbox = gtk_hbox_new (FALSE, 0);
4879 gtk_container_add (GTK_CONTAINER (vbox), hbox);
4880 gtk_widget_show (hbox);
4882 check = gtk_check_button_new_with_label("Editable");
4883 gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
4884 gtk_signal_connect (GTK_OBJECT(check), "toggled",
4885 GTK_SIGNAL_FUNC(entry_toggle_editable), entry);
4886 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);
4887 gtk_widget_show (check);
4889 check = gtk_check_button_new_with_label("Visible");
4890 gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
4891 gtk_signal_connect (GTK_OBJECT(check), "toggled",
4892 GTK_SIGNAL_FUNC(entry_toggle_visibility), entry);
4893 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);
4894 gtk_widget_show (check);
4896 button = gtk_button_new_with_label ("Close");
4897 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
4898 GTK_SIGNAL_FUNC(gtk_exit),
4899 GTK_OBJECT (window));
4900 gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
4901 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
4902 gtk_widget_grab_default (button);
4903 gtk_widget_show (button);
4905 gtk_widget_show(window);
4913 <!-- ----------------------------------------------------------------- -->
4916 The Spin Button widget is generally used to allow the user to select a
4917 value from a range of numeric values. It consists of a text
4918 entry box with up and down arrow buttons attached to the
4919 side. Selecting one of the buttons causes the value to "spin" up and
4920 down the range of possible values. The entry box may also be edited
4921 directly to enter a specific value.
4923 The Spin Button allows the value to have zero or a number of decimal
4924 places and to be incremented/decremented in configurable steps. The
4925 action of holding down one of the buttons optionally results in an
4926 acceleration of change in the value according to how long it is
4929 The Spin Button uses an <ref id="sec_Adjustment" name="Adjustment">
4930 object to hold information about the range of values that the spin
4931 button can take. This makes for a powerful Spin Button widget.
4933 Recall that an adjustment widget is created with the following
4934 function, which illustrates the information that it holds:
4937 GtkObject *gtk_adjustment_new( gfloat value,
4940 gfloat step_increment,
4941 gfloat page_increment,
4945 These attributes of an Adjustment are used by the Spin Button in the
4949 <item> <tt/value/: initial value for the Spin Button
4950 <item> <tt/lower/: lower range value
4951 <item> <tt/upper/: upper range value
4952 <item> <tt/step_increment/: value to increment/decrement when pressing
4953 mouse button 1 on a button
4954 <item> <tt/page_increment/: value to increment/decrement when pressing
4955 mouse button 2 on a button
4956 <item> <tt/page_size/: unused
4959 Additionally, mouse button 3 can be used to jump directly to the
4960 <tt/upper/ or <tt/lower/ values when used to select one of the
4961 buttons. Lets look at how to create a Spin Button:
4964 GtkWidget *gtk_spin_button_new( GtkAdjustment *adjustment,
4969 The <tt/climb_rate/ argument take a value between 0.0 and 1.0 and
4970 indicates the amount of acceleration that the Spin Button has. The
4971 <tt/digits/ argument specifies the number of decimal places to which
4972 the value will be displayed.
4974 A Spin Button can be reconfigured after creation using the following
4978 void gtk_spin_button_configure( GtkSpinButton *spin_button,
4979 GtkAdjustment *adjustment,
4984 The <tt/spin_button/ argument specifies the Spin Button widget that is
4985 to be reconfigured. The other arguments are as specified above.
4987 The adjustment can be set and retrieved independantly using the
4988 following two functions:
4991 void gtk_spin_button_set_adjustment( GtkSpinButton *spin_button,
4992 GtkAdjustment *adjustment );
4994 GtkAdjustment *gtk_spin_button_get_adjustment( GtkSpinButton *spin_button );
4997 The number of decimal places can also be altered using:
5000 void gtk_spin_button_set_digits( GtkSpinButton *spin_button,
5004 The value that a Spin Button is currently displaying can be changed
5005 using the following function:
5008 void gtk_spin_button_set_value( GtkSpinButton *spin_button,
5012 The current value of a Spin Button can be retrieved as either a
5013 floating point or integer value with the following functions:
5016 gfloat gtk_spin_button_get_value_as_float( GtkSpinButton *spin_button );
5018 gint gtk_spin_button_get_value_as_int( GtkSpinButton *spin_button );
5021 If you want to alter the value of a Spin Value relative to its current
5022 value, then the following function can be used:
5025 void gtk_spin_button_spin( GtkSpinButton *spin_button,
5026 GtkSpinType direction,
5030 The <tt/direction/ parameter can take one of the following values:
5033 GTK_SPIN_STEP_FORWARD
5034 GTK_SPIN_STEP_BACKWARD
5035 GTK_SPIN_PAGE_FORWARD
5036 GTK_SPIN_PAGE_BACKWARD
5039 GTK_SPIN_USER_DEFINED
5042 This function packs in quite a bit of functionality, which I will
5043 attempt to clearly explain. Many of these settings use values from the
5044 Adjustment object that is associated with a Spin Button.
5046 <tt/GTK_SPIN_STEP_FORWARD/ and <tt/GTK_SPIN_STEP_BACKWARD/ change the
5047 value of the Spin Button by the amount specified by <tt/increment/,
5048 unless <tt/increment/ is equal to 0, in which case the value is
5049 changed by the value of <tt/step_increment/ in theAdjustment.
5051 <tt/GTK_SPIN_PAGE_FORWARD/ and <tt/GTK_SPIN_PAGE_BACKWARD/ simply
5052 alter the value of the Spin Button by <tt/increment/.
5054 <tt/GTK_SPIN_HOME/ sets the value of the Spin Button to the bottom of
5055 the Adjustments range.
5057 <tt/GTK_SPIN_END/ sets the value of the Spin Button to the top of the
5060 <tt/GTK_SPIN_USER_DEFINED/ simply alters the value of the Spin Button
5061 by the specified amount.
5063 We move away from functions for setting and retreving the range attributes
5064 of the Spin Button now, and move onto functions that effect the
5065 appearance and behaviour of the Spin Button widget itself.
5067 The first of these functions is used to constrain the text box of the
5068 Spin Button such that it may only contain a numeric value. This
5069 prevents a user from typing anything other than numeric values into
5070 the text box of a Spin Button:
5073 void gtk_spin_button_set_numeric( GtkSpinButton *spin_button,
5077 You can set whether a Spin Button will wrap around between the upper
5078 and lower range values with the following function:
5081 void gtk_spin_button_set_wrap( GtkSpinButton *spin_button,
5085 You can set a Spin Button to round the value to the nearest
5086 <tt/step_increment/, which is set within the Adjustment object used
5087 with the Spin Button. This is accomplished with the following
5091 void gtk_spin_button_set_snap_to_ticks( GtkSpinButton *spin_button,
5092 gboolean snap_to_ticks );
5095 The update policy of a Spin Button can be changed with the following
5099 void gtk_spin_button_set_update_policy( GtkSpinButton *spin_button,
5100 GtkSpinButtonUpdatePolicy policy );
5103 <!-- TODO: find out what this does - TRG -->
5105 The possible values of <tt/policy/ are either <tt/GTK_UPDATE_ALWAYS/ or
5106 <tt/GTK_UPDATE_IF_VALID/.
5109 These policies affect the behavior of a Spin Button when parsing
5110 inserted text and syncing its value with the values of the
5113 In the case of <tt/GTK_UPDATE_IF_VALID/ the Spin Button only value
5114 gets changed if the text input is a numeric value that is within the
5115 range specified by the Adjustment. Otherwise the text is reset to the
5118 In case of <tt/GTK_UPDATE_ALWAYS/ we ignore errors while converting
5119 text into a numeric value.
5121 The appearance of the buttons used in a Spin Button can be changed
5122 using the following function:
5125 void gtk_spin_button_set_shadow_type( GtkSpinButton *spin_button,
5126 GtkShadowType shadow_type );
5129 As usual, the <tt/shadow_type/ can be one of:
5134 GTK_SHADOW_ETCHED_IN
5135 GTK_SHADOW_ETCHED_OUT
5138 Finally, you can explicitly request that a Spin Button update itself:
5141 void gtk_spin_button_update( GtkSpinButton *spin_button );
5144 It's example time again.
5147 /* example-start spinbutton spinbutton.c */
5149 #include <gtk/gtk.h>
5151 static GtkWidget *spinner1;
5153 void toggle_snap( GtkWidget *widget,
5154 GtkSpinButton *spin )
5156 gtk_spin_button_set_snap_to_ticks (spin, GTK_TOGGLE_BUTTON (widget)->active);
5159 void toggle_numeric( GtkWidget *widget,
5160 GtkSpinButton *spin )
5162 gtk_spin_button_set_numeric (spin, GTK_TOGGLE_BUTTON (widget)->active);
5165 void change_digits( GtkWidget *widget,
5166 GtkSpinButton *spin )
5168 gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinner1),
5169 gtk_spin_button_get_value_as_int (spin));
5172 void get_value( GtkWidget *widget,
5177 GtkSpinButton *spin;
5179 spin = GTK_SPIN_BUTTON (spinner1);
5180 label = GTK_LABEL (gtk_object_get_user_data (GTK_OBJECT (widget)));
5181 if (GPOINTER_TO_INT (data) == 1)
5182 sprintf (buf, "%d", gtk_spin_button_get_value_as_int (spin));
5184 sprintf (buf, "%0.*f", spin->digits,
5185 gtk_spin_button_get_value_as_float (spin));
5186 gtk_label_set_text (label, buf);
5196 GtkWidget *main_vbox;
5199 GtkWidget *spinner2;
5203 GtkWidget *val_label;
5206 /* Initialise GTK */
5207 gtk_init(&argc, &argv);
5209 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5211 gtk_signal_connect (GTK_OBJECT (window), "destroy",
5212 GTK_SIGNAL_FUNC (gtk_main_quit),
5215 gtk_window_set_title (GTK_WINDOW (window), "Spin Button");
5217 main_vbox = gtk_vbox_new (FALSE, 5);
5218 gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 10);
5219 gtk_container_add (GTK_CONTAINER (window), main_vbox);
5221 frame = gtk_frame_new ("Not accelerated");
5222 gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
5224 vbox = gtk_vbox_new (FALSE, 0);
5225 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
5226 gtk_container_add (GTK_CONTAINER (frame), vbox);
5228 /* Day, month, year spinners */
5230 hbox = gtk_hbox_new (FALSE, 0);
5231 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
5233 vbox2 = gtk_vbox_new (FALSE, 0);
5234 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5236 label = gtk_label_new ("Day :");
5237 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5238 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5240 adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 31.0, 1.0,
5242 spinner = gtk_spin_button_new (adj, 0, 0);
5243 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
5244 gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
5246 gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5248 vbox2 = gtk_vbox_new (FALSE, 0);
5249 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5251 label = gtk_label_new ("Month :");
5252 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5253 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5255 adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 12.0, 1.0,
5257 spinner = gtk_spin_button_new (adj, 0, 0);
5258 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
5259 gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
5260 GTK_SHADOW_ETCHED_IN);
5261 gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5263 vbox2 = gtk_vbox_new (FALSE, 0);
5264 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5266 label = gtk_label_new ("Year :");
5267 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5268 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5270 adj = (GtkAdjustment *) gtk_adjustment_new (1998.0, 0.0, 2100.0,
5272 spinner = gtk_spin_button_new (adj, 0, 0);
5273 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), FALSE);
5274 gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
5276 gtk_widget_set_usize (spinner, 55, 0);
5277 gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5279 frame = gtk_frame_new ("Accelerated");
5280 gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
5282 vbox = gtk_vbox_new (FALSE, 0);
5283 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
5284 gtk_container_add (GTK_CONTAINER (frame), vbox);
5286 hbox = gtk_hbox_new (FALSE, 0);
5287 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5289 vbox2 = gtk_vbox_new (FALSE, 0);
5290 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5292 label = gtk_label_new ("Value :");
5293 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5294 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5296 adj = (GtkAdjustment *) gtk_adjustment_new (0.0, -10000.0, 10000.0,
5298 spinner1 = gtk_spin_button_new (adj, 1.0, 2);
5299 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner1), TRUE);
5300 gtk_widget_set_usize (spinner1, 100, 0);
5301 gtk_box_pack_start (GTK_BOX (vbox2), spinner1, FALSE, TRUE, 0);
5303 vbox2 = gtk_vbox_new (FALSE, 0);
5304 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5306 label = gtk_label_new ("Digits :");
5307 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5308 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5310 adj = (GtkAdjustment *) gtk_adjustment_new (2, 1, 5, 1, 1, 0);
5311 spinner2 = gtk_spin_button_new (adj, 0.0, 0);
5312 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner2), TRUE);
5313 gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
5314 GTK_SIGNAL_FUNC (change_digits),
5315 (gpointer) spinner2);
5316 gtk_box_pack_start (GTK_BOX (vbox2), spinner2, FALSE, TRUE, 0);
5318 hbox = gtk_hbox_new (FALSE, 0);
5319 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5321 button = gtk_check_button_new_with_label ("Snap to 0.5-ticks");
5322 gtk_signal_connect (GTK_OBJECT (button), "clicked",
5323 GTK_SIGNAL_FUNC (toggle_snap),
5325 gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
5326 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
5328 button = gtk_check_button_new_with_label ("Numeric only input mode");
5329 gtk_signal_connect (GTK_OBJECT (button), "clicked",
5330 GTK_SIGNAL_FUNC (toggle_numeric),
5332 gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
5333 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
5335 val_label = gtk_label_new ("");
5337 hbox = gtk_hbox_new (FALSE, 0);
5338 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5339 button = gtk_button_new_with_label ("Value as Int");
5340 gtk_object_set_user_data (GTK_OBJECT (button), val_label);
5341 gtk_signal_connect (GTK_OBJECT (button), "clicked",
5342 GTK_SIGNAL_FUNC (get_value),
5343 GINT_TO_POINTER (1));
5344 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
5346 button = gtk_button_new_with_label ("Value as Float");
5347 gtk_object_set_user_data (GTK_OBJECT (button), val_label);
5348 gtk_signal_connect (GTK_OBJECT (button), "clicked",
5349 GTK_SIGNAL_FUNC (get_value),
5350 GINT_TO_POINTER (2));
5351 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
5353 gtk_box_pack_start (GTK_BOX (vbox), val_label, TRUE, TRUE, 0);
5354 gtk_label_set_text (GTK_LABEL (val_label), "0");
5356 hbox = gtk_hbox_new (FALSE, 0);
5357 gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, TRUE, 0);
5359 button = gtk_button_new_with_label ("Close");
5360 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
5361 GTK_SIGNAL_FUNC (gtk_widget_destroy),
5362 GTK_OBJECT (window));
5363 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
5365 gtk_widget_show_all (window);
5367 /* Enter the event loop */
5375 <!-- ----------------------------------------------------------------- -->
5378 The combo box is another fairly simple widget that is really just a
5379 collection of other widgets. From the user's point of view, the widget
5380 consists of a text entry box and a pull down menu from which the user
5381 can select one of a set of predefined entries. Alternatively, the user
5382 can type a different option directly into the text box.
5384 The following extract from the structure that defines a Combo Box
5385 identifies several of the components:
5398 As you can see, the Combo Box has two principal parts that you really
5399 care about: an entry and a list.
5401 First off, to create a combo box, use:
5404 GtkWidget *gtk_combo_new( void );
5407 Now, if you want to set the string in the entry section of the combo
5408 box, this is done by manipulating the <tt/entry/ widget directly:
5411 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), "My String.");
5414 To set the values in the popdown list, one uses the function:
5417 void gtk_combo_set_popdown_strings( GtkCombo *combo,
5421 Before you can do this, you have to assemble a GList of the strings
5422 that you want. GList is a linked list implementation that is part of
5423 <ref id="sec_glib" name="GLib">, a library supporing GTK. For the
5424 moment, the quick and dirty explanation is that you need to set up a
5425 GList pointer, set it equal to NULL, then append strings to it with
5428 GList *g_list_append( GList *glist,
5432 It is important that you set the initial GList pointer to NULL. The
5433 value returned from the g_list_append function must be used as the new
5434 pointer to the GList.
5436 Here's a typical code segment for creating a set of options:
5441 glist = g_list_append(glist, "String 1");
5442 glist = g_list_append(glist, "String 2");
5443 glist = g_list_append(glist, "String 3");
5444 glist = g_list_append(glist, "String 4");
5446 gtk_combo_set_popdown_strings( GTK_COMBO(combo), glist) ;
5449 At this point you have a working combo box that has been set up.
5450 There are a few aspects of its behavior that you can change. These
5451 are accomplished with the functions:
5454 void gtk_combo_set_use_arrows( GtkCombo *combo,
5457 void gtk_combo_set_use_arrows_always( GtkCombo *combo,
5460 void gtk_combo_set_case_sensitive( GtkCombo *combo,
5464 <tt/gtk_combo_set_use_arrows()/ lets the user change the value in the
5465 entry using the up/down arrow keys. This doesn't bring up the list, but
5466 rather replaces the current text in the entry with the next list entry
5467 (up or down, as your key choice indicates). It does this by searching
5468 in the list for the item corresponding to the current value in the
5469 entry and selecting the previous/next item accordingly. Usually in an
5470 entry the arrow keys are used to change focus (you can do that anyway
5471 using TAB). Note that when the current item is the last of the list
5472 and you press arrow-down it changes the focus (the same applies with
5473 the first item and arrow-up).
5475 If the current value in the entry is not in the list, then the
5476 function of <tt/gtk_combo_set_use_arrows()/ is disabled.
5478 <tt/gtk_combo_set_use_arrows_always()/ similarly allows the use the
5479 the up/down arrow keys to cycle through the choices in the dropdown
5480 list, except that it wraps around the values in the list, completely
5481 disabling the use of the up and down arrow keys for changing focus.
5483 <tt/gtk_combo_set_case_sensitive()/ toggles whether or not GTK
5484 searches for entries in a case sensitive manner. This is used when the
5485 Combo widget is asked to find a value from the list using the current
5486 entry in the text box. This completion can be performed in either a
5487 case sensitive or insensitive manner, depending upon the use of this
5488 function. The Combo widget can also simply complete the current entry
5489 if the user presses the key combination MOD-1 and "Tab". MOD-1 is
5490 often mapped to the "Alt" key, by the <tt/xmodmap/ utility. Note,
5491 however that some window managers also use this key combination, which
5492 will override its use within GTK.
5494 Now that we have a combo box, tailored to look and act how we want it,
5495 all that remains is being able to get data from the combo box. This is
5496 relatively straightforward. The majority of the time, all you are
5497 going to care about getting data from is the entry. The entry is
5498 accessed simply by <tt>GTK_ENTRY(GTK_COMBO(combo)->entry)</tt>. The
5499 two principal things that you are going to want to do with it are
5500 attach to the activate signal, which indicates that the user has
5501 pressed the Return or Enter key, and read the text. The first is
5502 accomplished using something like:
5505 gtk_signal_connect(GTK_OBJECT(GTK_COMB(combo)->entry), "activate",
5506 GTK_SIGNAL_FUNC (my_callback_function), my_data);
5509 Getting the text at any arbitrary time is accomplished by simply using
5513 gchar *gtk_entry_get_text(GtkEntry *entry);
5521 string = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry));
5524 That's about all there is to it. There is a function
5527 void gtk_combo_disable_activate(GtkCombo *combo);
5530 that will disable the activate signal on the entry widget in the combo
5531 box. Personally, I can't think of why you'd want to use it, but it
5534 <!-- There is also a function to set the string on a particular item, void
5535 gtk_combo_set_item_string(GtkCombo *combo, GtkItem *item, const gchar
5536 *item_value), but this requires that you have a pointer to the
5537 appropriate Item. Frankly, I have no idea how to do that.
5540 <!-- ----------------------------------------------------------------- -->
5541 <sect1> Color Selection
5543 The color selection widget is, not surprisingly, a widget for
5544 interactive selection of colors. This composite widget lets the user
5545 select a color by manipulating RGB (Red, Green, Blue) and HSV (Hue,
5546 Saturation, Value) triples. This is done either by adjusting single
5547 values with sliders or entries, or by picking the desired color from a
5548 hue-saturation wheel/value bar. Optionally, the opacity of the color
5551 The color selection widget currently emits only one signal,
5552 "color_changed", which is emitted whenever the current color in the
5553 widget changes, either when the user changes it or if it's set
5554 explicitly through gtk_color_selection_set_color().
5556 Lets have a look at what the color selection widget has to offer
5557 us. The widget comes in two flavours: gtk_color_selection and
5558 gtk_color_selection_dialog.
5561 GtkWidget *gtk_color_selection_new( void );
5564 You'll probably not be using this constructor directly. It creates an
5565 orphan ColorSelection widget which you'll have to parent
5566 yourself. The ColorSelection widget inherits from the VBox
5570 GtkWidget *gtk_color_selection_dialog_new( const gchar *title );
5573 This is the most common color selection constructor. It creates a
5574 ColorSelectionDialog. It consists of a Frame containing a
5575 ColorSelection widget, an HSeparator and an HBox with three buttons,
5576 "Ok", "Cancel" and "Help". You can reach these buttons by accessing
5577 the "ok_button", "cancel_button" and "help_button" widgets in the
5578 ColorSelectionDialog structure,
5579 (i.e., <tt>GTK_COLOR_SELECTION_DIALOG(colorseldialog)->ok_button</tt>)).
5582 void gtk_color_selection_set_update_policy( GtkColorSelection *colorsel,
5583 GtkUpdateType policy );
5586 This function sets the update policy. The default policy is
5587 <tt/GTK_UPDATE_CONTINUOUS/ which means that the current color is
5588 updated continuously when the user drags the sliders or presses the
5589 mouse and drags in the hue-saturation wheel or value bar. If you
5590 experience performance problems, you may want to set the policy to
5591 <tt/GTK_UPDATE_DISCONTINUOUS/ or <tt/GTK_UPDATE_DELAYED/.
5594 void gtk_color_selection_set_opacity( GtkColorSelection *colorsel,
5598 The color selection widget supports adjusting the opacity of a color
5599 (also known as the alpha channel). This is disabled by
5600 default. Calling this function with use_opacity set to TRUE enables
5601 opacity. Likewise, use_opacity set to FALSE will disable opacity.
5604 void gtk_color_selection_set_color( GtkColorSelection *colorsel,
5608 You can set the current color explicitly by calling this function with
5609 a pointer to an array of colors (gdouble). The length of the array
5610 depends on whether opacity is enabled or not. Position 0 contains the
5611 red component, 1 is green, 2 is blue and opacity is at position 3
5612 (only if opacity is enabled, see
5613 gtk_color_selection_set_opacity()). All values are between 0.0 and
5617 void gtk_color_selection_get_color( GtkColorSelection *colorsel,
5621 When you need to query the current color, typically when you've
5622 received a "color_changed" signal, you use this function. Color is a
5623 pointer to the array of colors to fill in. See the
5624 gtk_color_selection_set_color() function for the description of this
5627 <!-- Need to do a whole section on DnD - TRG
5631 The color sample areas (right under the hue-saturation wheel) supports
5632 drag and drop. The type of drag and drop is "application/x-color". The
5633 message data consists of an array of 4 (or 5 if opacity is enabled)
5634 gdouble values, where the value at position 0 is 0.0 (opacity on) or
5635 1.0 (opacity off) followed by the red, green and blue values at
5636 positions 1,2 and 3 respectively. If opacity is enabled, the opacity
5637 is passed in the value at position 4.
5640 Here's a simple example demonstrating the use of the
5641 ColorSelectionDialog. The program displays a window containing a
5642 drawing area. Clicking on it opens a color selection dialog, and
5643 changing the color in the color selection dialog changes the
5647 /* example-start colorsel colorsel.c */
5650 #include <gdk/gdk.h>
5651 #include <gtk/gtk.h>
5653 GtkWidget *colorseldlg = NULL;
5654 GtkWidget *drawingarea = NULL;
5656 /* Color changed handler */
5658 void color_changed_cb (GtkWidget *widget, GtkColorSelection *colorsel)
5662 GdkColormap *colormap;
5664 /* Get drawingarea colormap */
5666 colormap = gdk_window_get_colormap (drawingarea->window);
5668 /* Get current color */
5670 gtk_color_selection_get_color (colorsel,color);
5672 /* Fit to a unsigned 16 bit integer (0..65535) and
5673 * insert into the GdkColor structure */
5675 gdk_color.red = (guint16)(color[0]*65535.0);
5676 gdk_color.green = (guint16)(color[1]*65535.0);
5677 gdk_color.blue = (guint16)(color[2]*65535.0);
5679 /* Allocate color */
5681 gdk_color_alloc (colormap, &gdk_color);
5683 /* Set window background color */
5685 gdk_window_set_background (drawingarea->window, &gdk_color);
5689 gdk_window_clear (drawingarea->window);
5692 /* Drawingarea event handler */
5694 gint area_event (GtkWidget *widget, GdkEvent *event, gpointer client_data)
5696 gint handled = FALSE;
5697 GtkWidget *colorsel;
5699 /* Check if we've received a button pressed event */
5701 if (event->type == GDK_BUTTON_PRESS && colorseldlg == NULL)
5703 /* Yes, we have an event and there's no colorseldlg yet! */
5707 /* Create color selection dialog */
5709 colorseldlg = gtk_color_selection_dialog_new("Select background color");
5711 /* Get the ColorSelection widget */
5713 colorsel = GTK_COLOR_SELECTION_DIALOG(colorseldlg)->colorsel;
5715 /* Connect to the "color_changed" signal, set the client-data
5716 * to the colorsel widget */
5718 gtk_signal_connect(GTK_OBJECT(colorsel), "color_changed",
5719 (GtkSignalFunc)color_changed_cb, (gpointer)colorsel);
5721 /* Show the dialog */
5723 gtk_widget_show(colorseldlg);
5729 /* Close down and exit handler */
5731 void destroy_window (GtkWidget *widget, gpointer client_data)
5738 gint main (gint argc, gchar *argv[])
5742 /* Initialize the toolkit, remove gtk-related commandline stuff */
5744 gtk_init (&argc,&argv);
5746 /* Create toplevel window, set title and policies */
5748 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5749 gtk_window_set_title (GTK_WINDOW(window), "Color selection test");
5750 gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, TRUE);
5752 /* Attach to the "delete" and "destroy" events so we can exit */
5754 gtk_signal_connect (GTK_OBJECT(window), "delete_event",
5755 (GtkSignalFunc)destroy_window, (gpointer)window);
5757 gtk_signal_connect (GTK_OBJECT(window), "destroy",
5758 (GtkSignalFunc)destroy_window, (gpointer)window);
5760 /* Create drawingarea, set size and catch button events */
5762 drawingarea = gtk_drawing_area_new ();
5764 gtk_drawing_area_size (GTK_DRAWING_AREA(drawingarea), 200, 200);
5766 gtk_widget_set_events (drawingarea, GDK_BUTTON_PRESS_MASK);
5768 gtk_signal_connect (GTK_OBJECT(drawingarea), "event",
5769 (GtkSignalFunc)area_event, (gpointer)drawingarea);
5771 /* Add drawingarea to window, then show them both */
5773 gtk_container_add (GTK_CONTAINER(window), drawingarea);
5775 gtk_widget_show (drawingarea);
5776 gtk_widget_show (window);
5778 /* Enter the gtk main loop (this never returns) */
5782 /* Satisfy grumpy compilers */
5789 <!-- ----------------------------------------------------------------- -->
5790 <sect1> File Selections
5792 The file selection widget is a quick and simple way to display a File
5793 dialog box. It comes complete with Ok, Cancel, and Help buttons, a
5794 great way to cut down on programming time.
5796 To create a new file selection box use:
5799 GtkWidget *gtk_file_selection_new( gchar *title );
5802 To set the filename, for example to bring up a specific directory, or
5803 give a default filename, use this function:
5806 void gtk_file_selection_set_filename( GtkFileSelection *filesel,
5810 To grab the text that the user has entered or clicked on, use this
5814 gchar *gtk_file_selection_get_filename( GtkFileSelection *filesel );
5817 There are also pointers to the widgets contained within the file
5818 selection widget. These are:
5831 Most likely you will want to use the ok_button, cancel_button, and
5832 help_button pointers in signaling their use.
5834 Included here is an example stolen from testgtk.c, modified to run on
5835 its own. As you will see, there is nothing much to creating a file
5836 selection widget. While in this example the Help button appears on the
5837 screen, it does nothing as there is not a signal attached to it.
5840 /* example-start filesel filesel.c */
5842 #include <gtk/gtk.h>
5844 /* Get the selected filename and print it to the console */
5845 void file_ok_sel (GtkWidget *w, GtkFileSelection *fs)
5847 g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
5850 void destroy (GtkWidget *widget, gpointer data)
5855 int main (int argc, char *argv[])
5859 gtk_init (&argc, &argv);
5861 /* Create a new file selection widget */
5862 filew = gtk_file_selection_new ("File selection");
5864 gtk_signal_connect (GTK_OBJECT (filew), "destroy",
5865 (GtkSignalFunc) destroy, &filew);
5866 /* Connect the ok_button to file_ok_sel function */
5867 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
5868 "clicked", (GtkSignalFunc) file_ok_sel, filew );
5870 /* Connect the cancel_button to destroy the widget */
5871 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION
5872 (filew)->cancel_button),
5873 "clicked", (GtkSignalFunc) gtk_widget_destroy,
5874 GTK_OBJECT (filew));
5876 /* Lets set the filename, as if this were a save dialog, and we are giving
5877 a default filename */
5878 gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew),
5881 gtk_widget_show(filew);
5888 <!-- ***************************************************************** -->
5889 <sect> Container Widgets
5890 <!-- ***************************************************************** -->
5892 <!-- ----------------------------------------------------------------- -->
5893 <sect1>The EventBox <label id="sec_EventBox">
5895 Some GTK widgets don't have associated X windows, so they just draw on
5896 their parents. Because of this, they cannot receive events and if they
5897 are incorrectly sized, they don't clip so you can get messy
5898 overwriting, etc. If you require more from these widgets, the EventBox
5901 At first glance, the EventBox widget might appear to be totally
5902 useless. It draws nothing on the screen and responds to no
5903 events. However, it does serve a function - it provides an X window
5904 for its child widget. This is important as many GTK widgets do not
5905 have an associated X window. Not having an X window saves memory and
5906 improves performance, but also has some drawbacks. A widget without an
5907 X window cannot receive events, and does not perform any clipping on
5908 its contents. Although the name <em/EventBox/ emphasizes the
5909 event-handling function, the widget can also be used for clipping.
5910 (and more, see the example below).
5912 To create a new EventBox widget, use:
5915 GtkWidget *gtk_event_box_new( void );
5918 A child widget can then be added to this EventBox:
5921 gtk_container_add( GTK_CONTAINER(event_box), child_widget );
5924 The following example demonstrates both uses of an EventBox - a label
5925 is created that is clipped to a small box, and set up so that a
5926 mouse-click on the label causes the program to exit. Resizing the
5927 window reveals varying amounts of the label.
5930 /* example-start eventbox eventbox.c */
5932 #include <gtk/gtk.h>
5935 main (int argc, char *argv[])
5938 GtkWidget *event_box;
5941 gtk_init (&argc, &argv);
5943 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5945 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
5947 gtk_signal_connect (GTK_OBJECT (window), "destroy",
5948 GTK_SIGNAL_FUNC (gtk_exit), NULL);
5950 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
5952 /* Create an EventBox and add it to our toplevel window */
5954 event_box = gtk_event_box_new ();
5955 gtk_container_add (GTK_CONTAINER(window), event_box);
5956 gtk_widget_show (event_box);
5958 /* Create a long label */
5960 label = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
5961 gtk_container_add (GTK_CONTAINER (event_box), label);
5962 gtk_widget_show (label);
5964 /* Clip it short. */
5965 gtk_widget_set_usize (label, 110, 20);
5967 /* And bind an action to it */
5968 gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
5969 gtk_signal_connect (GTK_OBJECT(event_box), "button_press_event",
5970 GTK_SIGNAL_FUNC (gtk_exit), NULL);
5972 /* Yet one more thing you need an X window for ... */
5974 gtk_widget_realize (event_box);
5975 gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1));
5977 gtk_widget_show (window);
5986 <!-- ----------------------------------------------------------------- -->
5987 <sect1>The Alignment widget <label id="sec_Alignment">
5989 The alignment widget allows you to place a widget within its window at
5990 a position and size relative to the size of the Alignment widget
5991 itself. For example, it can be very useful for centering a widget
5994 There are only two functions associated with the Alignment widget:
5997 GtkWidget* gtk_alignment_new( gfloat xalign,
6002 void gtk_alignment_set( GtkAlignment *alignment,
6009 The first function creates a new Alignment widget with the specified
6010 parameters. The second function allows the alignment paramters of an
6011 exisiting Alignment widget to be altered.
6013 All four alignment parameters are floating point numbers which can
6014 range from 0.0 to 1.0. The <tt/xalign/ and <tt/yalign/ arguments
6015 affect the position of the widget placed within the Alignment
6016 widget. The <tt/xscale/ and <tt/yscale/ arguments effect the amount of
6017 space allocated to the widget.
6019 A child widget can be added to this Alignment widget using:
6022 gtk_container_add( GTK_CONTAINER(alignment), child_widget );
6025 For an example of using an Alignment widget, refer to the example for
6026 the <ref id="sec_ProgressBar" name="Progress Bar"> widget.
6028 <!-- ----------------------------------------------------------------- -->
6029 <sect1> Fixed Container
6031 The Fixed container allows you to place widgets at a fixed position
6032 within it's window, relative to it's upper left hand corner. The
6033 position of the widgets can be changed dynamically.
6035 There are only three functions associated with the fixed widget:
6038 GtkWidget* gtk_fixed_new( void );
6040 void gtk_fixed_put( GtkFixed *fixed,
6045 void gtk_fixed_move( GtkFixed *fixed,
6051 The function <tt/gtk_fixed_new/ allows you to create a new Fixed
6054 <tt/gtk_fixed_put/ places <tt/widget/ in the container <tt/fixed/ at
6055 the position specified by <tt/x/ and <tt/y/.
6057 <tt/gtk_fixed_move/ allows the specified widget to be moved to a new
6060 The following example illustrates how to use the Fixed Container.
6063 /* example-start fixed fixed.c */
6065 #include <gtk/gtk.h>
6067 /* I'm going to be lazy and use some global variables to
6068 * store the position of the widget within the fixed
6073 /* This callback function moves the button to a new position
6074 * in the Fixed container. */
6075 void move_button( GtkWidget *widget,
6080 gtk_fixed_move( GTK_FIXED(fixed), widget, x, y);
6086 /* GtkWidget is the storage type for widgets */
6092 /* Initialise GTK */
6093 gtk_init(&argc, &argv);
6095 /* Create a new window */
6096 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6097 gtk_window_set_title(GTK_WINDOW(window), "Fixed Container");
6099 /* Here we connect the "destroy" event to a signal handler */
6100 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6101 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
6103 /* Sets the border width of the window. */
6104 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6106 /* Create a Fixed Container */
6107 fixed = gtk_fixed_new();
6108 gtk_container_add(GTK_CONTAINER(window), fixed);
6109 gtk_widget_show(fixed);
6111 for (i = 1 ; i <= 3 ; i++) {
6112 /* Creates a new button with the label "Press me" */
6113 button = gtk_button_new_with_label ("Press me");
6115 /* When the button receives the "clicked" signal, it will call the
6116 * function move_button() passing it the Fixed Container as its
6118 gtk_signal_connect (GTK_OBJECT (button), "clicked",
6119 GTK_SIGNAL_FUNC (move_button), fixed);
6121 /* This packs the button into the fixed containers window. */
6122 gtk_fixed_put (GTK_FIXED (fixed), button, i*50, i*50);
6124 /* The final step is to display this newly created widget. */
6125 gtk_widget_show (button);
6128 /* Display the window */
6129 gtk_widget_show (window);
6131 /* Enter the event loop */
6139 <!-- ----------------------------------------------------------------- -->
6140 <sect1> Layout Container
6142 The Layout container is similar to the Fixed container except that it
6143 implements an infinite (where infinity is less than 2^32) scrolling
6144 area. The X window system has a limitation where windows can be at
6145 most 32767 pixels wide or tall. The Layout container gets around this
6146 limitation by doing some exotic stuff using window and bit gravities,
6147 so that you can have smooth scrolling even when you have many child
6148 widgets in your scrolling area.
6150 A Layout container is created using:
6153 GtkWidget *gtk_layout_new( GtkAdjustment *hadjustment,
6154 GtkAdjustment *vadjustment );
6157 As you can see, you can optionally specify the Adjustment objects that
6158 the Layout widget will use for its scrolling.
6160 You can add and move widgets in the Layout container using the
6161 following two functions:
6164 void gtk_layout_put( GtkLayout *layout,
6169 void gtk_layout_move( GtkLayout *layout,
6175 The size of the Layout container can be set using the next function:
6178 void gtk_layout_set_size( GtkLayout *layout,
6183 Layout containers are one of the very few widgets in the GTK widget
6184 set that actively repaint themselves on screen as they are changed
6185 using the above functions (the vast majority of widgets queue
6186 requests which are then processed when control returns to the
6187 <tt/gtk_main()/ function).
6189 When you want to make a large number of changes to a Layout container,
6190 you can use the following two functions to disable and re-enable this
6191 repainting functionality:
6194 void gtk_layout_freeze( GtkLayout *layout );
6196 void gtk_layout_thaw( GtkLayout *layout );
6199 The final four functions for use with Layout widgets are for
6200 manipulating the horizontal and vertical adjustment widgets:
6203 GtkAdjustment* gtk_layout_get_hadjustment( GtkLayout *layout );
6205 GtkAdjustment* gtk_layout_get_vadjustment( GtkLayout *layout );
6207 void gtk_layout_set_hadjustment( GtkLayout *layout,
6208 GtkAdjustment *adjustment );
6210 void gtk_layout_set_vadjustment( GtkLayout *layout,
6211 GtkAdjustment *adjustment);
6214 <!-- ----------------------------------------------------------------- -->
6215 <sect1> Frames <label id="sec_Frames">
6217 Frames can be used to enclose one or a group of widgets with a box
6218 which can optionally be labelled. The position of the label and the
6219 style of the box can be altered to suit.
6221 A Frame can be created with the following function:
6224 GtkWidget *gtk_frame_new( const gchar *label );
6227 The label is by default placed in the upper left hand corner of the
6228 frame. A value of NULL for the <tt/label/ argument will result in no
6229 label being displayed. The text of the label can be changed using the
6233 void gtk_frame_set_label( GtkFrame *frame,
6234 const gchar *label );
6237 The position of the label can be changed using this function:
6240 void gtk_frame_set_label_align( GtkFrame *frame,
6245 <tt/xalign/ and <tt/yalign/ take values between 0.0 and 1.0. <tt/xalign/
6246 indicates the position of the label along the top horizontal of the
6247 frame. <tt/yalign/ is not currently used. The default value of xalign
6248 is 0.0 which places the label at the left hand end of the frame.
6250 The next function alters the style of the box that is used to outline
6254 void gtk_frame_set_shadow_type( GtkFrame *frame,
6255 GtkShadowType type);
6258 The <tt/type/ argument can take one of the following values:
6263 GTK_SHADOW_ETCHED_IN (the default)
6264 GTK_SHADOW_ETCHED_OUT
6267 The following code example illustrates the use of the Frame widget.
6270 /* example-start frame frame.c */
6272 #include <gtk/gtk.h>
6277 /* GtkWidget is the storage type for widgets */
6283 /* Initialise GTK */
6284 gtk_init(&argc, &argv);
6286 /* Create a new window */
6287 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6288 gtk_window_set_title(GTK_WINDOW(window), "Frame Example");
6290 /* Here we connect the "destroy" event to a signal handler */
6291 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6292 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
6294 gtk_widget_set_usize(window, 300, 300);
6295 /* Sets the border width of the window. */
6296 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6298 /* Create a Frame */
6299 frame = gtk_frame_new(NULL);
6300 gtk_container_add(GTK_CONTAINER(window), frame);
6302 /* Set the frame's label */
6303 gtk_frame_set_label( GTK_FRAME(frame), "GTK Frame Widget" );
6305 /* Align the label at the right of the frame */
6306 gtk_frame_set_label_align( GTK_FRAME(frame), 1.0, 0.0);
6308 /* Set the style of the frame */
6309 gtk_frame_set_shadow_type( GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
6311 gtk_widget_show(frame);
6313 /* Display the window */
6314 gtk_widget_show (window);
6316 /* Enter the event loop */
6325 <!-- ----------------------------------------------------------------- -->
6326 <sect1> Aspect Frames
6328 The aspect frame widget is like a frame widget, except that it also
6329 enforces the aspect ratio (that is, the ratio of the width to the
6330 height) of the child widget to have a certain value, adding extra
6331 space if necessary. This is useful, for instance, if you want to
6332 preview a larger image. The size of the preview should vary when the
6333 user resizes the window, but the aspect ratio needs to always match
6336 To create a new aspect frame use:
6339 GtkWidget *gtk_aspect_frame_new( const gchar *label,
6346 <tt/xalign/ and <tt/yalign/ specify alignment as with Alignment
6347 widgets. If <tt/obey_child/ is true, the aspect ratio of a child
6348 widget will match the aspect ratio of the ideal size it requests.
6349 Otherwise, it is given by <tt/ratio/.
6351 To change the options of an existing aspect frame, you can use:
6354 void gtk_aspect_frame_set( GtkAspectFrame *aspect_frame,
6361 As an example, the following program uses an AspectFrame to present a
6362 drawing area whose aspect ratio will always be 2:1, no matter how the
6363 user resizes the top-level window.
6366 /* example-start aspectframe aspectframe.c */
6368 #include <gtk/gtk.h>
6371 main (int argc, char *argv[])
6374 GtkWidget *aspect_frame;
6375 GtkWidget *drawing_area;
6376 gtk_init (&argc, &argv);
6378 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6379 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
6380 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6381 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
6382 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6384 /* Create an aspect_frame and add it to our toplevel window */
6386 aspect_frame = gtk_aspect_frame_new ("2x1", /* label */
6389 2, /* xsize/ysize = 2 */
6390 FALSE /* ignore child's aspect */);
6392 gtk_container_add (GTK_CONTAINER(window), aspect_frame);
6393 gtk_widget_show (aspect_frame);
6395 /* Now add a child widget to the aspect frame */
6397 drawing_area = gtk_drawing_area_new ();
6399 /* Ask for a 200x200 window, but the AspectFrame will give us a 200x100
6400 * window since we are forcing a 2x1 aspect ratio */
6401 gtk_widget_set_usize (drawing_area, 200, 200);
6402 gtk_container_add (GTK_CONTAINER(aspect_frame), drawing_area);
6403 gtk_widget_show (drawing_area);
6405 gtk_widget_show (window);
6412 <!-- ----------------------------------------------------------------- -->
6413 <sect1> Paned Window Widgets
6415 The paned window widgets are useful when you want to divide an area
6416 into two parts, with the relative size of the two parts controlled by
6417 the user. A groove is drawn between the two portions with a handle
6418 that the user can drag to change the ratio. The division can either be
6419 horizontal (HPaned) or vertical (VPaned).
6421 To create a new paned window, call one of:
6424 GtkWidget *gtk_hpaned_new (void);
6426 GtkWidget *gtk_vpaned_new (void);
6429 After creating the paned window widget, you need to add child widgets
6430 to its two halves. To do this, use the functions:
6433 void gtk_paned_add1 (GtkPaned *paned, GtkWidget *child);
6435 void gtk_paned_add2 (GtkPaned *paned, GtkWidget *child);
6438 <tt/gtk_paned_add1()/ adds the child widget to the left or top half of
6439 the paned window. <tt/gtk_paned_add2()/ adds the child widget to the
6440 right or bottom half of the paned window.
6442 A paned widget can be changed visually using the following two
6446 void gtk_paned_set_handle_size( GtkPaned *paned,
6449 void gtk_paned_set_gutter_size( GtkPaned *paned,
6453 The first of these sets the size of the handle and the second sets the
6454 size of the gutter that is between the two parts of the paned window.
6456 As an example, we will create part of the user interface of an
6457 imaginary email program. A window is divided into two portions
6458 vertically, with the top portion being a list of email messages and
6459 the bottom portion the text of the email message. Most of the program
6460 is pretty straightforward. A couple of points to note: text can't be
6461 added to a Text widget until it is realized. This could be done by
6462 calling <tt/gtk_widget_realize()/, but as a demonstration of an
6463 alternate technique, we connect a handler to the "realize" signal to
6464 add the text. Also, we need to add the <tt/GTK_SHRINK/ option to some
6465 of the items in the table containing the text window and its
6466 scrollbars, so that when the bottom portion is made smaller, the
6467 correct portions shrink instead of being pushed off the bottom of the
6471 /* example-start paned paned.c */
6473 #include <gtk/gtk.h>
6475 /* Create the list of "messages" */
6480 GtkWidget *scrolled_window;
6482 GtkWidget *list_item;
6487 /* Create a new scrolled window, with scrollbars only if needed */
6488 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
6489 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
6490 GTK_POLICY_AUTOMATIC,
6491 GTK_POLICY_AUTOMATIC);
6493 /* Create a new list and put it in the scrolled window */
6494 list = gtk_list_new ();
6495 gtk_scrolled_window_add_with_viewport (
6496 GTK_SCROLLED_WINDOW (scrolled_window), list);
6497 gtk_widget_show (list);
6499 /* Add some messages to the window */
6500 for (i=0; i<10; i++) {
6502 sprintf(buffer,"Message #%d",i);
6503 list_item = gtk_list_item_new_with_label (buffer);
6504 gtk_container_add (GTK_CONTAINER(list), list_item);
6505 gtk_widget_show (list_item);
6509 return scrolled_window;
6512 /* Add some text to our text widget - this is a callback that is invoked
6513 when our window is realized. We could also force our window to be
6514 realized with gtk_widget_realize, but it would have to be part of
6515 a hierarchy first */
6518 realize_text (GtkWidget *text, gpointer data)
6520 gtk_text_freeze (GTK_TEXT (text));
6521 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
6522 "From: pathfinder@nasa.gov\n"
6523 "To: mom@nasa.gov\n"
6524 "Subject: Made it!\n"
6526 "We just got in this morning. The weather has been\n"
6527 "great - clear but cold, and there are lots of fun sights.\n"
6528 "Sojourner says hi. See you soon.\n"
6531 gtk_text_thaw (GTK_TEXT (text));
6534 /* Create a scrolled text area that displays a "message" */
6540 GtkWidget *hscrollbar;
6541 GtkWidget *vscrollbar;
6543 /* Create a table to hold the text widget and scrollbars */
6544 table = gtk_table_new (2, 2, FALSE);
6546 /* Put a text widget in the upper left hand corner. Note the use of
6547 * GTK_SHRINK in the y direction */
6548 text = gtk_text_new (NULL, NULL);
6549 gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
6550 GTK_FILL | GTK_EXPAND,
6551 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
6552 gtk_widget_show (text);
6554 /* Put a HScrollbar in the lower left hand corner */
6555 hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
6556 gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
6557 GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
6558 gtk_widget_show (hscrollbar);
6560 /* And a VScrollbar in the upper right */
6561 vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
6562 gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
6563 GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
6564 gtk_widget_show (vscrollbar);
6566 /* Add a handler to put a message in the text widget when it is realized */
6567 gtk_signal_connect (GTK_OBJECT (text), "realize",
6568 GTK_SIGNAL_FUNC (realize_text), NULL);
6574 main (int argc, char *argv[])
6581 gtk_init (&argc, &argv);
6583 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6584 gtk_window_set_title (GTK_WINDOW (window), "Paned Windows");
6585 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6586 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
6587 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6588 gtk_widget_set_usize (GTK_WIDGET(window), 450, 400);
6590 /* create a vpaned widget and add it to our toplevel window */
6592 vpaned = gtk_vpaned_new ();
6593 gtk_container_add (GTK_CONTAINER(window), vpaned);
6594 gtk_paned_set_handle_size (GTK_PANED(vpaned),
6596 gtk_paned_set_gutter_size (GTK_PANED(vpaned),
6598 gtk_widget_show (vpaned);
6600 /* Now create the contents of the two halves of the window */
6602 list = create_list ();
6603 gtk_paned_add1 (GTK_PANED(vpaned), list);
6604 gtk_widget_show (list);
6606 text = create_text ();
6607 gtk_paned_add2 (GTK_PANED(vpaned), text);
6608 gtk_widget_show (text);
6609 gtk_widget_show (window);
6616 <!-- ----------------------------------------------------------------- -->
6617 <sect1>Viewports <label id="sec_Viewports">
6619 It is unlikely that you will ever need to use the Viewport widget
6620 directly. You are much more likely to use the
6621 <ref id="sec_ScrolledWindow" name="Scrolled Window"> widget which
6622 itself uses the Viewport.
6624 A viewport widget allows you to place a larger widget within it such
6625 that you can view a part of it at a time. It uses
6626 <ref id="sec_Adjustment" name="Adjustments"> to define the area that
6627 is currently in view.
6629 A Viewport is created with the function
6632 GtkWidget *gtk_viewport_new( GtkAdjustment *hadjustment,
6633 GtkAdjustment *vadjustment );
6636 As you can see you can specify the horizontal and vertical Adjustments
6637 that the widget is to use when you create the widget. It will create
6638 its own if you pass NULL as the value of the arguments.
6640 You can get and set the adjustments after the widget has been created
6641 using the following four functions:
6644 GtkAdjustment *gtk_viewport_get_hadjustment (GtkViewport *viewport );
6646 GtkAdjustment *gtk_viewport_get_vadjustment (GtkViewport *viewport );
6648 void gtk_viewport_set_hadjustment( GtkViewport *viewport,
6649 GtkAdjustment *adjustment );
6651 void gtk_viewport_set_vadjustment( GtkViewport *viewport,
6652 GtkAdjustment *adjustment );
6655 The only other viewport function is used to alter its appearance:
6658 void gtk_viewport_set_shadow_type( GtkViewport *viewport,
6659 GtkShadowType type );
6662 Possible values for the <tt/type/ parameter are:
6667 GTK_SHADOW_ETCHED_IN,
6668 GTK_SHADOW_ETCHED_OUT
6671 <!-- ----------------------------------------------------------------- -->
6672 <sect1>Scrolled Windows <label id="sec_ScrolledWindow">
6674 Scrolled windows are used to create a scrollable area with another
6675 widget inside it. You may insert any type of widget into a scrolled
6676 window, and it will be accessible regardless of the size by using the
6679 The following function is used to create a new scrolled window.
6682 GtkWidget *gtk_scrolled_window_new( GtkAdjustment *hadjustment,
6683 GtkAdjustment *vadjustment );
6686 Where the first argument is the adjustment for the horizontal
6687 direction, and the second, the adjustment for the vertical direction.
6688 These are almost always set to NULL.
6691 void gtk_scrolled_window_set_policy( GtkScrolledWindow *scrolled_window,
6692 GtkPolicyType hscrollbar_policy,
6693 GtkPolicyType vscrollbar_policy );
6696 This sets the policy to be used with respect to the scrollbars.
6697 The first argument is the scrolled window you wish to change. The second
6698 sets the policy for the horizontal scrollbar, and the third the policy for
6699 the vertical scrollbar.
6701 The policy may be one of <tt/GTK_POLICY_AUTOMATIC/ or
6702 <tt/GTK_POLICY_ALWAYS/. <tt/GTK_POLICY_AUTOMATIC/ will automatically
6703 decide whether you need scrollbars, whereas <tt/GTK_POLICY_ALWAYS/
6704 will always leave the scrollbars there.
6706 You can then place your object into the scrolled window using the
6710 void gtk_scrolled_window_add_with_viewport( GtkScrolledWindow *scrolled_window,
6714 Here is a simple example that packs a table eith 100 toggle buttons
6715 into a scrolled window. I've only commented on the parts that may be
6719 /* example-start scrolledwin scrolledwin.c */
6721 #include <gtk/gtk.h>
6723 void destroy(GtkWidget *widget, gpointer data)
6728 int main (int argc, char *argv[])
6730 static GtkWidget *window;
6731 GtkWidget *scrolled_window;
6737 gtk_init (&argc, &argv);
6739 /* Create a new dialog window for the scrolled window to be
6741 window = gtk_dialog_new ();
6742 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6743 (GtkSignalFunc) destroy, NULL);
6744 gtk_window_set_title (GTK_WINDOW (window), "GtkScrolledWindow example");
6745 gtk_container_set_border_width (GTK_CONTAINER (window), 0);
6746 gtk_widget_set_usize(window, 300, 300);
6748 /* create a new scrolled window. */
6749 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
6751 gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 10);
6753 /* the policy is one of GTK_POLICY AUTOMATIC, or GTK_POLICY_ALWAYS.
6754 * GTK_POLICY_AUTOMATIC will automatically decide whether you need
6755 * scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars
6756 * there. The first one is the horizontal scrollbar, the second,
6758 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
6759 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
6760 /* The dialog window is created with a vbox packed into it. */
6761 gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)->vbox), scrolled_window,
6763 gtk_widget_show (scrolled_window);
6765 /* create a table of 10 by 10 squares. */
6766 table = gtk_table_new (10, 10, FALSE);
6768 /* set the spacing to 10 on x and 10 on y */
6769 gtk_table_set_row_spacings (GTK_TABLE (table), 10);
6770 gtk_table_set_col_spacings (GTK_TABLE (table), 10);
6772 /* pack the table into the scrolled window */
6773 gtk_scrolled_window_add_with_viewport (
6774 GTK_SCROLLED_WINDOW (scrolled_window), table);
6775 gtk_widget_show (table);
6777 /* this simply creates a grid of toggle buttons on the table
6778 * to demonstrate the scrolled window. */
6779 for (i = 0; i < 10; i++)
6780 for (j = 0; j < 10; j++) {
6781 sprintf (buffer, "button (%d,%d)\n", i, j);
6782 button = gtk_toggle_button_new_with_label (buffer);
6783 gtk_table_attach_defaults (GTK_TABLE (table), button,
6785 gtk_widget_show (button);
6788 /* Add a "close" button to the bottom of the dialog */
6789 button = gtk_button_new_with_label ("close");
6790 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
6791 (GtkSignalFunc) gtk_widget_destroy,
6792 GTK_OBJECT (window));
6794 /* this makes it so the button is the default. */
6796 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
6797 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0);
6799 /* This grabs this button to be the default button. Simply hitting
6800 * the "Enter" key will cause this button to activate. */
6801 gtk_widget_grab_default (button);
6802 gtk_widget_show (button);
6804 gtk_widget_show (window);
6813 Try playing with resizing the window. You'll notice how the scrollbars
6814 react. You may also wish to use the gtk_widget_set_usize() call to set
6815 the default size of the window or other widgets.
6817 <!-- ----------------------------------------------------------------- -->
6820 Button Boxes are a convenient way to quickly layout a group of
6821 buttons. They come in both horizontal and vertical flavours. You
6822 create a new Button Box with one of the following calls, which create
6823 a horizontal or vertical box, respectively:
6826 GtkWidget *gtk_hbutton_box_new( void );
6828 GtkWidget *gtk_vbutton_box_new( void );
6831 The only attributes pertaining to button boxes effect how the buttons
6832 are laid out. You can change the spacing between the buttons with:
6835 void gtk_hbutton_box_set_spacing_default( gint spacing );
6837 void gtk_vbutton_box_set_spacing_default( gint spacing );
6840 Similarly, the current spacing values can be queried using:
6843 gint gtk_hbutton_box_get_spacing_default( void );
6845 gint gtk_vbutton_box_get_spacing_default( void );
6848 The second attribute that we can access effects the layout of the
6849 buttons within the box. It is set using one of:
6852 void gtk_hbutton_box_set_layout_default( GtkButtonBoxStyle layout );
6854 void gtk_vbutton_box_set_layout_default( GtkButtonBoxStyle layout );
6857 The <tt/layout/ argument can take one of the following values:
6860 GTK_BUTTONBOX_DEFAULT_STYLE
6861 GTK_BUTTONBOX_SPREAD
6867 The current layout setting can be retrieved using:
6870 GtkButtonBoxStyle gtk_hbutton_box_get_layout_default( void );
6872 GtkButtonBoxStyle gtk_vbutton_box_get_layout_default( void );
6875 Buttons are added to a Button Box using the usual function:
6878 gtk_container_add( GTK_CONTAINER(button_box), child_widget );
6881 Here's an example that illustrates all the different layout settings
6885 /* example-start buttonbox buttonbox.c */
6887 #include <gtk/gtk.h>
6889 /* Create a Button Box with the specified parameters */
6890 GtkWidget *create_bbox (gint horizontal,
6901 frame = gtk_frame_new (title);
6904 bbox = gtk_hbutton_box_new ();
6906 bbox = gtk_vbutton_box_new ();
6908 gtk_container_set_border_width (GTK_CONTAINER (bbox), 5);
6909 gtk_container_add (GTK_CONTAINER (frame), bbox);
6911 /* Set the appearance of the Button Box */
6912 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), layout);
6913 gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), spacing);
6914 gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), child_w, child_h);
6916 button = gtk_button_new_with_label ("OK");
6917 gtk_container_add (GTK_CONTAINER (bbox), button);
6919 button = gtk_button_new_with_label ("Cancel");
6920 gtk_container_add (GTK_CONTAINER (bbox), button);
6922 button = gtk_button_new_with_label ("Help");
6923 gtk_container_add (GTK_CONTAINER (bbox), button);
6931 static GtkWidget* window = NULL;
6932 GtkWidget *main_vbox;
6935 GtkWidget *frame_horz;
6936 GtkWidget *frame_vert;
6938 /* Initialize GTK */
6939 gtk_init( &argc, &argv );
6941 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6942 gtk_window_set_title (GTK_WINDOW (window), "Button Boxes");
6944 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6945 GTK_SIGNAL_FUNC(gtk_main_quit),
6948 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6950 main_vbox = gtk_vbox_new (FALSE, 0);
6951 gtk_container_add (GTK_CONTAINER (window), main_vbox);
6953 frame_horz = gtk_frame_new ("Horizontal Button Boxes");
6954 gtk_box_pack_start (GTK_BOX (main_vbox), frame_horz, TRUE, TRUE, 10);
6956 vbox = gtk_vbox_new (FALSE, 0);
6957 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
6958 gtk_container_add (GTK_CONTAINER (frame_horz), vbox);
6960 gtk_box_pack_start (GTK_BOX (vbox),
6961 create_bbox (TRUE, "Spread (spacing 40)", 40, 85, 20, GTK_BUTTONBOX_SPREAD),
6964 gtk_box_pack_start (GTK_BOX (vbox),
6965 create_bbox (TRUE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
6968 gtk_box_pack_start (GTK_BOX (vbox),
6969 create_bbox (TRUE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
6972 gtk_box_pack_start (GTK_BOX (vbox),
6973 create_bbox (TRUE, "End (spacing 10)", 10, 85, 20, GTK_BUTTONBOX_END),
6976 frame_vert = gtk_frame_new ("Vertical Button Boxes");
6977 gtk_box_pack_start (GTK_BOX (main_vbox), frame_vert, TRUE, TRUE, 10);
6979 hbox = gtk_hbox_new (FALSE, 0);
6980 gtk_container_set_border_width (GTK_CONTAINER (hbox), 10);
6981 gtk_container_add (GTK_CONTAINER (frame_vert), hbox);
6983 gtk_box_pack_start (GTK_BOX (hbox),
6984 create_bbox (FALSE, "Spread (spacing 5)", 5, 85, 20, GTK_BUTTONBOX_SPREAD),
6987 gtk_box_pack_start (GTK_BOX (hbox),
6988 create_bbox (FALSE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
6991 gtk_box_pack_start (GTK_BOX (hbox),
6992 create_bbox (FALSE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
6995 gtk_box_pack_start (GTK_BOX (hbox),
6996 create_bbox (FALSE, "End (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_END),
6999 gtk_widget_show_all (window);
7001 /* Enter the event loop */
7009 <!-- ----------------------------------------------------------------- -->
7012 Toolbars are usually used to group some number of widgets in order to
7013 simplify customization of their look and layout. Typically a toolbar
7014 consists of buttons with icons, labels and tooltips, but any other
7015 widget can also be put inside a toolbar. Finally, items can be
7016 arranged horizontally or vertically and buttons can be displayed with
7017 icons, labels, or both.
7019 Creating a toolbar is (as one may already suspect) done with the
7023 GtkWidget *gtk_toolbar_new( GtkOrientation orientation,
7024 GtkToolbarStyle style );
7027 where orientation may be one of:
7030 GTK_ORIENTATION_HORIZONTAL
7031 GTK_ORIENTATION_VERTICAL
7042 The style applies to all the buttons created with the `item' functions
7043 (not to buttons inserted into toolbar as separate widgets).
7045 After creating a toolbar one can append, prepend and insert items
7046 (that means simple text strings) or elements (that means any widget
7047 types) into the toolbar. To describe an item we need a label text, a
7048 tooltip text, a private tooltip text, an icon for the button and a
7049 callback function for it. For example, to append or prepend an item
7050 you may use the following functions:
7053 GtkWidget *gtk_toolbar_append_item( GtkToolbar *toolbar,
7055 const char *tooltip_text,
7056 const char *tooltip_private_text,
7058 GtkSignalFunc callback,
7059 gpointer user_data );
7061 GtkWidget *gtk_toolbar_prepend_item( GtkToolbar *toolbar,
7063 const char *tooltip_text,
7064 const char *tooltip_private_text,
7066 GtkSignalFunc callback,
7067 gpointer user_data );
7070 If you want to use gtk_toolbar_insert_item, the only additional
7071 parameter which must be specified is the position in which the item
7072 should be inserted, thus:
7075 GtkWidget *gtk_toolbar_insert_item( GtkToolbar *toolbar,
7077 const char *tooltip_text,
7078 const char *tooltip_private_text,
7080 GtkSignalFunc callback,
7085 To simplify adding spaces between toolbar items, you may use the
7086 following functions:
7089 void gtk_toolbar_append_space( GtkToolbar *toolbar );
7091 void gtk_toolbar_prepend_space( GtkToolbar *toolbar );
7093 void gtk_toolbar_insert_space( GtkToolbar *toolbar,
7098 While the size of the added space can be set globally for a
7099 whole toolbar with the function:
7102 void gtk_toolbar_set_space_size( GtkToolbar *toolbar,
7106 If it's required, the orientation of a toolbar and its style can be
7107 changed "on the fly" using the following functions:
7110 void gtk_toolbar_set_orientation( GtkToolbar *toolbar,
7111 GtkOrientation orientation );
7113 void gtk_toolbar_set_style( GtkToolbar *toolbar,
7114 GtkToolbarStyle style );
7116 void gtk_toolbar_set_tooltips( GtkToolbar *toolbar,
7120 Where <tt/orientation/ is one of <tt/GTK_ORIENTATION_HORIZONTAL/ or
7121 <tt/GTK_ORIENTATION_VERTICAL/. The <tt/style/ is used to set
7122 appearance of the toolbar items by using one of
7123 <tt/GTK_TOOLBAR_ICONS/, <tt/GTK_TOOLBAR_TEXT/, or
7124 <tt/GTK_TOOLBAR_BOTH/.
7126 To show some other things that can be done with a toolbar, let's take
7127 the following program (we'll interrupt the listing with some
7128 additional explanations):
7131 #include <gtk/gtk.h>
7135 /* This function is connected to the Close button or
7136 * closing the window from the WM */
7137 void delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
7143 The above beginning seems for sure familiar to you if it's not your first
7144 GTK program. There is one additional thing though, we include a nice XPM
7145 picture to serve as an icon for all of the buttons.
7148 GtkWidget* close_button; /* This button will emit signal to close
7150 GtkWidget* tooltips_button; /* to enable/disable tooltips */
7151 GtkWidget* text_button,
7153 * both_button; /* radio buttons for toolbar style */
7154 GtkWidget* entry; /* a text entry to show packing any widget into
7158 In fact not all of the above widgets are needed here, but to make things
7159 clearer I put them all together.
7162 /* that's easy... when one of the buttons is toggled, we just
7163 * check which one is active and set the style of the toolbar
7165 * ATTENTION: our toolbar is passed as data to callback ! */
7166 void radio_event (GtkWidget *widget, gpointer data)
7168 if (GTK_TOGGLE_BUTTON (text_button)->active)
7169 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_TEXT);
7170 else if (GTK_TOGGLE_BUTTON (icon_button)->active)
7171 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_ICONS);
7172 else if (GTK_TOGGLE_BUTTON (both_button)->active)
7173 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_BOTH);
7176 /* even easier, just check given toggle button and enable/disable
7178 void toggle_event (GtkWidget *widget, gpointer data)
7180 gtk_toolbar_set_tooltips (GTK_TOOLBAR ( data ),
7181 GTK_TOGGLE_BUTTON (widget)->active );
7185 The above are just two callback functions that will be called when
7186 one of the buttons on a toolbar is pressed. You should already be
7187 familiar with things like this if you've already used toggle buttons (and
7191 int main (int argc, char *argv[])
7193 /* Here is our main window (a dialog) and a handle for the handlebox */
7195 GtkWidget* handlebox;
7197 /* Ok, we need a toolbar, an icon with a mask (one for all of
7198 the buttons) and an icon widget to put this icon in (but
7199 we'll create a separate widget for each button) */
7200 GtkWidget * toolbar;
7205 /* this is called in all GTK application. */
7206 gtk_init (&argc, &argv);
7208 /* create a new window with a given title, and nice size */
7209 dialog = gtk_dialog_new ();
7210 gtk_window_set_title ( GTK_WINDOW ( dialog ) , "GTKToolbar Tutorial");
7211 gtk_widget_set_usize( GTK_WIDGET ( dialog ) , 600 , 300 );
7212 GTK_WINDOW ( dialog ) ->allow_shrink = TRUE;
7214 /* typically we quit if someone tries to close us */
7215 gtk_signal_connect ( GTK_OBJECT ( dialog ), "delete_event",
7216 GTK_SIGNAL_FUNC ( delete_event ), NULL);
7218 /* we need to realize the window because we use pixmaps for
7219 * items on the toolbar in the context of it */
7220 gtk_widget_realize ( dialog );
7222 /* to make it nice we'll put the toolbar into the handle box,
7223 * so that it can be detached from the main window */
7224 handlebox = gtk_handle_box_new ();
7225 gtk_box_pack_start ( GTK_BOX ( GTK_DIALOG(dialog)->vbox ),
7226 handlebox, FALSE, FALSE, 5 );
7229 The above should be similar to any other GTK application. Just
7230 initialization of GTK, creating the window, etc. There is only one
7231 thing that probably needs some explanation: a handle box. A handle box
7232 is just another box that can be used to pack widgets in to. The
7233 difference between it and typical boxes is that it can be detached
7234 from a parent window (or, in fact, the handle box remains in the
7235 parent, but it is reduced to a very small rectangle, while all of its
7236 contents are reparented to a new freely floating window). It is
7237 usually nice to have a detachable toolbar, so these two widgets occur
7238 together quite often.
7241 /* toolbar will be horizontal, with both icons and text, and
7242 * with 5pxl spaces between items and finally,
7243 * we'll also put it into our handlebox */
7244 toolbar = gtk_toolbar_new ( GTK_ORIENTATION_HORIZONTAL,
7246 gtk_container_set_border_width ( GTK_CONTAINER ( toolbar ) , 5 );
7247 gtk_toolbar_set_space_size ( GTK_TOOLBAR ( toolbar ), 5 );
7248 gtk_container_add ( GTK_CONTAINER ( handlebox ) , toolbar );
7250 /* now we create icon with mask: we'll reuse it to create
7251 * icon widgets for toolbar items */
7252 icon = gdk_pixmap_create_from_xpm_d ( dialog->window, &mask,
7253 &dialog->style->white, gtk_xpm );
7256 Well, what we do above is just a straightforward initialization of
7257 the toolbar widget and creation of a GDK pixmap with its mask. If you
7258 want to know something more about using pixmaps, refer to GDK
7259 documentation or to the <ref id="sec_Pixmaps" name="Pixmaps"> section
7260 earlier in this tutorial.
7263 /* our first item is <close> button */
7264 iconw = gtk_pixmap_new ( icon, mask ); /* icon widget */
7266 gtk_toolbar_append_item ( GTK_TOOLBAR (toolbar), /* our toolbar */
7267 "Close", /* button label */
7268 "Closes this app", /* this button's tooltip */
7269 "Private", /* tooltip private info */
7270 iconw, /* icon widget */
7271 GTK_SIGNAL_FUNC (delete_event), /* a signal */
7273 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) ); /* space after item */
7276 In the above code you see the simplest case: adding a button to
7277 toolbar. Just before appending a new item, we have to construct a
7278 pixmap widget to serve as an icon for this item; this step will have
7279 to be repeated for each new item. Just after the item we also add a
7280 space, so the following items will not touch each other. As you see
7281 gtk_toolbar_append_item returns a pointer to our newly created button
7282 widget, so that we can work with it in the normal way.
7285 /* now, let's make our radio buttons group... */
7286 iconw = gtk_pixmap_new ( icon, mask );
7287 icon_button = gtk_toolbar_append_element(
7288 GTK_TOOLBAR(toolbar),
7289 GTK_TOOLBAR_CHILD_RADIOBUTTON, /* a type of element */
7290 NULL, /* pointer to widget */
7292 "Only icons in toolbar", /* tooltip */
7293 "Private", /* tooltip private string */
7295 GTK_SIGNAL_FUNC (radio_event), /* signal */
7296 toolbar); /* data for signal */
7297 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7300 Here we begin creating a radio buttons group. To do this we use
7301 gtk_toolbar_append_element. In fact, using this function one can also
7302 +add simple items or even spaces (type = <tt/GTK_TOOLBAR_CHILD_SPACE/
7303 or +<tt/GTK_TOOLBAR_CHILD_BUTTON/). In the above case we start
7304 creating a radio group. In creating other radio buttons for this group
7305 a pointer to the previous button in the group is required, so that a
7306 list of buttons can be easily constructed (see the section on <ref
7307 id="sec_Radio_Buttons" name="Radio Buttons"> earlier in this
7311 /* following radio buttons refer to previous ones */
7312 iconw = gtk_pixmap_new ( icon, mask );
7314 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
7315 GTK_TOOLBAR_CHILD_RADIOBUTTON,
7318 "Only texts in toolbar",
7321 GTK_SIGNAL_FUNC (radio_event),
7323 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7325 iconw = gtk_pixmap_new ( icon, mask );
7327 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
7328 GTK_TOOLBAR_CHILD_RADIOBUTTON,
7331 "Icons and text in toolbar",
7334 GTK_SIGNAL_FUNC (radio_event),
7336 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7337 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(both_button),TRUE);
7340 In the end we have to set the state of one of the buttons manually
7341 (otherwise they all stay in active state, preventing us from switching
7345 /* here we have just a simple toggle button */
7346 iconw = gtk_pixmap_new ( icon, mask );
7348 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
7349 GTK_TOOLBAR_CHILD_TOGGLEBUTTON,
7352 "Toolbar with or without tips",
7355 GTK_SIGNAL_FUNC (toggle_event),
7357 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7358 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tooltips_button),TRUE);
7361 A toggle button can be created in the obvious way (if one knows how to create
7362 radio buttons already).
7365 /* to pack a widget into toolbar, we only have to
7366 * create it and append it with an appropriate tooltip */
7367 entry = gtk_entry_new ();
7368 gtk_toolbar_append_widget( GTK_TOOLBAR (toolbar),
7370 "This is just an entry",
7373 /* well, it isn't created within thetoolbar, so we must still show it */
7374 gtk_widget_show ( entry );
7377 As you see, adding any kind of widget to a toolbar is simple. The
7378 one thing you have to remember is that this widget must be shown manually
7379 (contrary to other items which will be shown together with the toolbar).
7382 /* that's it ! let's show everything. */
7383 gtk_widget_show ( toolbar );
7384 gtk_widget_show (handlebox);
7385 gtk_widget_show ( dialog );
7387 /* rest in gtk_main and wait for the fun to begin! */
7394 So, here we are at the end of toolbar tutorial. Of course, to appreciate
7395 it in full you need also this nice XPM icon, so here it is:
7399 static char * gtk_xpm[] = {
7406 "................+...............",
7407 "..............+++++.............",
7408 "............+++++@@++...........",
7409 "..........+++++@@@@@@++.........",
7410 "........++++@@@@@@@@@@++........",
7411 "......++++@@++++++++@@@++.......",
7412 ".....+++@@@+++++++++++@@@++.....",
7413 "...+++@@@@+++@@@@@@++++@@@@+....",
7414 "..+++@@@@+++@@@@@@@@+++@@@@@++..",
7415 ".++@@@@@@+++@@@@@@@@@@@@@@@@@@++",
7416 ".+#+@@@@@@++@@@@+++@@@@@@@@@@@@+",
7417 ".+##++@@@@+++@@@+++++@@@@@@@@$@.",
7418 ".+###++@@@@+++@@@+++@@@@@++$$$@.",
7419 ".+####+++@@@+++++++@@@@@+@$$$$@.",
7420 ".+#####+++@@@@+++@@@@++@$$$$$$+.",
7421 ".+######++++@@@@@@@++@$$$$$$$$+.",
7422 ".+#######+##+@@@@+++$$$$$$@@$$+.",
7423 ".+###+++##+##+@@++@$$$$$$++$$$+.",
7424 ".+###++++##+##+@@$$$$$$$@+@$$@+.",
7425 ".+###++++++#+++@$$@+@$$@++$$$@+.",
7426 ".+####+++++++#++$$@+@$$++$$$$+..",
7427 ".++####++++++#++$$@+@$++@$$$$+..",
7428 ".+#####+++++##++$$++@+++$$$$$+..",
7429 ".++####+++##+#++$$+++++@$$$$$+..",
7430 ".++####+++####++$$++++++@$$$@+..",
7431 ".+#####++#####++$$+++@++++@$@+..",
7432 ".+#####++#####++$$++@$$@+++$@@..",
7433 ".++####++#####++$$++$$$$$+@$@++.",
7434 ".++####++#####++$$++$$$$$$$$+++.",
7435 ".+++####+#####++$$++$$$$$$$@+++.",
7436 "..+++#########+@$$+@$$$$$$+++...",
7437 "...+++########+@$$$$$$$$@+++....",
7438 ".....+++######+@$$$$$$$+++......",
7439 "......+++#####+@$$$$$@++........",
7440 ".......+++####+@$$$$+++.........",
7441 ".........++###+$$$@++...........",
7442 "..........++##+$@+++............",
7443 "...........+++++++..............",
7444 ".............++++..............."};
7447 <!-- ----------------------------------------------------------------- -->
7450 The NoteBook Widget is a collection of "pages" that overlap each
7451 other, each page contains different information with only one page
7452 visible at a time. This widget has become more common lately in GUI
7453 programming, and it is a good way to show blocks of similar
7454 information that warrant separation in their display.
7456 The first function call you will need to know, as you can probably
7457 guess by now, is used to create a new notebook widget.
7460 GtkWidget *gtk_notebook_new( void );
7463 Once the notebook has been created, there are a number of functions
7464 that operate on the notebook widget. Let's look at them individually.
7466 The first one we will look at is how to position the page indicators.
7467 These page indicators or "tabs" as they are referred to, can be
7468 positioned in four ways: top, bottom, left, or right.
7471 void gtk_notebook_set_tab_pos( GtkNotebook *notebook,
7472 GtkPositionType pos );
7475 GtkPositionType will be one of the following, which are pretty self
7484 <tt/GTK_POS_TOP/ is the default.
7486 Next we will look at how to add pages to the notebook. There are three
7487 ways to add pages to the NoteBook. Let's look at the first two
7488 together as they are quite similar.
7491 void gtk_notebook_append_page( GtkNotebook *notebook,
7493 GtkWidget *tab_label );
7495 void gtk_notebook_prepend_page( GtkNotebook *notebook,
7497 GtkWidget *tab_label );
7500 These functions add pages to the notebook by inserting them from the
7501 back of the notebook (append), or the front of the notebook (prepend).
7502 <tt/child/ is the widget that is placed within the notebook page, and
7503 <tt/tab_label/ is the label for the page being added. The <tt/child/
7504 widget must be created separately, and is typically a set of options
7505 setup witin one of the other container widgets, such as a table.
7507 The final function for adding a page to the notebook contains all of
7508 the properties of the previous two, but it allows you to specify what
7509 position you want the page to be in the notebook.
7512 void gtk_notebook_insert_page( GtkNotebook *notebook,
7514 GtkWidget *tab_label,
7518 The parameters are the same as _append_ and _prepend_ except it
7519 contains an extra parameter, <tt/position/. This parameter is used to
7520 specify what place this page will be inserted into the first page
7521 having position zero.
7523 Now that we know how to add a page, lets see how we can remove a page
7527 void gtk_notebook_remove_page( GtkNotebook *notebook,
7531 This function takes the page specified by <tt/page_num/ and removes it
7532 from the widget pointed to by <tt/notebook/.
7534 To find out what the current page is in a notebook use the function:
7537 gint gtk_notebook_get_current_page( GtkNotebook *notebook );
7540 These next two functions are simple calls to move the notebook page
7541 forward or backward. Simply provide the respective function call with
7542 the notebook widget you wish to operate on. Note: When the NoteBook is
7543 currently on the last page, and gtk_notebook_next_page is called, the
7544 notebook will wrap back to the first page. Likewise, if the NoteBook
7545 is on the first page, and gtk_notebook_prev_page is called, the
7546 notebook will wrap to the last page.
7549 void gtk_notebook_next_page( GtkNoteBook *notebook );
7551 void gtk_notebook_prev_page( GtkNoteBook *notebook );
7554 This next function sets the "active" page. If you wish the notebook to
7555 be opened to page 5 for example, you would use this function. Without
7556 using this function, the notebook defaults to the first page.
7559 void gtk_notebook_set_page( GtkNotebook *notebook,
7563 The next two functions add or remove the notebook page tabs and the
7564 notebook border respectively.
7567 void gtk_notebook_set_show_tabs( GtkNotebook *notebook,
7568 gboolean show_tabs);
7570 void gtk_notebook_set_show_border( GtkNotebook *notebook,
7571 gboolean show_border );
7574 The next function is useful when the you have a large number of pages,
7575 and the tabs don't fit on the page. It allows the tabs to be scrolled
7576 through using two arrow buttons.
7579 void gtk_notebook_set_scrollable( GtkNotebook *notebook,
7580 gboolean scrollable );
7583 <tt/show_tabs/, <tt/show_border/ and <tt/scrollable/ can be either
7586 Now let's look at an example, it is expanded from the testgtk.c code
7587 that comes with the GTK distribution. This small program creates a
7588 window with a notebook and six buttons. The notebook contains 11
7589 pages, added in three different ways, appended, inserted, and
7590 prepended. The buttons allow you rotate the tab positions, add/remove
7591 the tabs and border, remove a page, change pages in both a forward and
7592 backward manner, and exit the program.
7595 /* example-start notebook notebook.c */
7597 #include <gtk/gtk.h>
7599 /* This function rotates the position of the tabs */
7600 void rotate_book (GtkButton *button, GtkNotebook *notebook)
7602 gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos +1) %4);
7605 /* Add/Remove the page tabs and the borders */
7606 void tabsborder_book (GtkButton *button, GtkNotebook *notebook)
7610 if (notebook->show_tabs == 0)
7612 if (notebook->show_border == 0)
7615 gtk_notebook_set_show_tabs (notebook, tval);
7616 gtk_notebook_set_show_border (notebook, bval);
7619 /* Remove a page from the notebook */
7620 void remove_book (GtkButton *button, GtkNotebook *notebook)
7624 page = gtk_notebook_get_current_page(notebook);
7625 gtk_notebook_remove_page (notebook, page);
7626 /* Need to refresh the widget --
7627 This forces the widget to redraw itself. */
7628 gtk_widget_draw(GTK_WIDGET(notebook), NULL);
7631 void delete (GtkWidget *widget, GtkWidget *event, gpointer data)
7636 int main (int argc, char *argv[])
7641 GtkWidget *notebook;
7644 GtkWidget *checkbutton;
7649 gtk_init (&argc, &argv);
7651 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
7653 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
7654 GTK_SIGNAL_FUNC (delete), NULL);
7656 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
7658 table = gtk_table_new(3,6,FALSE);
7659 gtk_container_add (GTK_CONTAINER (window), table);
7661 /* Create a new notebook, place the position of the tabs */
7662 notebook = gtk_notebook_new ();
7663 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
7664 gtk_table_attach_defaults(GTK_TABLE(table), notebook, 0,6,0,1);
7665 gtk_widget_show(notebook);
7667 /* Let's append a bunch of pages to the notebook */
7668 for (i=0; i < 5; i++) {
7669 sprintf(bufferf, "Append Frame %d", i+1);
7670 sprintf(bufferl, "Page %d", i+1);
7672 frame = gtk_frame_new (bufferf);
7673 gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
7674 gtk_widget_set_usize (frame, 100, 75);
7675 gtk_widget_show (frame);
7677 label = gtk_label_new (bufferf);
7678 gtk_container_add (GTK_CONTAINER (frame), label);
7679 gtk_widget_show (label);
7681 label = gtk_label_new (bufferl);
7682 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
7685 /* Now let's add a page to a specific spot */
7686 checkbutton = gtk_check_button_new_with_label ("Check me please!");
7687 gtk_widget_set_usize(checkbutton, 100, 75);
7688 gtk_widget_show (checkbutton);
7690 label = gtk_label_new ("Add page");
7691 gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, label, 2);
7693 /* Now finally let's prepend pages to the notebook */
7694 for (i=0; i < 5; i++) {
7695 sprintf(bufferf, "Prepend Frame %d", i+1);
7696 sprintf(bufferl, "PPage %d", i+1);
7698 frame = gtk_frame_new (bufferf);
7699 gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
7700 gtk_widget_set_usize (frame, 100, 75);
7701 gtk_widget_show (frame);
7703 label = gtk_label_new (bufferf);
7704 gtk_container_add (GTK_CONTAINER (frame), label);
7705 gtk_widget_show (label);
7707 label = gtk_label_new (bufferl);
7708 gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook), frame, label);
7711 /* Set what page to start at (page 4) */
7712 gtk_notebook_set_page (GTK_NOTEBOOK(notebook), 3);
7714 /* Create a bunch of buttons */
7715 button = gtk_button_new_with_label ("close");
7716 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
7717 GTK_SIGNAL_FUNC (delete), NULL);
7718 gtk_table_attach_defaults(GTK_TABLE(table), button, 0,1,1,2);
7719 gtk_widget_show(button);
7721 button = gtk_button_new_with_label ("next page");
7722 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
7723 (GtkSignalFunc) gtk_notebook_next_page,
7724 GTK_OBJECT (notebook));
7725 gtk_table_attach_defaults(GTK_TABLE(table), button, 1,2,1,2);
7726 gtk_widget_show(button);
7728 button = gtk_button_new_with_label ("prev page");
7729 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
7730 (GtkSignalFunc) gtk_notebook_prev_page,
7731 GTK_OBJECT (notebook));
7732 gtk_table_attach_defaults(GTK_TABLE(table), button, 2,3,1,2);
7733 gtk_widget_show(button);
7735 button = gtk_button_new_with_label ("tab position");
7736 gtk_signal_connect (GTK_OBJECT (button), "clicked",
7737 (GtkSignalFunc) rotate_book,
7738 GTK_OBJECT(notebook));
7739 gtk_table_attach_defaults(GTK_TABLE(table), button, 3,4,1,2);
7740 gtk_widget_show(button);
7742 button = gtk_button_new_with_label ("tabs/border on/off");
7743 gtk_signal_connect (GTK_OBJECT (button), "clicked",
7744 (GtkSignalFunc) tabsborder_book,
7745 GTK_OBJECT (notebook));
7746 gtk_table_attach_defaults(GTK_TABLE(table), button, 4,5,1,2);
7747 gtk_widget_show(button);
7749 button = gtk_button_new_with_label ("remove page");
7750 gtk_signal_connect (GTK_OBJECT (button), "clicked",
7751 (GtkSignalFunc) remove_book,
7752 GTK_OBJECT(notebook));
7753 gtk_table_attach_defaults(GTK_TABLE(table), button, 5,6,1,2);
7754 gtk_widget_show(button);
7756 gtk_widget_show(table);
7757 gtk_widget_show(window);
7766 I hope this helps you on your way with creating notebooks for your
7769 <!-- ***************************************************************** -->
7771 <!-- ***************************************************************** -->
7773 <!-- ----------------------------------------------------------------- -->
7775 The CList widget has replaced the List widget (which is still
7778 The CList widget is a multi-column list widget that is capable of
7779 handling literally thousands of rows of information. Each column can
7780 optionally have a title, which itself is optionally active, allowing
7781 us to bind a function to its selection.
7783 <!-- ----------------------------------------------------------------- -->
7784 <sect1>Creating a CList widget
7786 Creating a CList is quite straightforward, once you have learned
7787 about widgets in general. It provides the almost standard two ways,
7788 that is the hard way, and the easy way. But before we create it, there
7789 is one thing we should figure out beforehand: how many columns should
7792 Not all columns have to be visible and can be used to store data that
7793 is related to a certain cell in the list.
7796 GtkWidget *gtk_clist_new ( gint columns );
7798 GtkWidget *gtk_clist_new_with_titles( gint columns,
7802 The first form is very straightforward, the second might require some
7803 explanation. Each column can have a title associated with it, and this
7804 title can be a label or a button that reacts when we click on it. If
7805 we use the second form, we must provide pointers to the title texts,
7806 and the number of pointers should equal the number of columns
7807 specified. Of course we can always use the first form, and manually
7810 Note: The CList widget does not have its own scrollbars and should
7811 be placed within a ScrolledWindow widget if your require this
7812 functionality. This is a change from the GTK 1.0 implementation.
7814 <!-- ----------------------------------------------------------------- -->
7815 <sect1>Modes of operation
7817 There are several attributes that can be used to alter the behaviour of
7818 a CList. First there is
7821 void gtk_clist_set_selection_mode( GtkCList *clist,
7822 GtkSelectionMode mode );
7825 which, as the name implies, sets the selection mode of the
7826 CList. The first argument is the CList widget, and the second
7827 specifies the cell selection mode (they are defined in gtkenums.h). At
7828 the time of this writing, the following modes are available to us:
7831 <item> <tt/GTK_SELECTION_SINGLE/ - The selection is either NULL or contains
7832 a GList pointer for a single selected item.
7834 <item> <tt/GTK_SELECTION_BROWSE/ - The selection is NULL if the list
7835 contains no widgets or insensitive ones only, otherwise it contains a
7836 GList pointer for one GList structure, and therefore exactly one list
7839 <item> <tt/GTK_SELECTION_MULTIPLE/ - The selection is NULL if no list items
7840 are selected or a GList pointer for the first selected item. That in
7841 turn points to a GList structure for the second selected item and so
7842 on. This is currently the <bf>default</bf> for the CList widget.
7844 <item> <tt/GTK_SELECTION_EXTENDED/ - The selection is always NULL.
7847 Others might be added in later revisions of GTK.
7849 We can also define what the border of the CList widget should look
7850 like. It is done through
7853 void gtk_clist_set_shadow_type( GtkCList *clist,
7854 GtkShadowType border );
7857 The possible values for the second argument are
7863 GTK_SHADOW_ETCHED_IN
7864 GTK_SHADOW_ETCHED_OUT
7867 <!-- ----------------------------------------------------------------- -->
7868 <sect1>Working with titles
7870 When you create a CList widget, you will also get a set of title
7871 buttons automatically. They live in the top of the CList window, and
7872 can act either as normal buttons that respond to being pressed, or
7873 they can be passive, in which case they are nothing more than a
7874 title. There are four different calls that aid us in setting the
7875 status of the title buttons.
7878 void gtk_clist_column_title_active( GtkCList *clist,
7881 void gtk_clist_column_title_passive( GtkCList *clist,
7884 void gtk_clist_column_titles_active( GtkCList *clist );
7886 void gtk_clist_column_titles_passive( GtkCList *clist );
7889 An active title is one which acts as a normal button, a passive one is
7890 just a label. The first two calls above will activate/deactivate the
7891 title button above the specific column, while the last two calls
7892 activate/deactivate all title buttons in the supplied clist widget.
7894 But of course there are those cases when we don't want them at all,
7895 and so they can be hidden and shown at will using the following two
7899 void gtk_clist_column_titles_show( GtkCList *clist );
7901 void gtk_clist_column_titles_hide( GtkCList *clist );
7904 For titles to be really useful we need a mechanism to set and change
7905 them, and this is done using
7908 void gtk_clist_set_column_title( GtkCList *clist,
7913 Note that only the title of one column can be set at a time, so if all
7914 the titles are known from the beginning, then I really suggest using
7915 gtk_clist_new_with_titles (as described above) to set them. It saves
7916 you coding time, and makes your program smaller. There are some cases
7917 where getting the job done the manual way is better, and that's when
7918 not all titles will be text. CList provides us with title buttons
7919 that can in fact incorporate whole widgets, for example a pixmap. It's
7923 void gtk_clist_set_column_widget( GtkCList *clist,
7925 GtkWidget *widget );
7928 which should require no special explanation.
7930 <!-- ----------------------------------------------------------------- -->
7931 <sect1>Manipulating the list itself
7933 It is possible to change the justification for a column, and it is
7937 void gtk_clist_set_column_justification( GtkCList *clist,
7939 GtkJustification justification );
7942 The GtkJustification type can take the following values:
7945 <item><tt/GTK_JUSTIFY_LEFT/ - The text in the column will begin from the
7948 <item><tt/GTK_JUSTIFY_RIGHT/ - The text in the column will begin from the
7951 <item><tt/GTK_JUSTIFY_CENTER/ - The text is placed in the center of the
7954 <item><tt/GTK_JUSTIFY_FILL/ - The text will use up all available space in
7955 the column. It is normally done by inserting extra blank spaces
7956 between words (or between individual letters if it's a single
7957 word). Much in the same way as any ordinary WYSIWYG text editor.
7960 The next function is a very important one, and should be standard in
7961 the setup of all CList widgets. When the list is created, the width
7962 of the various columns are chosen to match their titles, and since
7963 this is seldom the right width we have to set it using
7966 void gtk_clist_set_column_width( GtkCList *clist,
7971 Note that the width is given in pixels and not letters. The same goes
7972 for the height of the cells in the columns, but as the default value
7973 is the height of the current font this isn't as critical to the
7974 application. Still, it is done through
7977 void gtk_clist_set_row_height( GtkCList *clist,
7981 Again, note that the height is given in pixels.
7983 We can also move the list around without user interaction, however, it
7984 does require that we know what we are looking for. Or in other words,
7985 we need the row and column of the item we want to scroll to.
7988 void gtk_clist_moveto( GtkCList *clist,
7995 The gfloat row_align is pretty important to understand. It's a value
7996 between 0.0 and 1.0, where 0.0 means that we should scroll the list so
7997 the row appears at the top, while if the value of row_align is 1.0,
7998 the row will appear at the bottom instead. All other values between
7999 0.0 and 1.0 are also valid and will place the row between the top and
8000 the bottom. The last argument, gfloat col_align works in the same way,
8001 though 0.0 marks left and 1.0 marks right instead.
8003 Depending on the application's needs, we don't have to scroll to an
8004 item that is already visible to us. So how do we know if it is
8005 visible? As usual, there is a function to find that out as well.
8008 GtkVisibility gtk_clist_row_is_visible( GtkCList *clist,
8012 The return value is is one of the following:
8016 GTK_VISIBILITY_PARTIAL
8020 Note that it will only tell us if a row is visible. Currently there is
8021 no way to determine this for a column. We can get partial information
8022 though, because if the return is <tt/GTK_VISIBILITY_PARTIAL/, then
8023 some of it is hidden, but we don't know if it is the row that is being
8024 cut by the lower edge of the listbox, or if the row has columns that
8027 We can also change both the foreground and background colors of a
8028 particular row. This is useful for marking the row selected by the
8029 user, and the two functions that is used to do it are
8032 void gtk_clist_set_foreground( GtkCList *clist,
8036 void gtk_clist_set_background( GtkCList *clist,
8041 Please note that the colors must have been previously allocated.
8043 <!-- ----------------------------------------------------------------- -->
8044 <sect1>Adding rows to the list
8046 We can add rows in three ways. They can be prepended or appended to
8050 gint gtk_clist_prepend( GtkCList *clist,
8053 gint gtk_clist_append( GtkCList *clist,
8057 The return value of these two functions indicate the index of the row
8058 that was just added. We can insert a row at a given place using
8061 void gtk_clist_insert( GtkCList *clist,
8066 In these calls we have to provide a collection of pointers that are
8067 the texts we want to put in the columns. The number of pointers should
8068 equal the number of columns in the list. If the text[] argument is
8069 NULL, then there will be no text in the columns of the row. This is
8070 useful, for example, if we want to add pixmaps instead (something that
8071 has to be done manually).
8073 Also, please note that the numbering of both rows and columns start at 0.
8075 To remove an individual row we use
8078 void gtk_clist_remove( GtkCList *clist,
8082 There is also a call that removes all rows in the list. This is a lot
8083 faster than calling gtk_clist_remove once for each row, which is the
8087 void gtk_clist_clear( GtkCList *clist );
8090 There are also two convenience functions that should be used when a
8091 lot of changes have to be made to the list. This is to prevent the
8092 list flickering while being repeatedly updated, which may be highly
8093 annoying to the user. So instead it is a good idea to freeze the list,
8094 do the updates to it, and finally thaw it which causes the list to be
8095 updated on the screen.
8098 void gtk_clist_freeze( GtkCList * clist );
8100 void gtk_clist_thaw( GtkCList * clist );
8103 <!-- ----------------------------------------------------------------- -->
8104 <sect1>Setting text and pixmaps in the cells
8106 A cell can contain a pixmap, text or both. To set them the following
8110 void gtk_clist_set_text( GtkCList *clist,
8113 const gchar *text );
8115 void gtk_clist_set_pixmap( GtkCList *clist,
8121 void gtk_clist_set_pixtext( GtkCList *clist,
8130 It's quite straightforward. All the calls have the CList as the first
8131 argument, followed by the row and column of the cell, followed by the
8132 data to be set. The <tt/spacing/ argument in gtk_clist_set_pixtext is
8133 the number of pixels between the pixmap and the beginning of the
8134 text. In all cases the data is copied into the widget.
8136 To read back the data, we instead use
8139 gint gtk_clist_get_text( GtkCList *clist,
8144 gint gtk_clist_get_pixmap( GtkCList *clist,
8150 gint gtk_clist_get_pixtext( GtkCList *clist,
8159 The returned pointers are all pointers to the data stored within the
8160 widget, so the referenced data should not be modified or released. It
8161 isn't necessary to read it all back in case you aren't interested. Any
8162 of the pointers that are meant for return values (all except the
8163 clist) can be NULL. So if we want to read back only the text from a
8164 cell that is of type pixtext, then we would do the following, assuming
8165 that clist, row and column already exist:
8170 gtk_clist_get_pixtext(clist, row, column, &mytext, NULL, NULL, NULL);
8173 There is one more call that is related to what's inside a cell in the
8177 GtkCellType gtk_clist_get_cell_type( GtkCList *clist,
8182 which returns the type of data in a cell. The return value is one of
8192 There is also a function that will let us set the indentation, both
8193 vertical and horizontal, of a cell. The indentation value is of type
8194 gint, given in pixels, and can be both positive and negative.
8197 void gtk_clist_set_shift( GtkCList *clist,
8204 <!-- ----------------------------------------------------------------- -->
8205 <sect1>Storing data pointers
8207 With a CList it is possible to set a data pointer for a row. This
8208 pointer will not be visible for the user, but is merely a convenience
8209 for the programmer to associate a row with a pointer to some
8212 The functions should be fairly self-explanatory by now.
8215 void gtk_clist_set_row_data( GtkCList *clist,
8219 void gtk_clist_set_row_data_full( GtkCList *clist,
8222 GtkDestroyNotify destroy );
8224 gpointer gtk_clist_get_row_data( GtkCList *clist,
8227 gint gtk_clist_find_row_from_data( GtkCList *clist,
8231 <!-- ----------------------------------------------------------------- -->
8232 <sect1>Working with selections
8234 There are also functions available that let us force the (un)selection
8238 void gtk_clist_select_row( GtkCList *clist,
8242 void gtk_clist_unselect_row( GtkCList *clist,
8247 And also a function that will take x and y coordinates (for example,
8248 read from the mousepointer), and map that onto the list, returning the
8249 corresponding row and column.
8252 gint gtk_clist_get_selection_info( GtkCList *clist,
8259 When we detect something of interest (it might be movement of the
8260 pointer, a click somewhere in the list) we can read the pointer
8261 coordinates and find out where in the list the pointer is. Cumbersome?
8262 Luckily, there is a simpler way...
8264 <!-- ----------------------------------------------------------------- -->
8265 <sect1>The signals that bring it together
8267 As with all other widgets, there are a few signals that can be used. The
8268 CList widget is derived from the Container widget, and so has all the
8269 same signals, but also adds the following:
8272 <item>select_row - This signal will send the following information, in
8273 order: GtkCList *clist, gint row, gint column, GtkEventButton *event
8275 <item>unselect_row - When the user unselects a row, this signal is
8276 activated. It sends the same information as select_row
8278 <item>click_column - Send GtkCList *clist, gint column
8281 So if we want to connect a callback to select_row, the callback
8282 function would be declared like this
8285 void select_row_callback(GtkWidget *widget,
8288 GdkEventButton *event,
8292 The callback is connected as usual with
8295 gtk_signal_connect(GTK_OBJECT( clist),
8297 GTK_SIGNAL_FUNC(select_row_callback),
8301 <!-- ----------------------------------------------------------------- -->
8302 <sect1>A CList example
8306 /* example-start clist clist.c */
8308 #include <gtk/gtk.h>
8310 /* User clicked the "Add List" button. */
8311 void button_add_clicked( gpointer data )
8315 /* Something silly to add to the list. 4 rows of 2 columns each */
8316 gchar *drink[4][2] = { { "Milk", "3 Oz" },
8319 { "Snakes", "55" } };
8321 /* Here we do the actual adding of the text. It's done once for
8324 for ( indx=0 ; indx < 4 ; indx++ )
8325 gtk_clist_append( (GtkCList *) data, drink[indx]);
8330 /* User clicked the "Clear List" button. */
8331 void button_clear_clicked( gpointer data )
8333 /* Clear the list using gtk_clist_clear. This is much faster than
8334 * calling gtk_clist_remove once for each row.
8336 gtk_clist_clear( (GtkCList *) data);
8341 /* The user clicked the "Hide/Show titles" button. */
8342 void button_hide_show_clicked( gpointer data )
8344 /* Just a flag to remember the status. 0 = currently visible */
8345 static short int flag = 0;
8349 /* Hide the titles and set the flag to 1 */
8350 gtk_clist_column_titles_hide((GtkCList *) data);
8355 /* Show the titles and reset flag to 0 */
8356 gtk_clist_column_titles_show((GtkCList *) data);
8363 /* If we come here, then the user has selected a row in the list. */
8364 void selection_made( GtkWidget *clist,
8367 GdkEventButton *event,
8372 /* Get the text that is stored in the selected row and column
8373 * which was clicked in. We will receive it as a pointer in the
8376 gtk_clist_get_text(GTK_CLIST(clist), row, column, &text);
8378 /* Just prints some information about the selected row */
8379 g_print("You selected row %d. More specifically you clicked in "
8380 "column %d, and the text in this cell is %s\n\n",
8390 GtkWidget *vbox, *hbox;
8392 GtkWidget *button_add, *button_clear, *button_hide_show;
8393 gchar *titles[2] = { "Ingredients", "Amount" };
8395 gtk_init(&argc, &argv);
8397 window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
8398 gtk_widget_set_usize(GTK_WIDGET(window), 300, 150);
8400 gtk_window_set_title(GTK_WINDOW(window), "GtkCList Example");
8401 gtk_signal_connect(GTK_OBJECT(window),
8403 GTK_SIGNAL_FUNC(gtk_main_quit),
8406 vbox=gtk_vbox_new(FALSE, 5);
8407 gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
8408 gtk_container_add(GTK_CONTAINER(window), vbox);
8409 gtk_widget_show(vbox);
8411 /* Create the CList. For this example we use 2 columns */
8412 clist = gtk_clist_new_with_titles( 2, titles);
8414 /* When a selection is made, we want to know about it. The callback
8415 * used is selection_made, and its code can be found further down */
8416 gtk_signal_connect(GTK_OBJECT(clist), "select_row",
8417 GTK_SIGNAL_FUNC(selection_made),
8420 /* It isn't necessary to shadow the border, but it looks nice :) */
8421 gtk_clist_set_shadow_type (GTK_CLIST(clist), GTK_SHADOW_OUT);
8423 /* What however is important, is that we set the column widths as
8424 * they will never be right otherwise. Note that the columns are
8425 * numbered from 0 and up (to 1 in this case).
8427 gtk_clist_set_column_width (GTK_CLIST(clist), 0, 150);
8429 /* Add the CList widget to the vertical box and show it. */
8430 gtk_box_pack_start(GTK_BOX(vbox), clist, TRUE, TRUE, 0);
8431 gtk_widget_show(clist);
8433 /* Create the buttons and add them to the window. See the button
8434 * tutorial for more examples and comments on this.
8436 hbox = gtk_hbox_new(FALSE, 0);
8437 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
8438 gtk_widget_show(hbox);
8440 button_add = gtk_button_new_with_label("Add List");
8441 button_clear = gtk_button_new_with_label("Clear List");
8442 button_hide_show = gtk_button_new_with_label("Hide/Show titles");
8444 gtk_box_pack_start(GTK_BOX(hbox), button_add, TRUE, TRUE, 0);
8445 gtk_box_pack_start(GTK_BOX(hbox), button_clear, TRUE, TRUE, 0);
8446 gtk_box_pack_start(GTK_BOX(hbox), button_hide_show, TRUE, TRUE, 0);
8448 /* Connect our callbacks to the three buttons */
8449 gtk_signal_connect_object(GTK_OBJECT(button_add), "clicked",
8450 GTK_SIGNAL_FUNC(button_add_clicked),
8452 gtk_signal_connect_object(GTK_OBJECT(button_clear), "clicked",
8453 GTK_SIGNAL_FUNC(button_clear_clicked),
8455 gtk_signal_connect_object(GTK_OBJECT(button_hide_show), "clicked",
8456 GTK_SIGNAL_FUNC(button_hide_show_clicked),
8459 gtk_widget_show(button_add);
8460 gtk_widget_show(button_clear);
8461 gtk_widget_show(button_hide_show);
8463 /* The interface is completely set up so we show the window and
8464 * enter the gtk_main loop.
8466 gtk_widget_show(window);
8474 <!-- ***************************************************************** -->
8475 <sect> Tree Widget <label id="sec_Tree_Widgets">
8476 <!-- ***************************************************************** -->
8478 The purpose of tree widgets is to display hierarchically-organized
8479 data. The Tree widget itself is a vertical container for widgets of
8480 type TreeItem. Tree itself is not terribly different from
8481 CList - both are derived directly from Container, and the
8482 Container methods work in the same way on Tree widgets as on
8483 CList widgets. The difference is that Tree widgets can be nested
8484 within other Tree widgets. We'll see how to do this shortly.
8486 The Tree widget has its own window, and defaults to a white
8487 background, as does CList. Also, most of the Tree methods work in
8488 the same way as the corresponding CList ones. However, Tree is
8489 not derived from CList, so you cannot use them interchangeably.
8492 <sect1> Creating a Tree
8494 A Tree is created in the usual way, using:
8497 GtkWidget *gtk_tree_new( void );
8500 Like the CList widget, a Tree will simply keep growing as more
8501 items are added to it, as well as when subtrees are expanded. For
8502 this reason, they are almost always packed into a
8503 ScrolledWindow. You might want to use gtk_widget_set_usize() on the
8504 scrolled window to ensure that it is big enough to see the tree's
8505 items, as the default size for ScrolledWindow is quite small.
8507 Now that you have a tree, you'll probably want to add some items to
8508 it. <ref id="sec_Tree_Item_Widget" name="The Tree Item Widget"> below
8509 explains the gory details of TreeItem. For now, it'll suffice to
8513 GtkWidget *gtk_tree_item_new_with_label( gchar *label );
8516 You can then add it to the tree using one of the following (see
8517 <ref id="sec_Tree_Functions" name="Functions and Macros">
8518 below for more options):
8521 void gtk_tree_append( GtkTree *tree,
8522 GtkWidget *tree_item );
8524 void gtk_tree_prepend( GtkTree *tree,
8525 GtkWidget *tree_item );
8528 Note that you must add items to a Tree one at a time - there is no
8529 equivalent to gtk_list_*_items().
8531 <!-- ----------------------------------------------------------------- -->
8532 <sect1> Adding a Subtree
8534 A subtree is created like any other Tree widget. A subtree is added
8535 to another tree beneath a tree item, using:
8538 void gtk_tree_item_set_subtree( GtkTreeItem *tree_item,
8539 GtkWidget *subtree );
8542 You do not need to call gtk_widget_show() on a subtree before or after
8543 adding it to a TreeItem. However, you <em>must</em> have added the
8544 TreeItem in question to a parent tree before calling
8545 gtk_tree_item_set_subtree(). This is because, technically, the parent
8546 of the subtree is <em>not</em> the GtkTreeItem which "owns" it, but
8547 rather the GtkTree which holds that GtkTreeItem.
8549 When you add a subtree to a TreeItem, a plus or minus sign appears
8550 beside it, which the user can click on to "expand" or "collapse" it,
8551 meaning, to show or hide its subtree. TreeItems are collapsed by
8552 default. Note that when you collapse a TreeItem, any selected
8553 items in its subtree remain selected, which may not be what the user
8556 <!-- ----------------------------------------------------------------- -->
8557 <sect1> Handling the Selection List
8559 As with CList, the Tree type has a <tt>selection</tt> field, and
8560 it is possible to control the behaviour of the tree (somewhat) by
8561 setting the selection type using:
8564 void gtk_tree_set_selection_mode( GtkTree *tree,
8565 GtkSelectionMode mode );
8568 The semantics associated with the various selection modes are
8569 described in the section on the CList widget. As with the CList
8570 widget, the "select_child", "unselect_child" (not really - see <ref
8571 id="sec_Tree_Signals" name="Signals"> below for an explanation),
8572 and "selection_changed" signals are emitted when list items are
8573 selected or unselected. However, in order to take advantage of these
8574 signals, you need to know <em>which</em> Tree widget they will be
8575 emitted by, and where to find the list of selected items.
8577 This is a source of potential confusion. The best way to explain this
8578 is that though all Tree widgets are created equal, some are more equal
8579 than others. All Tree widgets have their own X window, and can
8580 therefore receive events such as mouse clicks (if their TreeItems or
8581 their children don't catch them first!). However, to make
8582 <tt/GTK_SELECTION_SINGLE/ and <tt/GTK_SELECTION_BROWSE/ selection
8583 types behave in a sane manner, the list of selected items is specific
8584 to the topmost Tree widget in a hierarchy, known as the "root tree".
8586 Thus, accessing the <tt>selection</tt> field directly in an arbitrary
8587 Tree widget is not a good idea unless you <em>know</em> it's the root
8588 tree. Instead, use the <tt/GTK_TREE_SELECTION (Tree)/ macro, which
8589 gives the root tree's selection list as a GList pointer. Of course,
8590 this list can include items that are not in the subtree in question if
8591 the selection type is <tt/GTK_SELECTION_MULTIPLE/.
8593 Finally, the "select_child" (and "unselect_child", in theory) signals
8594 are emitted by all trees, but the "selection_changed" signal is only
8595 emitted by the root tree. Consequently, if you want to handle the
8596 "select_child" signal for a tree and all its subtrees, you will have
8597 to call gtk_signal_connect() for every subtree.
8599 <sect1> Tree Widget Internals
8601 The Tree's struct definition looks like this:
8606 GtkContainer container;
8610 GtkTree* root_tree; /* owner of selection list */
8611 GtkWidget* tree_owner;
8615 guint current_indent;
8616 guint selection_mode : 2;
8617 guint view_mode : 1;
8618 guint view_line : 1;
8622 The perils associated with accessing the <tt>selection</tt> field
8623 directly have already been mentioned. The other important fields of
8624 the struct can also be accessed with handy macros or class functions.
8625 <tt/GTK_TREE_IS_ROOT_TREE (Tree)/ returns a boolean value which
8626 indicates whether a tree is the root tree in a Tree hierarchy, while
8627 <tt/GTK_TREE_ROOT_TREE (Tree)/ returns the root tree, an object of
8628 type GtkTree (so, remember to cast it using <tt/GTK_WIDGET (Tree)/ if
8629 you want to use one of the gtk_widget_*() functions on it).
8631 Instead of directly accessing the children field of a Tree widget,
8632 it's probably best to cast it using >tt/GTK_CONTAINER (Tree)/, and
8633 pass it to the gtk_container_children() function. This creates a
8634 duplicate of the original list, so it's advisable to free it up using
8635 g_list_free() after you're done with it, or to iterate on it
8636 destructively, like this:
8639 children = gtk_container_children (GTK_CONTAINER (tree));
8641 do_something_nice (GTK_TREE_ITEM (children->data));
8642 children = g_list_remove_link (children, children);
8646 The <tt>tree_owner</tt> field is defined only in subtrees, where it
8647 points to the TreeItem widget which holds the tree in question.
8648 The <tt>level</tt> field indicates how deeply nested a particular tree
8649 is; root trees have level 0, and each successive level of subtrees has
8650 a level one greater than the parent level. This field is set only
8651 after a Tree widget is actually mapped (i.e. drawn on the screen).
8653 <sect2> Signals<label id="sec_Tree_Signals">
8656 void selection_changed( GtkTree *tree );
8659 This signal will be emitted whenever the <tt>selection</tt> field of a
8660 Tree has changed. This happens when a child of the Tree is
8661 selected or deselected.
8664 void select_child( GtkTree *tree,
8668 This signal is emitted when a child of the Tree is about to get
8669 selected. This happens on calls to gtk_tree_select_item(),
8670 gtk_tree_select_child(), on <em>all</em> button presses and calls to
8671 gtk_tree_item_toggle() and gtk_item_toggle(). It may sometimes be
8672 indirectly triggered on other occasions where children get added to or
8673 removed from the Tree.
8676 void unselect_child (GtkTree *tree,
8680 This signal is emitted when a child of the Tree is about to get
8681 deselected. As of GTK 1.0.4, this seems to only occur on calls to
8682 gtk_tree_unselect_item() or gtk_tree_unselect_child(), and perhaps on
8683 other occasions, but <em>not</em> when a button press deselects a
8684 child, nor on emission of the "toggle" signal by gtk_item_toggle().
8686 <sect2> Functions and Macros<label id="sec_Tree_Functions">
8689 guint gtk_tree_get_type( void );
8692 Returns the "GtkTree" type identifier.
8695 GtkWidget* gtk_tree_new( void );
8698 Create a new Tree object. The new widget is returned as a pointer to a
8699 GtkWidget object. NULL is returned on failure.
8702 void gtk_tree_append( GtkTree *tree,
8703 GtkWidget *tree_item );
8706 Append a tree item to a Tree.
8709 void gtk_tree_prepend( GtkTree *tree,
8710 GtkWidget *tree_item );
8713 Prepend a tree item to a Tree.
8716 void gtk_tree_insert( GtkTree *tree,
8717 GtkWidget *tree_item,
8721 Insert a tree item into a Tree at the position in the list
8722 specified by <tt>position.</tt>
8725 void gtk_tree_remove_items( GtkTree *tree,
8729 Remove a list of items (in the form of a GList *) from a Tree.
8730 Note that removing an item from a tree dereferences (and thus usually)
8731 destroys it <em>and</em> its subtree, if it has one, <em>and</em> all
8732 subtrees in that subtree. If you want to remove only one item, you
8733 can use gtk_container_remove().
8736 void gtk_tree_clear_items( GtkTree *tree,
8741 Remove the items from position <tt>start</tt> to position <tt>end</tt>
8742 from a Tree. The same warning about dereferencing applies here, as
8743 gtk_tree_clear_items() simply constructs a list and passes it to
8744 gtk_tree_remove_items().
8747 void gtk_tree_select_item( GtkTree *tree,
8751 Emits the "select_item" signal for the child at position
8752 <tt>item</tt>, thus selecting the child (unless you unselect it in a
8756 void gtk_tree_unselect_item( GtkTree *tree,
8760 Emits the "unselect_item" signal for the child at position
8761 <tt>item</tt>, thus unselecting the child.
8764 void gtk_tree_select_child( GtkTree *tree,
8765 GtkWidget *tree_item );
8768 Emits the "select_item" signal for the child <tt>tree_item</tt>, thus
8772 void gtk_tree_unselect_child( GtkTree *tree,
8773 GtkWidget *tree_item );
8776 Emits the "unselect_item" signal for the child <tt>tree_item</tt>,
8777 thus unselecting it.
8780 gint gtk_tree_child_position( GtkTree *tree,
8784 Returns the position in the tree of <tt>child</tt>, unless
8785 <tt>child</tt> is not in the tree, in which case it returns -1.
8788 void gtk_tree_set_selection_mode( GtkTree *tree,
8789 GtkSelectionMode mode );
8792 Sets the selection mode, which can be one of <tt/GTK_SELECTION_SINGLE/ (the
8793 default), <tt/GTK_SELECTION_BROWSE/, <tt/GTK_SELECTION_MULTIPLE/, or
8794 <tt/GTK_SELECTION_EXTENDED/. This is only defined for root trees, which
8795 makes sense, since the root tree "owns" the selection. Setting it for
8796 subtrees has no effect at all; the value is simply ignored.
8799 void gtk_tree_set_view_mode( GtkTree *tree,
8800 GtkTreeViewMode mode );
8803 Sets the "view mode", which can be either <tt/GTK_TREE_VIEW_LINE/ (the
8804 default) or <tt/GTK_TREE_VIEW_ITEM/. The view mode propagates from a
8805 tree to its subtrees, and can't be set exclusively to a subtree (this
8806 is not exactly true - see the example code comments).
8808 The term "view mode" is rather ambiguous - basically, it controls the
8809 way the highlight is drawn when one of a tree's children is selected.
8810 If it's <tt/GTK_TREE_VIEW_LINE/, the entire TreeItem widget is
8811 highlighted, while for <tt/GTK_TREE_VIEW_ITEM/, only the child widget
8812 (i.e., usually the label) is highlighted.
8815 void gtk_tree_set_view_lines( GtkTree *tree,
8819 Controls whether connecting lines between tree items are drawn.
8820 <tt>flag</tt> is either TRUE, in which case they are, or FALSE, in
8821 which case they aren't.
8824 GtkTree *GTK_TREE (gpointer obj);
8827 Cast a generic pointer to "GtkTree *".
8830 GtkTreeClass *GTK_TREE_CLASS (gpointer class);
8833 Cast a generic pointer to "GtkTreeClass *".
8836 gint GTK_IS_TREE (gpointer obj);
8839 Determine if a generic pointer refers to a "GtkTree" object.
8842 gint GTK_IS_ROOT_TREE (gpointer obj)
8845 Determine if a generic pointer refers to a "GtkTree" object
8846 <em>and</em> is a root tree. Though this will accept any pointer, the
8847 results of passing it a pointer that does not refer to a Tree are
8848 undefined and possibly harmful.
8851 GtkTree *GTK_TREE_ROOT_TREE (gpointer obj)
8854 Return the root tree of a pointer to a "GtkTree" object. The above
8858 GList *GTK_TREE_SELECTION( gpointer obj)
8861 Return the selection list of the root tree of a "GtkTree" object. The
8862 above warning applies here, too.
8864 <sect1> Tree Item Widget<label id="sec_Tree_Item_Widget">
8866 The TreeItem widget, like CListItem, is derived from Item,
8867 which in turn is derived from Bin. Therefore, the item itself is a
8868 generic container holding exactly one child widget, which can be of
8869 any type. The TreeItem widget has a number of extra fields, but
8870 the only one we need be concerned with is the <tt>subtree</tt> field.
8872 The definition for the TreeItem struct looks like this:
8880 GtkWidget *pixmaps_box;
8881 GtkWidget *plus_pix_widget, *minus_pix_widget;
8883 GList *pixmaps; /* pixmap node for this items color depth */
8889 The <tt>pixmaps_box</tt> field is an EventBox which catches clicks on
8890 the plus/minus symbol which controls expansion and collapsing. The
8891 <tt>pixmaps</tt> field points to an internal data structure. Since
8892 you can always obtain the subtree of a TreeItem in a (relatively)
8893 type-safe manner with the <tt/GTK_TREE_ITEM_SUBTREE (Item)/ macro,
8894 it's probably advisable never to touch the insides of a TreeItem
8895 unless you <em>really</em> know what you're doing.
8897 Since it is directly derived from an Item it can be treated as such by
8898 using the <tt/GTK_ITEM (TreeItem)/ macro. A TreeItem usually holds a
8899 label, so the convenience function gtk_list_item_new_with_label() is
8900 provided. The same effect can be achieved using code like the
8901 following, which is actually copied verbatim from
8902 gtk_tree_item_new_with_label():
8905 tree_item = gtk_tree_item_new ();
8906 label_widget = gtk_label_new (label);
8907 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
8909 gtk_container_add (GTK_CONTAINER (tree_item), label_widget);
8910 gtk_widget_show (label_widget);
8913 As one is not forced to add a Label to a TreeItem, you could
8914 also add an HBox or an Arrow, or even a Notebook (though your
8915 app will likely be quite unpopular in this case) to the TreeItem.
8917 If you remove all the items from a subtree, it will be destroyed and
8918 unparented, unless you reference it beforehand, and the TreeItem
8919 which owns it will be collapsed. So, if you want it to stick around,
8920 do something like the following:
8923 gtk_widget_ref (tree);
8924 owner = GTK_TREE(tree)->tree_owner;
8925 gtk_container_remove (GTK_CONTAINER(tree), item);
8926 if (tree->parent == NULL){
8927 gtk_tree_item_expand (GTK_TREE_ITEM(owner));
8928 gtk_tree_item_set_subtree (GTK_TREE_ITEM(owner), tree);
8931 gtk_widget_unref (tree);
8934 Finally, drag-n-drop <em>does</em> work with TreeItems. You just
8935 have to make sure that the TreeItem you want to make into a drag
8936 item or a drop site has not only been added to a Tree, but that
8937 each successive parent widget has a parent itself, all the way back to
8938 a toplevel or dialog window, when you call gtk_widget_dnd_drag_set()
8939 or gtk_widget_dnd_drop_set(). Otherwise, strange things will happen.
8943 TreeItem inherits the "select", "deselect", and "toggle" signals
8944 from Item. In addition, it adds two signals of its own, "expand"
8948 void select( GtkItem *tree_item );
8951 This signal is emitted when an item is about to be selected, either
8952 after it has been clicked on by the user, or when the program calls
8953 gtk_tree_item_select(), gtk_item_select(), or gtk_tree_select_child().
8956 void deselect( GtkItem *tree_item );
8959 This signal is emitted when an item is about to be unselected, either
8960 after it has been clicked on by the user, or when the program calls
8961 gtk_tree_item_deselect() or gtk_item_deselect(). In the case of
8962 TreeItems, it is also emitted by gtk_tree_unselect_child(), and
8963 sometimes gtk_tree_select_child().
8966 void toggle( GtkItem *tree_item );
8969 This signal is emitted when the program calls gtk_item_toggle(). The
8970 effect it has when emitted on a TreeItem is to call
8971 gtk_tree_select_child() (and never gtk_tree_unselect_child()) on the
8972 item's parent tree, if the item has a parent tree. If it doesn't,
8973 then the highlight is reversed on the item.
8976 void expand( GtkTreeItem *tree_item );
8979 This signal is emitted when the tree item's subtree is about to be
8980 expanded, that is, when the user clicks on the plus sign next to the
8981 item, or when the program calls gtk_tree_item_expand().
8984 void collapse( GtkTreeItem *tree_item );
8987 This signal is emitted when the tree item's subtree is about to be
8988 collapsed, that is, when the user clicks on the minus sign next to the
8989 item, or when the program calls gtk_tree_item_collapse().
8991 <sect2> Functions and Macros
8994 guint gtk_tree_item_get_type( void );
8997 Returns the "GtkTreeItem" type identifier.
9000 GtkWidget* gtk_tree_item_new( void );
9003 Create a new TreeItem object. The new widget is returned as a
9004 pointer to a GtkWidget object. NULL is returned on failure.
9007 GtkWidget* gtk_tree_item_new_with_label (gchar *label);
9010 Create a new TreeItem object, having a single GtkLabel as the sole
9011 child. The new widget is returned as a pointer to a GtkWidget
9012 object. NULL is returned on failure.
9015 void gtk_tree_item_select( GtkTreeItem *tree_item );
9018 This function is basically a wrapper around a call to
9019 <tt>gtk_item_select (GTK_ITEM (tree_item))</tt> which will emit the
9023 void gtk_tree_item_deselect( GtkTreeItem *tree_item );
9026 This function is basically a wrapper around a call to
9027 gtk_item_deselect (GTK_ITEM (tree_item)) which will emit the deselect
9031 void gtk_tree_item_set_subtree( GtkTreeItem *tree_item,
9032 GtkWidget *subtree );
9035 This function adds a subtree to tree_item, showing it if tree_item is
9036 expanded, or hiding it if tree_item is collapsed. Again, remember that
9037 the tree_item must have already been added to a tree for this to work.
9040 void gtk_tree_item_remove_subtree( GtkTreeItem *tree_item );
9043 This removes all of tree_item's subtree's children (thus unreferencing
9044 and destroying it, any of its children's subtrees, and so on...), then
9045 removes the subtree itself, and hides the plus/minus sign.
9048 void gtk_tree_item_expand( GtkTreeItem *tree_item );
9051 This emits the "expand" signal on tree_item, which expands it.
9054 void gtk_tree_item_collapse( GtkTreeItem *tree_item );
9057 This emits the "collapse" signal on tree_item, which collapses it.
9060 GtkTreeItem *GTK_TREE_ITEM (gpointer obj)
9063 Cast a generic pointer to "GtkTreeItem *".
9066 GtkTreeItemClass *GTK_TREE_ITEM_CLASS (gpointer obj)
9069 Cast a generic pointer to "GtkTreeItemClass".
9072 gint GTK_IS_TREE_ITEM (gpointer obj)
9075 Determine if a generic pointer refers to a "GtkTreeItem" object.
9078 GtkWidget GTK_TREE_ITEM_SUBTREE (gpointer obj)
9081 Returns a tree item's subtree (<tt/obj/ should point to a
9082 "GtkTreeItem" object).
9084 <sect1> Tree Example
9086 This is somewhat like the tree example in testgtk.c, but a lot less
9087 complete (although much better commented). It puts up a window with a
9088 tree, and connects all the signals for the relevant objects, so you
9089 can see when they are emitted.
9092 /* example-start tree tree.c */
9094 #include <gtk/gtk.h>
9096 /* for all the GtkItem:: and GtkTreeItem:: signals */
9097 static void cb_itemsignal (GtkWidget *item, gchar *signame)
9102 /* It's a Bin, so it has one child, which we know to be a
9103 label, so get that */
9104 label = GTK_LABEL (GTK_BIN (item)->child);
9105 /* Get the text of the label */
9106 gtk_label_get (label, &name);
9107 /* Get the level of the tree which the item is in */
9108 g_print ("%s called for item %s->%p, level %d\n", signame, name,
9109 item, GTK_TREE (item->parent)->level);
9112 /* Note that this is never called */
9113 static void cb_unselect_child (GtkWidget *root_tree, GtkWidget *child,
9116 g_print ("unselect_child called for root tree %p, subtree %p, child %p\n",
9117 root_tree, subtree, child);
9120 /* Note that this is called every time the user clicks on an item,
9121 whether it is already selected or not. */
9122 static void cb_select_child (GtkWidget *root_tree, GtkWidget *child,
9125 g_print ("select_child called for root tree %p, subtree %p, child %p\n",
9126 root_tree, subtree, child);
9129 static void cb_selection_changed (GtkWidget *tree)
9133 g_print ("selection_change called for tree %p\n", tree);
9134 g_print ("selected objects are:\n");
9136 i = GTK_TREE_SELECTION(tree);
9142 /* Get a GtkWidget pointer from the list node */
9143 item = GTK_WIDGET (i->data);
9144 label = GTK_LABEL (GTK_BIN (item)->child);
9145 gtk_label_get (label, &name);
9146 g_print ("\t%s on level %d\n", name, GTK_TREE
9147 (item->parent)->level);
9152 int main (int argc, char *argv[])
9154 GtkWidget *window, *scrolled_win, *tree;
9155 static gchar *itemnames[] = {"Foo", "Bar", "Baz", "Quux",
9159 gtk_init (&argc, &argv);
9161 /* a generic toplevel window */
9162 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9163 gtk_signal_connect (GTK_OBJECT(window), "delete_event",
9164 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
9165 gtk_container_set_border_width (GTK_CONTAINER(window), 5);
9167 /* A generic scrolled window */
9168 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
9169 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
9170 GTK_POLICY_AUTOMATIC,
9171 GTK_POLICY_AUTOMATIC);
9172 gtk_widget_set_usize (scrolled_win, 150, 200);
9173 gtk_container_add (GTK_CONTAINER(window), scrolled_win);
9174 gtk_widget_show (scrolled_win);
9176 /* Create the root tree */
9177 tree = gtk_tree_new();
9178 g_print ("root tree is %p\n", tree);
9179 /* connect all GtkTree:: signals */
9180 gtk_signal_connect (GTK_OBJECT(tree), "select_child",
9181 GTK_SIGNAL_FUNC(cb_select_child), tree);
9182 gtk_signal_connect (GTK_OBJECT(tree), "unselect_child",
9183 GTK_SIGNAL_FUNC(cb_unselect_child), tree);
9184 gtk_signal_connect (GTK_OBJECT(tree), "selection_changed",
9185 GTK_SIGNAL_FUNC(cb_selection_changed), tree);
9186 /* Add it to the scrolled window */
9187 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW(scrolled_win),
9189 /* Set the selection mode */
9190 gtk_tree_set_selection_mode (GTK_TREE(tree),
9191 GTK_SELECTION_MULTIPLE);
9193 gtk_widget_show (tree);
9195 for (i = 0; i < 5; i++){
9196 GtkWidget *subtree, *item;
9199 /* Create a tree item */
9200 item = gtk_tree_item_new_with_label (itemnames[i]);
9201 /* Connect all GtkItem:: and GtkTreeItem:: signals */
9202 gtk_signal_connect (GTK_OBJECT(item), "select",
9203 GTK_SIGNAL_FUNC(cb_itemsignal), "select");
9204 gtk_signal_connect (GTK_OBJECT(item), "deselect",
9205 GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
9206 gtk_signal_connect (GTK_OBJECT(item), "toggle",
9207 GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
9208 gtk_signal_connect (GTK_OBJECT(item), "expand",
9209 GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
9210 gtk_signal_connect (GTK_OBJECT(item), "collapse",
9211 GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
9212 /* Add it to the parent tree */
9213 gtk_tree_append (GTK_TREE(tree), item);
9214 /* Show it - this can be done at any time */
9215 gtk_widget_show (item);
9216 /* Create this item's subtree */
9217 subtree = gtk_tree_new();
9218 g_print ("-> item %s->%p, subtree %p\n", itemnames[i], item,
9221 /* This is still necessary if you want these signals to be called
9222 for the subtree's children. Note that selection_change will be
9223 signalled for the root tree regardless. */
9224 gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
9225 GTK_SIGNAL_FUNC(cb_select_child), subtree);
9226 gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
9227 GTK_SIGNAL_FUNC(cb_unselect_child), subtree);
9228 /* This has absolutely no effect, because it is completely ignored
9230 gtk_tree_set_selection_mode (GTK_TREE(subtree),
9231 GTK_SELECTION_SINGLE);
9232 /* Neither does this, but for a rather different reason - the
9233 view_mode and view_line values of a tree are propagated to
9234 subtrees when they are mapped. So, setting it later on would
9235 actually have a (somewhat unpredictable) effect */
9236 gtk_tree_set_view_mode (GTK_TREE(subtree), GTK_TREE_VIEW_ITEM);
9237 /* Set this item's subtree - note that you cannot do this until
9238 AFTER the item has been added to its parent tree! */
9239 gtk_tree_item_set_subtree (GTK_TREE_ITEM(item), subtree);
9241 for (j = 0; j < 5; j++){
9244 /* Create a subtree item, in much the same way */
9245 subitem = gtk_tree_item_new_with_label (itemnames[j]);
9246 /* Connect all GtkItem:: and GtkTreeItem:: signals */
9247 gtk_signal_connect (GTK_OBJECT(subitem), "select",
9248 GTK_SIGNAL_FUNC(cb_itemsignal), "select");
9249 gtk_signal_connect (GTK_OBJECT(subitem), "deselect",
9250 GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
9251 gtk_signal_connect (GTK_OBJECT(subitem), "toggle",
9252 GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
9253 gtk_signal_connect (GTK_OBJECT(subitem), "expand",
9254 GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
9255 gtk_signal_connect (GTK_OBJECT(subitem), "collapse",
9256 GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
9257 g_print ("-> -> item %s->%p\n", itemnames[j], subitem);
9258 /* Add it to its parent tree */
9259 gtk_tree_append (GTK_TREE(subtree), subitem);
9261 gtk_widget_show (subitem);
9265 /* Show the window and loop endlessly */
9266 gtk_widget_show (window);
9273 <!-- ***************************************************************** -->
9275 <!-- ***************************************************************** -->
9277 There are two ways to create menus: there's the easy way, and there's
9278 the hard way. Both have their uses, but you can usually use the
9279 Itemfactory (the easy way). The "hard" way is to create all the menus
9280 using the calls directly. The easy way is to use the gtk_item_factory
9281 calls. This is much simpler, but there are advantages and
9282 disadvantages to each approach.
9284 The Itemfactory is much easier to use, and to add new menus to,
9285 although writing a few wrapper functions to create menus using the
9286 manual method could go a long way towards usability. With the
9287 Itemfactory, it is not possible to add images or the character '/' to
9290 <!-- ----------------------------------------------------------------- -->
9291 <sect1>Manual Menu Creation
9293 In the true tradition of teaching, we'll show you the hard way
9296 There are three widgets that go into making a menubar and submenus:
9298 <item>a menu item, which is what the user wants to select, e.g.,
9300 <item>a menu, which acts as a container for the menu items, and
9301 <item>a menubar, which is a container for each of the individual
9305 This is slightly complicated by the fact that menu item widgets are
9306 used for two different things. They are both the widgets that are
9307 packed into the menu, and the widget that is packed into the menubar,
9308 which, when selected, activates the menu.
9310 Let's look at the functions that are used to create menus and
9311 menubars. This first function is used to create a new menubar.
9315 GtkWidget *gtk_menu_bar_new( void );
9319 This rather self explanatory function creates a new menubar. You use
9320 gtk_container_add to pack this into a window, or the box_pack
9321 functions to pack it into a box - the same as buttons.
9324 GtkWidget *gtk_menu_new( void );
9327 This function returns a pointer to a new menu; it is never actually
9328 shown (with gtk_widget_show), it is just a container for the menu
9329 items. I hope this will become more clear when you look at the
9332 The next two calls are used to create menu items that are packed into
9333 the menu (and menubar).
9336 GtkWidget *gtk_menu_item_new( void );
9342 GtkWidget *gtk_menu_item_new_with_label( const char *label );
9345 These calls are used to create the menu items that are to be
9346 displayed. Remember to differentiate between a "menu" as created with
9347 gtk_menu_new and a "menu item" as created by the gtk_menu_item_new
9348 functions. The menu item will be an actual button with an associated
9349 action, whereas a menu will be a container holding menu items.
9351 The gtk_menu_new_with_label and gtk_menu_new functions are just as
9352 you'd expect after reading about the buttons. One creates a new menu
9353 item with a label already packed into it, and the other just creates a
9356 Once you've created a menu item you have to put it into a menu. This
9357 is done using the function gtk_menu_append. In order to capture when
9358 the item is selected by the user, we need to connect to the
9359 <tt/activate/ signal in the usual way. So, if we wanted to create a
9360 standard <tt/File/ menu, with the options <tt/Open/, <tt/Save/, and
9361 <tt/Quit/, the code would look something like:
9364 file_menu = gtk_menu_new (); /* Don't need to show menus */
9366 /* Create the menu items */
9367 open_item = gtk_menu_item_new_with_label ("Open");
9368 save_item = gtk_menu_item_new_with_label ("Save");
9369 quit_item = gtk_menu_item_new_with_label ("Quit");
9371 /* Add them to the menu */
9372 gtk_menu_append (GTK_MENU (file_menu), open_item);
9373 gtk_menu_append (GTK_MENU (file_menu), save_item);
9374 gtk_menu_append (GTK_MENU (file_menu), quit_item);
9376 /* Attach the callback functions to the activate signal */
9377 gtk_signal_connect_object (GTK_OBJECT (open_items), "activate",
9378 GTK_SIGNAL_FUNC (menuitem_response),
9379 (gpointer) "file.open");
9380 gtk_signal_connect_object (GTK_OBJECT (save_items), "activate",
9381 GTK_SIGNAL_FUNC (menuitem_response),
9382 (gpointer) "file.save");
9384 /* We can attach the Quit menu item to our exit function */
9385 gtk_signal_connect_object (GTK_OBJECT (quit_items), "activate",
9386 GTK_SIGNAL_FUNC (destroy),
9387 (gpointer) "file.quit");
9389 /* We do need to show menu items */
9390 gtk_widget_show (open_item);
9391 gtk_widget_show (save_item);
9392 gtk_widget_show (quit_item);
9395 At this point we have our menu. Now we need to create a menubar and a
9396 menu item for the <tt/File/ entry, to which we add our menu. The code
9400 menu_bar = gtk_menu_bar_new ();
9401 gtk_container_add (GTK_CONTAINER (window), menu_bar);
9402 gtk_widget_show (menu_bar);
9404 file_item = gtk_menu_item_new_with_label ("File");
9405 gtk_widget_show (file_item);
9408 Now we need to associate the menu with <tt/file_item/. This is done
9412 void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
9413 GtkWidget *submenu );
9416 So, our example would continue with
9419 gtk_menu_item_set_submenu (GTK_MENU_ITEM (file_item), file_menu);
9422 All that is left to do is to add the menu to the menubar, which is
9423 accomplished using the function
9426 void gtk_menu_bar_append( GtkMenuBar *menu_bar,
9427 GtkWidget *menu_item );
9430 which in our case looks like this:
9433 gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), file_item);
9436 If we wanted the menu right justified on the menubar, such as help
9437 menus often are, we can use the following function (again on
9438 <tt/file_item/ in the current example) before attaching it to the
9442 void gtk_menu_item_right_justify( GtkMenuItem *menu_item );
9445 Here is a summary of the steps needed to create a menu bar with menus
9449 <item> Create a new menu using gtk_menu_new()
9450 <item> Use multiple calls to gtk_menu_item_new() for each item you
9451 wish to have on your menu. And use gtk_menu_append() to put each of
9452 these new items on to the menu.
9453 <item> Create a menu item using gtk_menu_item_new(). This will be the
9454 root of the menu, the text appearing here will be on the menubar
9456 <item>Use gtk_menu_item_set_submenu() to attach the menu to the root
9457 menu item (the one created in the above step).
9458 <item> Create a new menubar using gtk_menu_bar_new. This step only
9459 needs to be done once when creating a series of menus on one menu bar.
9460 <item> Use gtk_menu_bar_append() to put the root menu onto the menubar.
9463 Creating a popup menu is nearly the same. The difference is that the
9464 menu is not posted "automatically" by a menubar, but explicitly by
9465 calling the function gtk_menu_popup() from a button-press event, for
9466 example. Take these steps:
9469 <item>Create an event handling function. It needs to have the
9472 static gint handler (GtkWidget *widget,
9475 and it will use the event to find out where to pop up the menu.
9476 <item>In the event handler, if the event is a mouse button press,
9477 treat <tt>event</tt> as a button event (which it is) and use it as
9478 shown in the sample code to pass information to gtk_menu_popup().
9479 <item>Bind that event handler to a widget with
9481 gtk_signal_connect_object (GTK_OBJECT (widget), "event",
9482 GTK_SIGNAL_FUNC (handler),
9485 where <tt>widget</tt> is the widget you are binding to,
9486 <tt>handler</tt> is the handling function, and <tt>menu</tt> is a menu
9487 created with gtk_menu_new(). This can be a menu which is also posted
9488 by a menu bar, as shown in the sample code.
9491 <!-- ----------------------------------------------------------------- -->
9492 <sect1>Manual Menu Example
9494 That should about do it. Let's take a look at an example to help clarify.
9497 /* example-start menu menu.c */
9499 #include <gtk/gtk.h>
9501 static gint button_press (GtkWidget *, GdkEvent *);
9502 static void menuitem_response (gchar *);
9510 GtkWidget *menu_bar;
9511 GtkWidget *root_menu;
9512 GtkWidget *menu_items;
9518 gtk_init (&argc, &argv);
9520 /* create a new window */
9521 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9522 gtk_widget_set_usize (GTK_WIDGET (window), 200, 100);
9523 gtk_window_set_title (GTK_WINDOW (window), "GTK Menu Test");
9524 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
9525 (GtkSignalFunc) gtk_main_quit, NULL);
9527 /* Init the menu-widget, and remember -- never
9528 * gtk_show_widget() the menu widget!!
9529 * This is the menu that holds the menu items, the one that
9530 * will pop up when you click on the "Root Menu" in the app */
9531 menu = gtk_menu_new ();
9533 /* Next we make a little loop that makes three menu-entries for "test-menu".
9534 * Notice the call to gtk_menu_append. Here we are adding a list of
9535 * menu items to our menu. Normally, we'd also catch the "clicked"
9536 * signal on each of the menu items and setup a callback for it,
9537 * but it's omitted here to save space. */
9539 for (i = 0; i < 3; i++)
9541 /* Copy the names to the buf. */
9542 sprintf (buf, "Test-undermenu - %d", i);
9544 /* Create a new menu-item with a name... */
9545 menu_items = gtk_menu_item_new_with_label (buf);
9547 /* ...and add it to the menu. */
9548 gtk_menu_append (GTK_MENU (menu), menu_items);
9550 /* Do something interesting when the menuitem is selected */
9551 gtk_signal_connect_object (GTK_OBJECT (menu_items), "activate",
9552 GTK_SIGNAL_FUNC (menuitem_response), (gpointer) g_strdup (buf));
9554 /* Show the widget */
9555 gtk_widget_show (menu_items);
9558 /* This is the root menu, and will be the label
9559 * displayed on the menu bar. There won't be a signal handler attached,
9560 * as it only pops up the rest of the menu when pressed. */
9561 root_menu = gtk_menu_item_new_with_label ("Root Menu");
9563 gtk_widget_show (root_menu);
9565 /* Now we specify that we want our newly created "menu" to be the menu
9566 * for the "root menu" */
9567 gtk_menu_item_set_submenu (GTK_MENU_ITEM (root_menu), menu);
9569 /* A vbox to put a menu and a button in: */
9570 vbox = gtk_vbox_new (FALSE, 0);
9571 gtk_container_add (GTK_CONTAINER (window), vbox);
9572 gtk_widget_show (vbox);
9574 /* Create a menu-bar to hold the menus and add it to our main window */
9575 menu_bar = gtk_menu_bar_new ();
9576 gtk_box_pack_start (GTK_BOX (vbox), menu_bar, FALSE, FALSE, 2);
9577 gtk_widget_show (menu_bar);
9579 /* Create a button to which to attach menu as a popup */
9580 button = gtk_button_new_with_label ("press me");
9581 gtk_signal_connect_object (GTK_OBJECT (button), "event",
9582 GTK_SIGNAL_FUNC (button_press), GTK_OBJECT (menu));
9583 gtk_box_pack_end (GTK_BOX (vbox), button, TRUE, TRUE, 2);
9584 gtk_widget_show (button);
9586 /* And finally we append the menu-item to the menu-bar -- this is the
9587 * "root" menu-item I have been raving about =) */
9588 gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), root_menu);
9590 /* always display the window as the last step so it all splashes on
9591 * the screen at once. */
9592 gtk_widget_show (window);
9599 /* Respond to a button-press by posting a menu passed in as widget.
9601 * Note that the "widget" argument is the menu being posted, NOT
9602 * the button that was pressed.
9605 static gint button_press (GtkWidget *widget, GdkEvent *event)
9608 if (event->type == GDK_BUTTON_PRESS) {
9609 GdkEventButton *bevent = (GdkEventButton *) event;
9610 gtk_menu_popup (GTK_MENU (widget), NULL, NULL, NULL, NULL,
9611 bevent->button, bevent->time);
9612 /* Tell calling code that we have handled this event; the buck
9617 /* Tell calling code that we have not handled this event; pass it on. */
9622 /* Print a string when a menu item is selected */
9624 static void menuitem_response (gchar *string)
9626 printf ("%s\n", string);
9631 You may also set a menu item to be insensitive and, using an accelerator
9632 table, bind keys to menu functions.
9634 <!-- ----------------------------------------------------------------- -->
9635 <sect1>Using ItemFactory
9637 Now that we've shown you the hard way, here's how you do it using the
9638 gtk_item_factory calls.
9640 <!-- ----------------------------------------------------------------- -->
9641 <sect1>Item Factory Example
9643 Here is an example using the GTK item factory.
9646 /* example-start menu itemfactory.c */
9648 #include <gtk/gtk.h>
9649 #include <strings.h>
9651 /* Obligatory basic callback */
9652 static void print_hello( GtkWidget *w,
9655 g_message ("Hello, World!\n");
9658 /* This is the GtkItemFactoryEntry structure used to generate new menus.
9659 Item 1: The menu path. The letter after the underscore indicates an
9660 accelerator key once the menu is open.
9661 Item 2: The accelerator key for the entry
9662 Item 3: The callback function.
9663 Item 4: The callback action. This changes the parameters with
9664 which the function is called. The default is 0.
9665 Item 5: The item type, used to define what kind of an item it is.
9666 Here are the possible values:
9670 "<Title>" -> create a title item
9671 "<Item>" -> create a simple item
9672 "<CheckItem>" -> create a check item
9673 "<ToggleItem>" -> create a toggle item
9674 "<RadioItem>" -> create a radio item
9675 <path> -> path of a radio item to link against
9676 "<Separator>" -> create a separator
9677 "<Branch>" -> create an item to hold sub items (optional)
9678 "<LastBranch>" -> create a right justified branch
9681 static GtkItemFactoryEntry menu_items[] = {
9682 { "/_File", NULL, NULL, 0, "<Branch>" },
9683 { "/File/_New", "<control>N", print_hello, 0, NULL },
9684 { "/File/_Open", "<control>O", print_hello, 0, NULL },
9685 { "/File/_Save", "<control>S", print_hello, 0, NULL },
9686 { "/File/Save _As", NULL, NULL, 0, NULL },
9687 { "/File/sep1", NULL, NULL, 0, "<Separator>" },
9688 { "/File/Quit", "<control>Q", gtk_main_quit, 0, NULL },
9689 { "/_Options", NULL, NULL, 0, "<Branch>" },
9690 { "/Options/Test", NULL, NULL, 0, NULL },
9691 { "/_Help", NULL, NULL, 0, "<LastBranch>" },
9692 { "/_Help/About", NULL, NULL, 0, NULL },
9696 void get_main_menu( GtkWidget *window,
9697 GtkWidget **menubar )
9699 GtkItemFactory *item_factory;
9700 GtkAccelGroup *accel_group;
9701 gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
9703 accel_group = gtk_accel_group_new ();
9705 /* This function initializes the item factory.
9706 Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
9707 or GTK_TYPE_OPTION_MENU.
9708 Param 2: The path of the menu.
9709 Param 3: A pointer to a gtk_accel_group. The item factory sets up
9710 the accelerator table while generating menus.
9713 item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>",
9716 /* This function generates the menu items. Pass the item factory,
9717 the number of items in the array, the array itself, and any
9718 callback data for the the menu items. */
9719 gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
9721 /* Attach the new accelerator group to the window. */
9722 gtk_accel_group_attach (accel_group, GTK_OBJECT (window));
9725 /* Finally, return the actual menu bar created by the item factory. */
9726 *menubar = gtk_item_factory_get_widget (item_factory, "<main>");
9733 GtkWidget *main_vbox;
9736 gtk_init (&argc, &argv);
9738 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9739 gtk_signal_connect (GTK_OBJECT (window), "destroy",
9740 GTK_SIGNAL_FUNC (gtk_main_quit),
9742 gtk_window_set_title (GTK_WINDOW(window), "Item Factory");
9743 gtk_widget_set_usize (GTK_WIDGET(window), 300, 200);
9745 main_vbox = gtk_vbox_new (FALSE, 1);
9746 gtk_container_border_width (GTK_CONTAINER (main_vbox), 1);
9747 gtk_container_add (GTK_CONTAINER (window), main_vbox);
9748 gtk_widget_show (main_vbox);
9750 get_main_menu (window, &menubar);
9751 gtk_box_pack_start (GTK_BOX (main_vbox), menubar, FALSE, TRUE, 0);
9752 gtk_widget_show (menubar);
9754 gtk_widget_show (window);
9763 For now, there's only this example. An explanation and lots 'o' comments
9766 <!-- ***************************************************************** -->
9768 <!-- ***************************************************************** -->
9770 The Text widget allows multiple lines of text to be displayed and
9771 edited. It supports both multi-colored and multi-font text, allowing
9772 them to be mixed in any way we wish. It also has a wide set of key
9773 based text editing commands, which are compatible with Emacs.
9775 The text widget supports full cut-and-paste facilities, including the
9776 use of double- and triple-click to select a word and a whole line,
9779 <!-- ----------------------------------------------------------------- -->
9780 <sect1>Creating and Configuring a Text box
9782 There is only one function for creating a new Text widget.
9785 GtkWidget *gtk_text_new( GtkAdjustment *hadj,
9786 GtkAdjustment *vadj );
9789 The arguments allow us to give the Text widget pointers to Adjustments
9790 that can be used to track the viewing position of the widget. Passing
9791 NULL values to either or both of these arguments will cause the
9792 gtk_text_new function to create its own.
9795 void gtk_text_set_adjustments( GtkText *text,
9796 GtkAdjustment *hadj,
9797 GtkAdjustment *vadj );
9800 The above function allows the horizontal and vertical adjustments of a
9801 text widget to be changed at any time.
9803 The text widget will not automatically create its own scrollbars when
9804 the amount of text to be displayed is too long for the display
9805 window. We therefore have to create and add them to the display layout
9809 vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
9810 gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, FALSE, 0);
9811 gtk_widget_show (vscrollbar);
9814 The above code snippet creates a new vertical scrollbar, and attaches
9815 it to the vertical adjustment of the text widget, <tt/text/. It then
9816 packs it into a box in the normal way.
9818 Note, currently the Text widget does not support horizontal
9821 There are two main ways in which a Text widget can be used: to allow
9822 the user to edit a body of text, or to allow us to display multiple
9823 lines of text to the user. In order for us to switch between these
9824 modes of operation, the text widget has the following function:
9827 void gtk_text_set_editable( GtkText *text,
9831 The <tt/editable/ argument is a TRUE or FALSE value that specifies
9832 whether the user is permitted to edit the contents of the Text
9833 widget. When the text widget is editable, it will display a cursor at
9834 the current insertion point.
9836 You are not, however, restricted to just using the text widget in
9837 these two modes. You can toggle the editable state of the text widget
9838 at any time, and can insert text at any time.
9840 The text widget wraps lines of text that are too long to fit onto a
9841 single line of the display window. Its default behaviour is to break
9842 words across line breaks. This can be changed using the next function:
9845 void gtk_text_set_word_wrap( GtkText *text,
9849 Using this function allows us to specify that the text widget should
9850 wrap long lines on word boundaries. The <tt/word_wrap/ argument is a
9851 TRUE or FALSE value.
9853 <!-- ----------------------------------------------------------------- -->
9854 <sect1>Text Manipulation
9856 The current insertion point of a Text widget can be set using
9858 void gtk_text_set_point( GtkText *text,
9862 where <tt/index/ is the position to set the insertion point.
9864 Analogous to this is the function for getting the current insertion
9868 guint gtk_text_get_point( GtkText *text );
9871 A function that is useful in combination with the above two functions
9875 guint gtk_text_get_length( GtkText *text );
9878 which returns the current length of the Text widget. The length is the
9879 number of characters that are within the text block of the widget,
9880 including characters such as newline, which marks the end of
9883 In order to insert text at the current insertion point of a Text
9884 widget, the function gtk_text_insert is used, which also allows us to
9885 specify background and foreground colors and a font for the text.
9888 void gtk_text_insert( GtkText *text,
9896 Passing a value of <tt/NULL/ in as the value for the foreground color,
9897 background color or font will result in the values set within the
9898 widget style to be used. Using a value of <tt/-1/ for the length
9899 parameter will result in the whole of the text string given being
9902 The text widget is one of the few within GTK that redraws itself
9903 dynamically, outside of the gtk_main function. This means that all
9904 changes to the contents of the text widget take effect
9905 immediately. This may be undesirable when performing multiple changes
9906 to the text widget. In order to allow us to perform multiple updates
9907 to the text widget without it continuously redrawing, we can freeze
9908 the widget, which temporarily stops it from automatically redrawing
9909 itself every time it is changed. We can then thaw the widget after our
9910 updates are complete.
9912 The following two functions perform this freeze and thaw action:
9915 void gtk_text_freeze( GtkText *text );
9917 void gtk_text_thaw( GtkText *text );
9920 Text is deleted from the text widget relative to the current insertion
9921 point by the following two functions. The return value is a TRUE or
9922 FALSE indicator of whether the operation was successful.
9925 gint gtk_text_backward_delete( GtkText *text,
9928 gint gtk_text_forward_delete ( GtkText *text,
9932 If you want to retrieve the contents of the text widget, then the
9933 macro <tt/GTK_TEXT_INDEX(t, index)/ allows you to retrieve the
9934 character at position <tt/index/ within the text widget <tt/t/.
9936 To retrieve larger blocks of text, we can use the function
9939 gchar *gtk_editable_get_chars( GtkEditable *editable,
9944 This is a function of the parent class of the text widget. A value of
9945 -1 as <tt/end_pos/ signifies the end of the text. The index of the
9948 The function allocates a new chunk of memory for the text block, so
9949 don't forget to free it with a call to g_free when you have finished
9952 <!-- ----------------------------------------------------------------- -->
9953 <sect1>Keyboard Shortcuts
9955 The text widget has a number of pre-installed keyboard shortcuts for
9956 common editing, motion and selection functions. These are accessed
9957 using Control and Alt key combinations.
9959 In addition to these, holding down the Control key whilst using cursor
9960 key movement will move the cursor by words rather than
9961 characters. Holding down Shift whilst using cursor movement will
9962 extend the selection.
9964 <sect2>Motion Shortcuts
9967 <item> Ctrl-A Beginning of line
9968 <item> Ctrl-E End of line
9969 <item> Ctrl-N Next Line
9970 <item> Ctrl-P Previous Line
9971 <item> Ctrl-B Backward one character
9972 <item> Ctrl-F Forward one character
9973 <item> Alt-B Backward one word
9974 <item> Alt-F Forward one word
9977 <sect2>Editing Shortcuts
9980 <item> Ctrl-H Delete Backward Character (Backspace)
9981 <item> Ctrl-D Delete Forward Character (Delete)
9982 <item> Ctrl-W Delete Backward Word
9983 <item> Alt-D Delete Forward Word
9984 <item> Ctrl-K Delete to end of line
9985 <item> Ctrl-U Delete line
9988 <sect2>Selection Shortcuts
9991 <item> Ctrl-X Cut to clipboard
9992 <item> Ctrl-C Copy to clipboard
9993 <item> Ctrl-V Paste from clipboard
9996 <!-- ----------------------------------------------------------------- -->
9997 <sect1>A GtkText Example
10000 /* example-start text text.c */
10005 #include <gtk/gtk.h>
10007 void text_toggle_editable (GtkWidget *checkbutton,
10010 gtk_text_set_editable(GTK_TEXT(text),
10011 GTK_TOGGLE_BUTTON(checkbutton)->active);
10014 void text_toggle_word_wrap (GtkWidget *checkbutton,
10017 gtk_text_set_word_wrap(GTK_TEXT(text),
10018 GTK_TOGGLE_BUTTON(checkbutton)->active);
10021 void close_application( GtkWidget *widget, gpointer data )
10026 int main (int argc, char *argv[])
10034 GtkWidget *separator;
10036 GtkWidget *vscrollbar;
10040 GdkFont *fixed_font;
10044 gtk_init (&argc, &argv);
10046 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
10047 gtk_widget_set_usize (window, 600, 500);
10048 gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, FALSE);
10049 gtk_signal_connect (GTK_OBJECT (window), "destroy",
10050 GTK_SIGNAL_FUNC(close_application),
10052 gtk_window_set_title (GTK_WINDOW (window), "Text Widget Example");
10053 gtk_container_set_border_width (GTK_CONTAINER (window), 0);
10056 box1 = gtk_vbox_new (FALSE, 0);
10057 gtk_container_add (GTK_CONTAINER (window), box1);
10058 gtk_widget_show (box1);
10061 box2 = gtk_vbox_new (FALSE, 10);
10062 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
10063 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
10064 gtk_widget_show (box2);
10067 table = gtk_table_new (2, 2, FALSE);
10068 gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
10069 gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
10070 gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
10071 gtk_widget_show (table);
10073 /* Create the GtkText widget */
10074 text = gtk_text_new (NULL, NULL);
10075 gtk_text_set_editable (GTK_TEXT (text), TRUE);
10076 gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
10077 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
10078 GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
10079 gtk_widget_show (text);
10081 /* Add a vertical scrollbar to the GtkText widget */
10082 vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
10083 gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
10084 GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
10085 gtk_widget_show (vscrollbar);
10087 /* Get the system color map and allocate the color red */
10088 cmap = gdk_colormap_get_system();
10089 color.red = 0xffff;
10092 if (!gdk_color_alloc(cmap, &color)) {
10093 g_error("couldn't allocate color");
10096 /* Load a fixed font */
10097 fixed_font = gdk_font_load ("-misc-fixed-medium-r-*-*-*-140-*-*-*-*-*-*");
10099 /* Realizing a widget creates a window for it,
10100 * ready for us to insert some text */
10101 gtk_widget_realize (text);
10103 /* Freeze the text widget, ready for multiple updates */
10104 gtk_text_freeze (GTK_TEXT (text));
10106 /* Insert some colored text */
10107 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
10109 gtk_text_insert (GTK_TEXT (text), NULL, &color, NULL,
10111 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
10112 "text and different ", -1);
10113 gtk_text_insert (GTK_TEXT (text), fixed_font, &text->style->black, NULL,
10116 /* Load the file text.c into the text window */
10118 infile = fopen("text.c", "r");
10126 nchars = fread(buffer, 1, 1024, infile);
10127 gtk_text_insert (GTK_TEXT (text), fixed_font, NULL,
10128 NULL, buffer, nchars);
10137 /* Thaw the text widget, allowing the updates to become visible */
10138 gtk_text_thaw (GTK_TEXT (text));
10140 hbox = gtk_hbutton_box_new ();
10141 gtk_box_pack_start (GTK_BOX (box2), hbox, FALSE, FALSE, 0);
10142 gtk_widget_show (hbox);
10144 check = gtk_check_button_new_with_label("Editable");
10145 gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, FALSE, 0);
10146 gtk_signal_connect (GTK_OBJECT(check), "toggled",
10147 GTK_SIGNAL_FUNC(text_toggle_editable), text);
10148 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);
10149 gtk_widget_show (check);
10150 check = gtk_check_button_new_with_label("Wrap Words");
10151 gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, TRUE, 0);
10152 gtk_signal_connect (GTK_OBJECT(check), "toggled",
10153 GTK_SIGNAL_FUNC(text_toggle_word_wrap), text);
10154 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), FALSE);
10155 gtk_widget_show (check);
10157 separator = gtk_hseparator_new ();
10158 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
10159 gtk_widget_show (separator);
10161 box2 = gtk_vbox_new (FALSE, 10);
10162 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
10163 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
10164 gtk_widget_show (box2);
10166 button = gtk_button_new_with_label ("close");
10167 gtk_signal_connect (GTK_OBJECT (button), "clicked",
10168 GTK_SIGNAL_FUNC(close_application),
10170 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
10171 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
10172 gtk_widget_grab_default (button);
10173 gtk_widget_show (button);
10175 gtk_widget_show (window);
10185 <!-- ***************************************************************** -->
10186 <sect> Undocumented Widgets
10187 <!-- ***************************************************************** -->
10189 These all require authors! :) Please consider contributing to our
10192 If you must use one of these widgets that are undocumented, I strongly
10193 suggest you take a look at their respective header files in the GTK
10194 distribution. GTK's function names are very descriptive. Once you
10195 have an understanding of how things work, it's not difficult to figure
10196 out how to use a widget simply by looking at its function
10197 declarations. This, along with a few examples from others' code, and
10198 it should be no problem.
10200 When you do come to understand all the functions of a new undocumented
10201 widget, please consider writing a tutorial on it so others may benefit
10204 <!-- ----------------------------------------------------------------- -->
10207 <!-- ----------------------------------------------------------------- -->
10210 <!-- ----------------------------------------------------------------- -->
10213 <!-- ----------------------------------------------------------------- -->
10214 <sect1> Drawing Area
10216 <!-- ----------------------------------------------------------------- -->
10217 <sect1> Font Selection Dialog
10219 <!-- ----------------------------------------------------------------- -->
10220 <sect1> Gamma Curve
10222 <!-- ----------------------------------------------------------------- -->
10225 <!-- ----------------------------------------------------------------- -->
10228 <!-- ----------------------------------------------------------------- -->
10229 <sect1> Plugs and Sockets
10231 <!-- ----------------------------------------------------------------- -->
10237 (This may need to be rewritten to follow the style of the rest of the tutorial)
10241 Previews serve a number of purposes in GIMP/GTK. The most important one is
10242 this. High quality images may take up to tens of megabytes of memory - easily!
10243 Any operation on an image that big is bound to take a long time. If it takes
10244 you 5-10 trial-and-errors (i.e., 10-20 steps, since you have to revert after
10245 you make an error) to choose the desired modification, it make take you
10246 literally hours to make the right one - if you don't run out of memory
10247 first. People who have spent hours in color darkrooms know the feeling.
10248 Previews to the rescue!
10250 But the annoyance of the delay is not the only issue. Oftentimes it is
10251 helpful to compare the Before and After versions side-by-side or at least
10252 back-to-back. If you're working with big images and 10 second delays,
10253 obtaining the Before and After impressions is, to say the least, difficult.
10254 For 30M images (4"x6", 600dpi, 24 bit) the side-by-side comparison is right
10255 out for most people, while back-to-back is more like back-to-1001, 1002,
10256 ..., 1010-back! Previews to the rescue!
10258 But there's more. Previews allow for side-by-side pre-previews. In other
10259 words, you write a plug-in (e.g., the filterpack simulation) which would have
10260 a number of here's-what-it-would-look-like-if-you-were-to-do-this previews.
10261 An approach like this acts as a sort of a preview palette and is very
10262 effective for subtle changes. Let's go previews!
10264 There's more. For certain plug-ins real-time image-specific human
10265 intervention maybe necessary. In the SuperNova plug-in, for example, the
10266 user is asked to enter the coordinates of the center of the future
10267 supernova. The easiest way to do this, really, is to present the user with a
10268 preview and ask him to interactively select the spot. Let's go previews!
10270 Finally, a couple of misc uses. One can use previews even when not working
10271 with big images. For example, they are useful when rendering complicated
10272 patterns. (Just check out the venerable Diffraction plug-in + many other
10273 ones!) As another example, take a look at the colormap rotation plug-in
10274 (work in progress). You can also use previews for little logos inside you
10275 plug-ins and even for an image of yourself, The Author. Let's go previews!
10277 When Not to Use Previews
10279 Don't use previews for graphs, drawing, etc. GDK is much faster for that. Use
10280 previews only for rendered images!
10284 You can stick a preview into just about anything. In a vbox, an hbox, a
10285 table, a button, etc. But they look their best in tight frames around them.
10286 Previews by themselves do not have borders and look flat without them. (Of
10287 course, if the flat look is what you want...) Tight frames provide the
10292 Previews in many ways are like any other widgets in GTK (whatever that
10293 means) except they possess an additional feature: they need to be filled with
10294 some sort of an image! First, we will deal exclusively with the GTK aspect
10295 of previews and then we'll discuss how to fill them.
10297 GtkWidget *preview!
10301 /* Create a preview widget,
10302 set its size, an show it */
10303 GtkWidget *preview;
10304 preview=gtk_preview_new(GTK_PREVIEW_COLOR)
10306 GTK_PREVIEW_GRAYSCALE);*/
10307 gtk_preview_size (GTK_PREVIEW (preview), WIDTH, HEIGHT);
10308 gtk_widget_show(preview);
10309 my_preview_rendering_function(preview);
10311 Oh yeah, like I said, previews look good inside frames, so how about:
10313 GtkWidget *create_a_preview(int Width,
10317 GtkWidget *preview;
10320 frame = gtk_frame_new(NULL);
10321 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
10322 gtk_container_set_border_width (GTK_CONTAINER(frame),0);
10323 gtk_widget_show(frame);
10325 preview=gtk_preview_new (Colorfulness?GTK_PREVIEW_COLOR
10326 :GTK_PREVIEW_GRAYSCALE);
10327 gtk_preview_size (GTK_PREVIEW (preview), Width, Height);
10328 gtk_container_add(GTK_CONTAINER(frame),preview);
10329 gtk_widget_show(preview);
10331 my_preview_rendering_function(preview);
10335 That's my basic preview. This routine returns the "parent" frame so you can
10336 place it somewhere else in your interface. Of course, you can pass the
10337 parent frame to this routine as a parameter. In many situations, however,
10338 the contents of the preview are changed continually by your application. In
10339 this case you may want to pass a pointer to the preview to a
10340 "create_a_preview()" and thus have control of it later.
10342 One more important note that may one day save you a lot of time. Sometimes
10343 it is desirable to label you preview. For example, you may label the preview
10344 containing the original image as "Original" and the one containing the
10345 modified image as "Less Original". It might occur to you to pack the
10346 preview along with the appropriate label into a vbox. The unexpected caveat
10347 is that if the label is wider than the preview (which may happen for a
10348 variety of reasons unforseeable to you, from the dynamic decision on the
10349 size of the preview to the size of the font) the frame expands and no longer
10350 fits tightly over the preview. The same problem can probably arise in other
10351 situations as well.
10355 The solution is to place the preview and the label into a 2x1 table and by
10356 attaching them with the following parameters (this is one possible variations
10357 of course. The key is no GTK_FILL in the second attachment):
10359 gtk_table_attach(GTK_TABLE(table),label,0,1,0,1,
10361 GTK_EXPAND|GTK_FILL,
10363 gtk_table_attach(GTK_TABLE(table),frame,0,1,1,2,
10369 And here's the result:
10375 Making a preview clickable is achieved most easily by placing it in a
10376 button. It also adds a nice border around the preview and you may not even
10377 need to place it in a frame. See the Filter Pack Simulation plug-in for an
10380 This is pretty much it as far as GTK is concerned.
10382 Filling In a Preview
10384 In order to familiarize ourselves with the basics of filling in previews,
10385 let's create the following pattern (contrived by trial and error):
10390 my_preview_rendering_function(GtkWidget *preview)
10393 #define HALF (SIZE/2)
10395 guchar *row=(guchar *) malloc(3*SIZE); /* 3 bits per dot */
10396 gint i, j; /* Coordinates */
10397 double r, alpha, x, y;
10399 if (preview==NULL) return; /* I usually add this when I want */
10400 /* to avoid silly crashes. You */
10401 /* should probably make sure that */
10402 /* everything has been nicely */
10404 for (j=0; j < ABS(cos(2*alpha)) ) { /* Are we inside the shape? */
10405 /* glib.h contains ABS(x). */
10406 row[i*3+0] = sqrt(1-r)*255; /* Define Red */
10407 row[i*3+1] = 128; /* Define Green */
10408 row[i*3+2] = 224; /* Define Blue */
10409 } /* "+0" is for alignment! */
10411 row[i*3+0] = r*255;
10412 row[i*3+1] = ABS(sin((float)i/SIZE*2*PI))*255;
10413 row[i*3+2] = ABS(sin((float)j/SIZE*2*PI))*255;
10416 gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,j,SIZE);
10417 /* Insert "row" into "preview" starting at the point with */
10418 /* coordinates (0,j) first column, j_th row extending SIZE */
10419 /* pixels to the right */
10422 free(row); /* save some space */
10423 gtk_widget_draw(preview,NULL); /* what does this do? */
10424 gdk_flush(); /* or this? */
10427 Non-GIMP users can have probably seen enough to do a lot of things already.
10428 For the GIMP users I have a few pointers to add.
10432 It is probably wise to keep a reduced version of the image around with just
10433 enough pixels to fill the preview. This is done by selecting every n'th
10434 pixel where n is the ratio of the size of the image to the size of the
10435 preview. All further operations (including filling in the previews) are then
10436 performed on the reduced number of pixels only. The following is my
10437 implementation of reducing the image. (Keep in mind that I've had only basic
10440 (UNTESTED CODE ALERT!!!)
10452 SELECTION_IN_CONTEXT,
10456 ReducedImage *Reduce_The_Image(GDrawable *drawable,
10461 /* This function reduced the image down to the the selected preview size */
10462 /* The preview size is determine by LongerSize, i.e., the greater of the */
10463 /* two dimensions. Works for RGB images only! */
10464 gint RH, RW; /* Reduced height and reduced width */
10465 gint width, height; /* Width and Height of the area being reduced */
10466 gint bytes=drawable->bpp;
10467 ReducedImage *temp=(ReducedImage *)malloc(sizeof(ReducedImage));
10469 guchar *tempRGB, *src_row, *tempmask, *src_mask_row,R,G,B;
10470 gint i, j, whichcol, whichrow, x1, x2, y1, y2;
10471 GPixelRgn srcPR, srcMask;
10472 gint NoSelectionMade=TRUE; /* Assume that we're dealing with the entire */
10475 gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
10478 /* If there's a SELECTION, we got its bounds!)
10480 if (width != drawable->width && height != drawable->height)
10481 NoSelectionMade=FALSE;
10482 /* Become aware of whether the user has made an active selection */
10483 /* This will become important later, when creating a reduced mask. */
10485 /* If we want to preview the entire image, overrule the above! */
10486 /* Of course, if no selection has been made, this does nothing! */
10487 if (Selection==ENTIRE_IMAGE) {
10489 x2=drawable->width;
10491 y2=drawable->height;
10494 /* If we want to preview a selection with some surrounding area we */
10495 /* have to expand it a little bit. Consider it a bit of a riddle. */
10496 if (Selection==SELECTION_IN_CONTEXT) {
10497 x1=MAX(0, x1-width/2.0);
10498 x2=MIN(drawable->width, x2+width/2.0);
10499 y1=MAX(0, y1-height/2.0);
10500 y2=MIN(drawable->height, y2+height/2.0);
10503 /* How we can determine the width and the height of the area being */
10508 /* The lines below determine which dimension is to be the longer */
10509 /* side. The idea borrowed from the supernova plug-in. I suspect I */
10510 /* could've thought of it myself, but the truth must be told. */
10511 /* Plagiarism stinks! */
10512 if (width>height) {
10514 RH=(float) height * (float) LongerSize/ (float) width;
10518 RW=(float)width * (float) LongerSize/ (float) height;
10521 /* The entire image is stretched into a string! */
10522 tempRGB = (guchar *) malloc(RW*RH*bytes);
10523 tempmask = (guchar *) malloc(RW*RH);
10525 gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height,
10527 gimp_pixel_rgn_init (&srcMask, mask, x1, y1, width, height,
10530 /* Grab enough to save a row of image and a row of mask. */
10531 src_row = (guchar *) malloc (width*bytes);
10532 src_mask_row = (guchar *) malloc (width);
10534 for (i=0; i < RH; i++) {
10535 whichrow=(float)i*(float)height/(float)RH;
10536 gimp_pixel_rgn_get_row (&srcPR, src_row, x1, y1+whichrow, width);
10537 gimp_pixel_rgn_get_row (&srcMask, src_mask_row, x1, y1+whichrow, width);
10539 for (j=0; j < RW; j++) {
10540 whichcol=(float)j*(float)width/(float)RW;
10542 /* No selection made = each point is completely selected! */
10543 if (NoSelectionMade)
10544 tempmask[i*RW+j]=255;
10546 tempmask[i*RW+j]=src_mask_row[whichcol];
10548 /* Add the row to the one long string which now contains the image! */
10549 tempRGB[i*RW*bytes+j*bytes+0]=src_row[whichcol*bytes+0];
10550 tempRGB[i*RW*bytes+j*bytes+1]=src_row[whichcol*bytes+1];
10551 tempRGB[i*RW*bytes+j*bytes+2]=src_row[whichcol*bytes+2];
10553 /* Hold on to the alpha as well */
10555 tempRGB[i*RW*bytes+j*bytes+3]=src_row[whichcol*bytes+3];
10562 temp->mask=tempmask;
10566 The following is a preview function which used the same ReducedImage type!
10567 Note that it uses fakes transparency (if one is present by means of
10568 fake_transparency which is defined as follows:
10570 gint fake_transparency(gint i, gint j)
10572 if ( ((i%20)- 10) * ((j%20)- 10)>0 )
10578 Now here's the preview function:
10581 my_preview_render_function(GtkWidget *preview,
10585 gint Inten, bytes=drawable->bpp;
10588 gint RW=reduced->width;
10589 gint RH=reduced->height;
10590 guchar *row=malloc(bytes*RW);;
10593 for (i=0; i < RH; i++) {
10594 for (j=0; j < RW; j++) {
10596 row[j*3+0] = reduced->rgb[i*RW*bytes + j*bytes + 0];
10597 row[j*3+1] = reduced->rgb[i*RW*bytes + j*bytes + 1];
10598 row[j*3+2] = reduced->rgb[i*RW*bytes + j*bytes + 2];
10601 for (k=0; k<3; k++) {
10602 float transp=reduced->rgb[i*RW*bytes+j*bytes+3]/255.0;
10603 row[3*j+k]=transp*a[3*j+k]+(1-transp)*fake_transparency(i,j);
10606 gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,i,RW);
10610 gtk_widget_draw(preview,NULL);
10614 Applicable Routines
10616 guint gtk_preview_get_type (void);
10618 void gtk_preview_uninit (void);
10620 GtkWidget* gtk_preview_new (GtkPreviewType type);
10621 /* Described above */
10622 void gtk_preview_size (GtkPreview *preview,
10625 /* Allows you to resize an existing preview. */
10626 /* Apparently there's a bug in GTK which makes */
10627 /* this process messy. A way to clean up a mess */
10628 /* is to manually resize the window containing */
10629 /* the preview after resizing the preview. */
10631 void gtk_preview_put (GtkPreview *preview,
10642 void gtk_preview_put_row (GtkPreview *preview,
10650 void gtk_preview_draw_row (GtkPreview *preview,
10655 /* Described in the text */
10657 void gtk_preview_set_expand (GtkPreview *preview,
10661 /* No clue for any of the below but */
10662 /* should be standard for most widgets */
10663 void gtk_preview_set_gamma (double gamma);
10664 void gtk_preview_set_color_cube (guint nred_shades,
10665 guint ngreen_shades,
10666 guint nblue_shades,
10667 guint ngray_shades);
10668 void gtk_preview_set_install_cmap (gint install_cmap);
10669 void gtk_preview_set_reserved (gint nreserved);
10670 GdkVisual* gtk_preview_get_visual (void);
10671 GdkColormap* gtk_preview_get_cmap (void);
10672 GtkPreviewInfo* gtk_preview_get_info (void);
10680 <!-- ***************************************************************** -->
10681 <sect>Setting Widget Attributes<label id="sec_setting_widget_attributes">
10682 <!-- ***************************************************************** -->
10684 This describes the functions used to operate on widgets. These can be
10685 used to set style, padding, size, etc.
10687 (Maybe I should make a whole section on accelerators.)
10690 void gtk_widget_install_accelerator( GtkWidget *widget,
10691 GtkAcceleratorTable *table,
10692 gchar *signal_name,
10694 guint8 modifiers );
10696 void gtk_widget_remove_accelerator ( GtkWidget *widget,
10697 GtkAcceleratorTable *table,
10698 gchar *signal_name);
10700 void gtk_widget_activate( GtkWidget *widget );
10702 void gtk_widget_set_name( GtkWidget *widget,
10705 gchar *gtk_widget_get_name( GtkWidget *widget );
10707 void gtk_widget_set_sensitive( GtkWidget *widget,
10710 void gtk_widget_set_style( GtkWidget *widget,
10713 GtkStyle *gtk_widget_get_style( GtkWidget *widget );
10715 GtkStyle *gtk_widget_get_default_style( void );
10717 void gtk_widget_set_uposition( GtkWidget *widget,
10721 void gtk_widget_set_usize( GtkWidget *widget,
10725 void gtk_widget_grab_focus( GtkWidget *widget );
10727 void gtk_widget_show( GtkWidget *widget );
10729 void gtk_widget_hide( GtkWidget *widget );
10732 <!-- ***************************************************************** -->
10733 <sect>Timeouts, IO and Idle Functions<label id="sec_timeouts">
10734 <!-- ***************************************************************** -->
10736 <!-- ----------------------------------------------------------------- -->
10739 You may be wondering how you make GTK do useful work when in gtk_main.
10740 Well, you have several options. Using the following function you can
10741 create a timeout function that will be called every "interval"
10745 gint gtk_timeout_add( guint32 interval,
10746 GtkFunction function,
10750 The first argument is the number of milliseconds between calls to your
10751 function. The second argument is the function you wish to have called,
10752 and the third, the data passed to this callback function. The return
10753 value is an integer "tag" which may be used to stop the timeout by
10757 void gtk_timeout_remove( gint tag );
10760 You may also stop the timeout function by returning zero or FALSE from
10761 your callback function. Obviously this means if you want your function
10762 to continue to be called, it should return a non-zero value,
10765 The declaration of your callback should look something like this:
10768 gint timeout_callback( gpointer data );
10771 <!-- ----------------------------------------------------------------- -->
10772 <sect1>Monitoring IO
10774 A nifty feature of GDK (the library that underlies GTK), is the
10775 ability to have it check for data on a file descriptor for you (as
10776 returned by open(2) or socket(2)). This is especially useful for
10777 networking applications. The function:
10780 gint gdk_input_add( gint source,
10781 GdkInputCondition condition,
10782 GdkInputFunction function,
10786 Where the first argument is the file descriptor you wish to have
10787 watched, and the second specifies what you want GDK to look for. This
10791 <item><tt/GDK_INPUT_READ/ - Call your function when there is data
10792 ready for reading on your file descriptor.
10794 <item>><tt/GDK_INPUT_WRITE/ - Call your function when the file
10795 descriptor is ready for writing.
10798 As I'm sure you've figured out already, the third argument is the
10799 function you wish to have called when the above conditions are
10800 satisfied, and the fourth is the data to pass to this function.
10802 The return value is a tag that may be used to stop GDK from monitoring
10803 this file descriptor using the following function.
10806 void gdk_input_remove( gint tag );
10809 The callback function should be declared as:
10812 void input_callback( gpointer data,
10814 GdkInputCondition condition );
10817 Where <tt/source/ and <tt/condition/ are as specified above.
10819 <!-- ----------------------------------------------------------------- -->
10820 <sect1>Idle Functions
10822 <!-- TODO: Need to check on idle priorities - TRG -->
10823 What if you have a function which you want to be called when nothing
10824 else is happening ?
10827 gint gtk_idle_add( GtkFunction function,
10831 This causes GTK to call the specified function whenever nothing else
10835 void gtk_idle_remove( gint tag );
10838 I won't explain the meaning of the arguments as they follow very much
10839 like the ones above. The function pointed to by the first argument to
10840 gtk_idle_add will be called whenever the opportunity arises. As with
10841 the others, returning FALSE will stop the idle function from being
10844 <!-- ***************************************************************** -->
10845 <sect>Advanced Event and Signal Handling<label id="sec_Adv_Events_and_Signals">
10846 <!-- ***************************************************************** -->
10848 <!-- ----------------------------------------------------------------- -->
10849 <sect1>Signal Functions
10851 <!-- ----------------------------------------------------------------- -->
10852 <sect2>Connecting and Disconnecting Signal Handlers
10856 guint gtk_signal_connect( GtkObject *object,
10858 GtkSignalFunc func,
10859 gpointer func_data );
10861 guint gtk_signal_connect_after( GtkObject *object,
10863 GtkSignalFunc func,
10864 gpointer func_data );
10866 guint gtk_signal_connect_object( GtkObject *object,
10868 GtkSignalFunc func,
10869 GtkObject *slot_object );
10871 guint gtk_signal_connect_object_after( GtkObject *object,
10873 GtkSignalFunc func,
10874 GtkObject *slot_object );
10876 guint gtk_signal_connect_full( GtkObject *object,
10878 GtkSignalFunc func,
10879 GtkCallbackMarshal marshal,
10881 GtkDestroyNotify destroy_func,
10882 gint object_signal,
10885 guint gtk_signal_connect_interp( GtkObject *object,
10887 GtkCallbackMarshal func,
10889 GtkDestroyNotify destroy_func,
10892 void gtk_signal_connect_object_while_alive( GtkObject *object,
10893 const gchar *signal,
10894 GtkSignalFunc func,
10895 GtkObject *alive_object );
10897 void gtk_signal_connect_while_alive( GtkObject *object,
10898 const gchar *signal,
10899 GtkSignalFunc func,
10900 gpointer func_data,
10901 GtkObject *alive_object );
10903 void gtk_signal_disconnect( GtkObject *object,
10904 guint handler_id );
10906 void gtk_signal_disconnect_by_func( GtkObject *object,
10907 GtkSignalFunc func,
10911 <!-- ----------------------------------------------------------------- -->
10912 <sect2>Blocking and Unblocking Signal Handlers
10915 void gtk_signal_handler_block( GtkObject *object,
10918 void gtk_signal_handler_block_by_func( GtkObject *object,
10919 GtkSignalFunc func,
10922 void gtk_signal_handler_block_by_data( GtkObject *object,
10925 void gtk_signal_handler_unblock( GtkObject *object,
10926 guint handler_id );
10928 void gtk_signal_handler_unblock_by_func( GtkObject *object,
10929 GtkSignalFunc func,
10932 void gtk_signal_handler_unblock_by_data( GtkObject *object,
10936 <!-- ----------------------------------------------------------------- -->
10937 <sect2>Emitting and Stopping Signals
10940 void gtk_signal_emit( GtkObject *object,
10944 void gtk_signal_emit_by_name( GtkObject *object,
10948 void gtk_signal_emitv( GtkObject *object,
10952 void gtk_signal_emitv_by_name( GtkObject *object,
10956 guint gtk_signal_n_emissions( GtkObject *object,
10959 guint gtk_signal_n_emissions_by_name( GtkObject *object,
10960 const gchar *name );
10962 void gtk_signal_emit_stop( GtkObject *object,
10965 void gtk_signal_emit_stop_by_name( GtkObject *object,
10966 const gchar *name );
10969 <!-- ----------------------------------------------------------------- -->
10970 <sect1>Signal Emission and Propagation
10972 Signal emission is the process whereby GTK runs all handlers for a
10973 specific object and signal.
10975 First, note that the return value from a signal emission is the return
10976 value of the <em>last</em> handler executed. Since event signals are
10977 all of type <tt/GTK_RUN_LAST/, this will be the default (GTK supplied)
10978 handler, unless you connect with gtk_signal_connect_after().
10980 The way an event (say "button_press_event") is handled, is:
10982 <item>Start with the widget where the event occured.
10984 <item>Emit the generic "event" signal. If that signal handler returns
10985 a value of TRUE, stop all processing.
10987 <item>Otherwise, emit a specific, "button_press_event" signal. If that
10988 returns TRUE, stop all processing.
10990 <item>Otherwise, go to the widget's parent, and repeat the above two
10993 <item>Continue until some signal handler returns TRUE, or until the
10994 top-level widget is reached.
10997 Some consequences of the above are:
10999 <item>Your handler's return value will have no effect if there is a
11000 default handler, unless you connect with gtk_signal_connect_after().
11002 <item>To prevent the default handler from being run, you need to
11003 connect with gtk_signal_connect() and use
11004 gtk_signal_emit_stop_by_name() - the return value only affects whether
11005 the signal is propagated, not the current emission.
11008 <!-- ***************************************************************** -->
11009 <sect>Managing Selections
11010 <!-- ***************************************************************** -->
11012 <!-- ----------------------------------------------------------------- -->
11015 One type of interprocess communication supported by X and GTK is
11016 <em>selections</em>. A selection identifies a chunk of data, for
11017 instance, a portion of text, selected by the user in some fashion, for
11018 instance, by dragging with the mouse. Only one application on a
11019 display (the <em>owner</em>) can own a particular selection at one
11020 time, so when a selection is claimed by one application, the previous
11021 owner must indicate to the user that selection has been
11022 relinquished. Other applications can request the contents of a
11023 selection in different forms, called <em>targets</em>. There can be
11024 any number of selections, but most X applications only handle one, the
11025 <em>primary selection</em>.
11027 In most cases, it isn't necessary for a GTK application to deal with
11028 selections itself. The standard widgets, such as the Entry widget,
11029 already have the capability to claim the selection when appropriate
11030 (e.g., when the user drags over text), and to retrieve the contents of
11031 the selection owned by another widget or another application (e.g.,
11032 when the user clicks the second mouse button). However, there may be
11033 cases in which you want to give other widgets the ability to supply
11034 the selection, or you wish to retrieve targets not supported by
11037 A fundamental concept needed to understand selection handling is that
11038 of the <em>atom</em>. An atom is an integer that uniquely identifies a
11039 string (on a certain display). Certain atoms are predefined by the X
11040 server, and in some cases there are constants in <tt>gtk.h</tt>
11041 corresponding to these atoms. For instance the constant
11042 <tt>GDK_PRIMARY_SELECTION</tt> corresponds to the string "PRIMARY".
11043 In other cases, you should use the functions
11044 <tt>gdk_atom_intern()</tt>, to get the atom corresponding to a string,
11045 and <tt>gdk_atom_name()</tt>, to get the name of an atom. Both
11046 selections and targets are identified by atoms.
11048 <!-- ----------------------------------------------------------------- -->
11049 <sect1> Retrieving the selection
11051 Retrieving the selection is an asynchronous process. To start the
11055 gint gtk_selection_convert( GtkWidget *widget,
11061 This <em>converts</em> the selection into the form specified by
11062 <tt/target/. If at all possible, the time field should be the time
11063 from the event that triggered the selection. This helps make sure that
11064 events occur in the order that the user requested them. However, if it
11065 is not available (for instance, if the conversion was triggered by a
11066 "clicked" signal), then you can use the constant
11067 <tt>GDK_CURRENT_TIME</tt>.
11069 When the selection owner responds to the request, a
11070 "selection_received" signal is sent to your application. The handler
11071 for this signal receives a pointer to a <tt>GtkSelectionData</tt>
11072 structure, which is defined as:
11075 struct _GtkSelectionData
11086 <tt>selection</tt> and <tt>target</tt> are the values you gave in your
11087 <tt>gtk_selection_convert()</tt> call. <tt>type</tt> is an atom that
11088 identifies the type of data returned by the selection owner. Some
11089 possible values are "STRING", a string of latin-1 characters, "ATOM",
11090 a series of atoms, "INTEGER", an integer, etc. Most targets can only
11091 return one type. <tt/format/ gives the length of the units (for
11092 instance characters) in bits. Usually, you don't care about this when
11093 receiving data. <tt>data</tt> is a pointer to the returned data, and
11094 <tt>length</tt> gives the length of the returned data, in bytes. If
11095 <tt>length</tt> is negative, then an error occurred and the selection
11096 could not be retrieved. This might happen if no application owned the
11097 selection, or if you requested a target that the application didn't
11098 support. The buffer is actually guaranteed to be one byte longer than
11099 <tt>length</tt>; the extra byte will always be zero, so it isn't
11100 necessary to make a copy of strings just to null terminate them.
11102 In the following example, we retrieve the special target "TARGETS",
11103 which is a list of all targets into which the selection can be
11107 /* example-start selection gettargets.c */
11109 #include <gtk/gtk.h>
11111 void selection_received (GtkWidget *widget,
11112 GtkSelectionData *selection_data,
11115 /* Signal handler invoked when user clicks on the "Get Targets" button */
11117 get_targets (GtkWidget *widget, gpointer data)
11119 static GdkAtom targets_atom = GDK_NONE;
11121 /* Get the atom corresponding to the string "TARGETS" */
11122 if (targets_atom == GDK_NONE)
11123 targets_atom = gdk_atom_intern ("TARGETS", FALSE);
11125 /* And request the "TARGETS" target for the primary selection */
11126 gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
11130 /* Signal handler called when the selections owner returns the data */
11132 selection_received (GtkWidget *widget, GtkSelectionData *selection_data,
11139 /* **** IMPORTANT **** Check to see if retrieval succeeded */
11140 if (selection_data->length < 0)
11142 g_print ("Selection retrieval failed\n");
11145 /* Make sure we got the data in the expected form */
11146 if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
11148 g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
11152 /* Print out the atoms we received */
11153 atoms = (GdkAtom *)selection_data->data;
11156 for (i=0; i<selection_data->length/sizeof(GdkAtom); i++)
11159 name = gdk_atom_name (atoms[i]);
11161 g_print ("%s\n",name);
11163 g_print ("(bad atom)\n");
11170 main (int argc, char *argv[])
11175 gtk_init (&argc, &argv);
11177 /* Create the toplevel window */
11179 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11180 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
11181 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
11183 gtk_signal_connect (GTK_OBJECT (window), "destroy",
11184 GTK_SIGNAL_FUNC (gtk_exit), NULL);
11186 /* Create a button the user can click to get targets */
11188 button = gtk_button_new_with_label ("Get Targets");
11189 gtk_container_add (GTK_CONTAINER (window), button);
11191 gtk_signal_connect (GTK_OBJECT(button), "clicked",
11192 GTK_SIGNAL_FUNC (get_targets), NULL);
11193 gtk_signal_connect (GTK_OBJECT(button), "selection_received",
11194 GTK_SIGNAL_FUNC (selection_received), NULL);
11196 gtk_widget_show (button);
11197 gtk_widget_show (window);
11206 <!-- ----------------------------------------------------------------- -->
11207 <sect1> Supplying the selection
11209 Supplying the selection is a bit more complicated. You must register
11210 handlers that will be called when your selection is requested. For
11211 each selection/target pair you will handle, you make a call to:
11214 void gtk_selection_add_handler( GtkWidget *widget,
11217 GtkSelectionFunction function,
11218 GtkRemoveFunction remove_func,
11222 <tt/widget/, <tt/selection/, and <tt/target/ identify the requests
11223 this handler will manage. <tt/remove_func/, if not
11224 NULL, will be called when the signal handler is removed. This is
11225 useful, for instance, for interpreted languages which need to
11226 keep track of a reference count for <tt/data/.
11228 The callback function has the signature:
11231 typedef void (*GtkSelectionFunction)( GtkWidget *widget,
11232 GtkSelectionData *selection_data,
11237 The GtkSelectionData is the same as above, but this time, we're
11238 responsible for filling in the fields <tt/type/, <tt/format/,
11239 <tt/data/, and <tt/length/. (The <tt/format/ field is actually
11240 important here - the X server uses it to figure out whether the data
11241 needs to be byte-swapped or not. Usually it will be 8 - <em/i.e./ a
11242 character - or 32 - <em/i.e./ a. integer.) This is done by calling the
11246 void gtk_selection_data_set( GtkSelectionData *selection_data,
11253 This function takes care of properly making a copy of the data so that
11254 you don't have to worry about keeping it around. (You should not fill
11255 in the fields of the GtkSelectionData structure by hand.)
11257 When prompted by the user, you claim ownership of the selection by
11261 gint gtk_selection_owner_set( GtkWidget *widget,
11266 If another application claims ownership of the selection, you will
11267 receive a "selection_clear_event".
11269 As an example of supplying the selection, the following program adds
11270 selection functionality to a toggle button. When the toggle button is
11271 depressed, the program claims the primary selection. The only target
11272 supported (aside from certain targets like "TARGETS" supplied by GTK
11273 itself), is the "STRING" target. When this target is requested, a
11274 string representation of the time is returned.
11277 /* example-start selection setselection.c */
11279 #include <gtk/gtk.h>
11282 /* Callback when the user toggles the selection */
11284 selection_toggled (GtkWidget *widget, gint *have_selection)
11286 if (GTK_TOGGLE_BUTTON(widget)->active)
11288 *have_selection = gtk_selection_owner_set (widget,
11289 GDK_SELECTION_PRIMARY,
11291 /* if claiming the selection failed, we return the button to
11293 if (!*have_selection)
11294 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), FALSE);
11298 if (*have_selection)
11300 /* Before clearing the selection by setting the owner to NULL,
11301 we check if we are the actual owner */
11302 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
11303 gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
11305 *have_selection = FALSE;
11310 /* Called when another application claims the selection */
11312 selection_clear (GtkWidget *widget, GdkEventSelection *event,
11313 gint *have_selection)
11315 *have_selection = FALSE;
11316 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), FALSE);
11321 /* Supplies the current time as the selection. */
11323 selection_handle (GtkWidget *widget,
11324 GtkSelectionData *selection_data,
11328 time_t current_time;
11330 current_time = time (NULL);
11331 timestr = asctime (localtime(&current_time));
11332 /* When we return a single string, it should not be null terminated.
11333 That will be done for us */
11335 gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
11336 8, timestr, strlen(timestr));
11340 main (int argc, char *argv[])
11344 GtkWidget *selection_button;
11346 static int have_selection = FALSE;
11348 gtk_init (&argc, &argv);
11350 /* Create the toplevel window */
11352 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11353 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
11354 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
11356 gtk_signal_connect (GTK_OBJECT (window), "destroy",
11357 GTK_SIGNAL_FUNC (gtk_exit), NULL);
11359 /* Create a toggle button to act as the selection */
11361 selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
11362 gtk_container_add (GTK_CONTAINER (window), selection_button);
11363 gtk_widget_show (selection_button);
11365 gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
11366 GTK_SIGNAL_FUNC (selection_toggled), &have_selection);
11367 gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
11368 GTK_SIGNAL_FUNC (selection_clear), &have_selection);
11370 gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
11371 GDK_SELECTION_TYPE_STRING,
11372 selection_handle, NULL);
11374 gtk_widget_show (selection_button);
11375 gtk_widget_show (window);
11385 <!-- ***************************************************************** -->
11386 <sect>GLib<label id="sec_glib">
11387 <!-- ***************************************************************** -->
11389 GLib is a lower-level library that provides many useful definitions
11390 and functions available for use when creating GDK and GTK
11391 applications. These include definitions for basic types and their
11392 limits, standard macros, type conversions, byte order, memory
11393 allocation, warnings and assertions, message logging, timers, string
11394 utilities, hook functions, a lexical scanner, dynamic loading of
11395 modules, and automatic string completion. A number of data structures
11396 (and their related operations) are also defined, including memory
11397 chunks, doubly-linked lists, singly-linked lists, hash tables, strings
11398 (which can grow dynamically), string chunks (groups of strings),
11399 arrays (which can grow in size as elements are added), balanced binary
11400 trees, N-ary trees, quarks (a two-way association of a string and a
11401 unique integer identifier), keyed data lists (lists of data elements
11402 accessible by a string or integer id), relations and tuples (tables of
11403 data which can be indexed on any number of fields), and caches.
11405 A summary of some of GLib's capabilities follows; not every function,
11406 data structure, or operation is covered here. For more complete
11407 information about the GLib routines, see the GLib documentation. One
11408 source of GLib documentation is <htmlurl url="http://www.gtk.org/"
11409 name="http://www.gtk.org/">.
11411 If you are using a language other than C, you should consult your
11412 language's binding documentation. In some cases your language may
11413 have equivalent functionality built-in, while in other cases it may
11416 <!-- ----------------------------------------------------------------- -->
11419 Definitions for the extremes of many of the standard types are:
11434 Also, the following typedefs. The ones left unspecified are dynamically set
11435 depending on the architecture. Remember to avoid counting on the size of a
11436 pointer if you want to be portable! E.g., a pointer on an Alpha is 8
11437 bytes, but 4 on Intel 80x86 family CPUs.
11446 unsigned char guchar;
11447 unsigned short gushort;
11448 unsigned long gulong;
11449 unsigned int guint;
11453 long double gldouble;
11465 <!-- ----------------------------------------------------------------- -->
11466 <sect1>Doubly Linked Lists
11468 The following functions are used to create, manage, and destroy
11469 standard doubly linked lists. Each element in the list contains a
11470 piece of data, together with pointers which link to the previous and
11471 next elements in the list. This enables easy movement in either
11472 direction through the list. The data item is of type "gpointer",
11473 which means the data can be a pointer to your real data or (through
11474 casting) a numeric value (but do not assume that int and gpointer have
11475 the same size!). These routines internally allocate list elements in
11476 blocks, which is more efficient than allocating elements individually.
11478 There is no function to specifically create a list. Instead, simply
11479 create a variable of type GList* and set its value to NULL; NULL is
11480 considered to be the empty list.
11482 To add elements to a list, use the g_list_append(), g_list_prepend(),
11483 g_list_insert(), or g_list_insert_sorted() routines. In all cases
11484 they accept a pointer to the beginning of the list, and return the
11485 (possibly changed) pointer to the beginning of the list. Thus, for
11486 all of the operations that add or remove elements, be sure to save the
11490 GList *g_list_append( GList *list,
11494 This adds a new element (with value <tt/data/) onto the end of the
11498 GList *g_list_prepend( GList *list,
11502 This adds a new element (with value <tt/data/) to the beginning of the
11506 GList *g_list_insert( GList *list,
11512 This inserts a new element (with value data) into the list at the
11513 given position. If position is 0, this is just like g_list_prepend();
11514 if position is less than 0, this is just like g_list_append().
11517 GList *g_list_remove( GList *list,
11521 This removes the element in the list with the value <tt/data/;
11522 if the element isn't there, the list is unchanged.
11525 void g_list_free( GList *list );
11528 This frees all of the memory used by a GList. If the list elements
11529 refer to dynamically-allocated memory, then they should be freed
11532 There are many other GLib functions that support doubly linked lists;
11533 see the glib documentation for more information. Here are a few of
11534 the more useful functions' signatures:
11537 GList *g_list_remove_link( GList *list,
11540 GList *g_list_reverse( GList *list );
11542 GList *g_list_nth( GList *list,
11545 GList *g_list_find( GList *list,
11548 GList *g_list_last( GList *list );
11550 GList *g_list_first( GList *list );
11552 gint g_list_length( GList *list );
11554 void g_list_foreach( GList *list,
11556 gpointer user_data );
11559 <!-- ----------------------------------------------------------------- -->
11560 <sect1>Singly Linked Lists
11562 Many of the above functions for singly linked lists are identical to the
11563 above. Here is a list of some of their operations:
11566 GSList *g_slist_append( GSList *list,
11569 GSList *g_slist_prepend( GSList *list,
11572 GSList *g_slist_insert( GSList *list,
11576 GSList *g_slist_remove( GSList *list,
11579 GSList *g_slist_remove_link( GSList *list,
11582 GSList *g_slist_reverse( GSList *list );
11584 GSList *g_slist_nth( GSList *list,
11587 GSList *g_slist_find( GSList *list,
11590 GSList *g_slist_last( GSList *list );
11592 gint g_slist_length( GSList *list );
11594 void g_slist_foreach( GSList *list,
11596 gpointer user_data );
11600 <!-- ----------------------------------------------------------------- -->
11601 <sect1>Memory Management
11604 gpointer g_malloc( gulong size );
11607 This is a replacement for malloc(). You do not need to check the return
11608 value as it is done for you in this function. If the memory allocation
11609 fails for whatever reasons, your applications will be terminated.
11612 gpointer g_malloc0( gulong size );
11615 Same as above, but zeroes the memory before returning a pointer to it.
11618 gpointer g_realloc( gpointer mem,
11622 Relocates "size" bytes of memory starting at "mem". Obviously, the
11623 memory should have been previously allocated.
11626 void g_free( gpointer mem );
11629 Frees memory. Easy one. If <tt/mem/ is NULL it simply returns.
11632 void g_mem_profile( void );
11635 Dumps a profile of used memory, but requires that you add <tt>#define
11636 MEM_PROFILE</tt> to the top of glib/gmem.c and re-make and make install.
11639 void g_mem_check( gpointer mem );
11642 Checks that a memory location is valid. Requires you add <tt>#define
11643 MEM_CHECK</tt> to the top of gmem.c and re-make and make install.
11645 <!-- ----------------------------------------------------------------- -->
11648 Timer functions can be used to time operations (e.g., to see how much
11649 time has elapsed). First, you create a new timer with g_timer_new().
11650 You can then use g_timer_start() to start timing an operation,
11651 g_timer_stop() to stop timing an operation, and g_timer_elapsed() to
11652 determine the elapsed time.
11655 GTimer *g_timer_new( void );
11657 void g_timer_destroy( GTimer *timer );
11659 void g_timer_start( GTimer *timer );
11661 void g_timer_stop( GTimer *timer );
11663 void g_timer_reset( GTimer *timer );
11665 gdouble g_timer_elapsed( GTimer *timer,
11666 gulong *microseconds );
11669 <!-- ----------------------------------------------------------------- -->
11670 <sect1>String Handling
11672 GLib defines a new type called a GString, which is similar to a
11673 standard C string but one that grows automatically. Its string data
11674 is null-terminated. What this gives you is protection from buffer
11675 overflow programming errors within your program. This is a very
11676 important feature, and hence I recommend that you make use of
11677 GStrings. GString itself has a simple public definition:
11682 gchar *str; /* Points to the string's current \0-terminated value. */
11683 gint len; /* Current length */
11687 As you might expect, there are a number of operations you can do with
11691 GString *g_string_new( gchar *init );
11694 This constructs a GString, copying the string value of <tt/init/
11695 into the GString and returning a pointer to it. NULL may be given as
11696 the argument for an initially empty GString.
11700 void g_string_free( GString *string,
11701 gint free_segment );
11704 This frees the memory for the given GString. If <tt/free_segment/ is
11705 TRUE, then this also frees its character data.
11709 GString *g_string_assign( GString *lval,
11710 const gchar *rval );
11713 This copies the characters from rval into lval, destroying the
11714 previous contents of lval. Note that lval will be lengthened as
11715 necessary to hold the string's contents, unlike the standard strcpy()
11718 The rest of these functions should be relatively obvious (the _c
11719 versions accept a character instead of a string):
11722 GString *g_string_truncate( GString *string,
11725 GString *g_string_append( GString *string,
11728 GString *g_string_append_c( GString *string,
11731 GString *g_string_prepend( GString *string,
11734 GString *g_string_prepend_c( GString *string,
11737 void g_string_sprintf( GString *string,
11741 void g_string_sprintfa ( GString *string,
11746 <!-- ----------------------------------------------------------------- -->
11747 <sect1>Utility and Error Functions
11750 gchar *g_strdup( const gchar *str );
11753 Replacement strdup function. Copies the original strings contents to
11754 newly allocated memory, and returns a pointer to it.
11757 gchar *g_strerror( gint errnum );
11760 I recommend using this for all error messages. It's much nicer, and more
11761 portable than perror() or others. The output is usually of the form:
11764 program name:function that failed:file or further description:strerror
11767 Here's an example of one such call used in our hello_world program:
11770 g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
11774 void g_error( gchar *format, ... );
11777 Prints an error message. The format is just like printf, but it
11778 prepends "** ERROR **: " to your message, and exits the program.
11779 Use only for fatal errors.
11782 void g_warning( gchar *format, ... );
11785 Same as above, but prepends "** WARNING **: ", and does not exit the
11789 void g_message( gchar *format, ... );
11792 Prints "message: " prepended to the string you pass in.
11795 void g_print( gchar *format, ... );
11798 Replacement for printf().
11800 And our last function:
11803 gchar *g_strsignal( gint signum );
11806 Prints out the name of the Unix system signal given the signal number.
11807 Useful in generic signal handling functions.
11809 All of the above are more or less just stolen from glib.h. If anyone cares
11810 to document any function, just send me an email!
11812 <!-- ***************************************************************** -->
11813 <sect>GTK's rc Files <label id="sec_gtkrc_files">
11814 <!-- ***************************************************************** -->
11816 GTK has its own way of dealing with application defaults, by using rc
11817 files. These can be used to set the colors of just about any widget, and
11818 can also be used to tile pixmaps onto the background of some widgets.
11820 <!-- ----------------------------------------------------------------- -->
11821 <sect1>Functions For rc Files
11823 When your application starts, you should include a call to:
11826 void gtk_rc_parse( char *filename );
11829 Passing in the filename of your rc file. This will cause GTK to parse
11830 this file, and use the style settings for the widget types defined
11833 If you wish to have a special set of widgets that can take on a
11834 different style from others, or any other logical division of widgets,
11838 void gtk_widget_set_name( GtkWidget *widget,
11842 Passing your newly created widget as the first argument, and the name
11843 you wish to give it as the second. This will allow you to change the
11844 attributes of this widget by name through the rc file.
11846 If we use a call something like this:
11849 button = gtk_button_new_with_label ("Special Button");
11850 gtk_widget_set_name (button, "special button");
11853 Then this button is given the name "special button" and may be addressed by
11854 name in the rc file as "special button.GtkButton". [<--- Verify ME!]
11856 The example rc file below, sets the properties of the main window, and lets
11857 all children of that main window inherit the style described by the "main
11858 button" style. The code used in the application is:
11861 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11862 gtk_widget_set_name (window, "main window");
11865 And then the style is defined in the rc file using:
11868 widget "main window.*GtkButton*" style "main_button"
11871 Which sets all the Button widgets in the "main window" to the
11872 "main_buttons" style as defined in the rc file.
11874 As you can see, this is a fairly powerful and flexible system. Use your
11875 imagination as to how best to take advantage of this.
11877 <!-- ----------------------------------------------------------------- -->
11878 <sect1>GTK's rc File Format
11880 The format of the GTK file is illustrated in the example below. This is
11881 the testgtkrc file from the GTK distribution, but I've added a
11882 few comments and things. You may wish to include this explanation in
11883 your application to allow the user to fine tune his application.
11885 There are several directives to change the attributes of a widget.
11888 <item>fg - Sets the foreground color of a widget.
11889 <item>bg - Sets the background color of a widget.
11890 <item>bg_pixmap - Sets the background of a widget to a tiled pixmap.
11891 <item>font - Sets the font to be used with the given widget.
11894 In addition to this, there are several states a widget can be in, and you
11895 can set different colors, pixmaps and fonts for each state. These states are:
11898 <item>NORMAL - The normal state of a widget, without the mouse over top of
11899 it, and not being pressed, etc.
11900 <item>PRELIGHT - When the mouse is over top of the widget, colors defined
11901 using this state will be in effect.
11902 <item>ACTIVE - When the widget is pressed or clicked it will be active, and
11903 the attributes assigned by this tag will be in effect.
11904 <item>INSENSITIVE - When a widget is set insensitive, and cannot be
11905 activated, it will take these attributes.
11906 <item>SELECTED - When an object is selected, it takes these attributes.
11909 When using the "fg" and "bg" keywords to set the colors of widgets, the
11913 fg[<STATE>] = { Red, Green, Blue }
11916 Where STATE is one of the above states (PRELIGHT, ACTIVE, etc), and the Red,
11917 Green and Blue are values in the range of 0 - 1.0, { 1.0, 1.0, 1.0 } being
11918 white. They must be in float form, or they will register as 0, so a straight
11919 "1" will not work, it must be "1.0". A straight "0" is fine because it
11920 doesn't matter if it's not recognized. Unrecognized values are set to 0.
11922 bg_pixmap is very similar to the above, except the colors are replaced by a
11925 pixmap_path is a list of paths separated by ":"'s. These paths will be
11926 searched for any pixmap you specify.
11928 The font directive is simply:
11930 font = "<font name>"
11933 The only hard part is figuring out the font string. Using xfontsel or
11934 a similar utility should help.
11936 The "widget_class" sets the style of a class of widgets. These classes are
11937 listed in the widget overview on the class hierarchy.
11939 The "widget" directive sets a specifically named set of widgets to a
11940 given style, overriding any style set for the given widget class.
11941 These widgets are registered inside the application using the
11942 gtk_widget_set_name() call. This allows you to specify the attributes of a
11943 widget on a per widget basis, rather than setting the attributes of an
11944 entire widget class. I urge you to document any of these special widgets so
11945 users may customize them.
11947 When the keyword <tt>parent</> is used as an attribute, the widget will take on
11948 the attributes of its parent in the application.
11950 When defining a style, you may assign the attributes of a previously defined
11951 style to this new one.
11954 style "main_button" = "button"
11956 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
11957 bg[PRELIGHT] = { 0.75, 0, 0 }
11961 This example takes the "button" style, and creates a new "main_button" style
11962 simply by changing the font and prelight background color of the "button"
11965 Of course, many of these attributes don't apply to all widgets. It's a
11966 simple matter of common sense really. Anything that could apply, should.
11968 <!-- ----------------------------------------------------------------- -->
11969 <sect1>Example rc file
11973 # pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
11975 pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
11977 # style <name> [= <name>]
11982 # widget <widget_set> style <style_name>
11983 # widget_class <widget_class_set> style <style_name>
11986 # Here is a list of all the possible states. Note that some do not apply to
11989 # NORMAL - The normal state of a widget, without the mouse over top of
11990 # it, and not being pressed, etc.
11992 # PRELIGHT - When the mouse is over top of the widget, colors defined
11993 # using this state will be in effect.
11995 # ACTIVE - When the widget is pressed or clicked it will be active, and
11996 # the attributes assigned by this tag will be in effect.
11998 # INSENSITIVE - When a widget is set insensitive, and cannot be
11999 # activated, it will take these attributes.
12001 # SELECTED - When an object is selected, it takes these attributes.
12003 # Given these states, we can set the attributes of the widgets in each of
12004 # these states using the following directives.
12006 # fg - Sets the foreground color of a widget.
12007 # fg - Sets the background color of a widget.
12008 # bg_pixmap - Sets the background of a widget to a tiled pixmap.
12009 # font - Sets the font to be used with the given widget.
12012 # This sets a style called "button". The name is not really important, as
12013 # it is assigned to the actual widgets at the bottom of the file.
12017 #This sets the padding around the window to the pixmap specified.
12018 #bg_pixmap[<STATE>] = "<pixmap filename>"
12019 bg_pixmap[NORMAL] = "warning.xpm"
12024 #Sets the foreground color (font color) to red when in the "NORMAL"
12027 fg[NORMAL] = { 1.0, 0, 0 }
12029 #Sets the background pixmap of this widget to that of its parent.
12030 bg_pixmap[NORMAL] = "<parent>"
12035 # This shows all the possible states for a button. The only one that
12036 # doesn't apply is the SELECTED state.
12038 fg[PRELIGHT] = { 0, 1.0, 1.0 }
12039 bg[PRELIGHT] = { 0, 0, 1.0 }
12040 bg[ACTIVE] = { 1.0, 0, 0 }
12041 fg[ACTIVE] = { 0, 1.0, 0 }
12042 bg[NORMAL] = { 1.0, 1.0, 0 }
12043 fg[NORMAL] = { .99, 0, .99 }
12044 bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
12045 fg[INSENSITIVE] = { 1.0, 0, 1.0 }
12048 # In this example, we inherit the attributes of the "button" style and then
12049 # override the font and background color when prelit to create a new
12050 # "main_button" style.
12052 style "main_button" = "button"
12054 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
12055 bg[PRELIGHT] = { 0.75, 0, 0 }
12058 style "toggle_button" = "button"
12060 fg[NORMAL] = { 1.0, 0, 0 }
12061 fg[ACTIVE] = { 1.0, 0, 0 }
12063 # This sets the background pixmap of the toggle_button to that of its
12064 # parent widget (as defined in the application).
12065 bg_pixmap[NORMAL] = "<parent>"
12070 bg_pixmap[NORMAL] = "marble.xpm"
12071 fg[NORMAL] = { 1.0, 1.0, 1.0 }
12076 font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
12079 # pixmap_path "~/.pixmaps"
12081 # These set the widget types to use the styles defined above.
12082 # The widget types are listed in the class hierarchy, but could probably be
12083 # just listed in this document for the users reference.
12085 widget_class "GtkWindow" style "window"
12086 widget_class "GtkDialog" style "window"
12087 widget_class "GtkFileSelection" style "window"
12088 widget_class "*Gtk*Scale" style "scale"
12089 widget_class "*GtkCheckButton*" style "toggle_button"
12090 widget_class "*GtkRadioButton*" style "toggle_button"
12091 widget_class "*GtkButton*" style "button"
12092 widget_class "*Ruler" style "ruler"
12093 widget_class "*GtkText" style "text"
12095 # This sets all the buttons that are children of the "main window" to
12096 # the main_button style. These must be documented to be taken advantage of.
12097 widget "main window.*GtkButton*" style "main_button"
12100 <!-- ***************************************************************** -->
12101 <sect>Writing Your Own Widgets
12102 <!-- ***************************************************************** -->
12104 <!-- ----------------------------------------------------------------- -->
12107 Although the GTK distribution comes with many types of widgets that
12108 should cover most basic needs, there may come a time when you need to
12109 create your own new widget type. Since GTK uses widget inheritance
12110 extensively, and there is already a widget that is close to what you want,
12111 it is often possible to make a useful new widget type in
12112 just a few lines of code. But before starting work on a new widget, check
12113 around first to make sure that someone has not already written
12114 it. This will prevent duplication of effort and keep the number of
12115 GTK widgets out there to a minimum, which will help keep both the code
12116 and the interface of different applications consistent. As a flip side
12117 to this, once you finish your widget, announce it to the world so
12118 other people can benefit. The best place to do this is probably the
12121 Complete sources for the example widgets are available at the place you
12122 got this tutorial, or from:
12124 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
12125 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
12128 <!-- ----------------------------------------------------------------- -->
12129 <sect1> The Anatomy Of A Widget
12131 In order to create a new widget, it is important to have an
12132 understanding of how GTK objects work. This section is just meant as a
12133 brief overview. See the reference documentation for the details.
12135 GTK widgets are implemented in an object oriented fashion. However,
12136 they are implemented in standard C. This greatly improves portability
12137 and stability over using current generation C++ compilers; however,
12138 it does mean that the widget writer has to pay attention to some of
12139 the implementation details. The information common to all instances of
12140 one class of widgets (e.g., to all Button widgets) is stored in the
12141 <em>class structure</em>. There is only one copy of this in
12142 which is stored information about the class's signals
12143 (which act like virtual functions in C). To support inheritance, the
12144 first field in the class structure must be a copy of the parent's
12145 class structure. The declaration of the class structure of GtkButtton
12149 struct _GtkButtonClass
12151 GtkContainerClass parent_class;
12153 void (* pressed) (GtkButton *button);
12154 void (* released) (GtkButton *button);
12155 void (* clicked) (GtkButton *button);
12156 void (* enter) (GtkButton *button);
12157 void (* leave) (GtkButton *button);
12161 When a button is treated as a container (for instance, when it is
12162 resized), its class structure can be cast to GtkContainerClass, and
12163 the relevant fields used to handle the signals.
12165 There is also a structure for each widget that is created on a
12166 per-instance basis. This structure has fields to store information that
12167 is different for each instance of the widget. We'll call this
12168 structure the <em>object structure</em>. For the Button class, it looks
12174 GtkContainer container;
12178 guint in_button : 1;
12179 guint button_down : 1;
12183 Note that, similar to the class structure, the first field is the
12184 object structure of the parent class, so that this structure can be
12185 cast to the parent class' object structure as needed.
12187 <!-- ----------------------------------------------------------------- -->
12188 <sect1> Creating a Composite widget
12190 <!-- ----------------------------------------------------------------- -->
12191 <sect2> Introduction
12193 One type of widget that you may be interested in creating is a
12194 widget that is merely an aggregate of other GTK widgets. This type of
12195 widget does nothing that couldn't be done without creating new
12196 widgets, but provides a convenient way of packaging user interface
12197 elements for reuse. The FileSelection and ColorSelection widgets in
12198 the standard distribution are examples of this type of widget.
12200 The example widget that we'll create in this section is the Tictactoe
12201 widget, a 3x3 array of toggle buttons which triggers a signal when all
12202 three buttons in a row, column, or on one of the diagonals are
12205 <!-- ----------------------------------------------------------------- -->
12206 <sect2> Choosing a parent class
12208 The parent class for a composite widget is typically the container
12209 class that holds all of the elements of the composite widget. For
12210 example, the parent class of the FileSelection widget is the
12211 Dialog class. Since our buttons will be arranged in a table, it
12212 might seem natural to make our parent class the Table
12213 class. Unfortunately, this turns out not to work. The creation of a
12214 widget is divided among two functions - a <tt/WIDGETNAME_new()/
12215 function that the user calls, and a <tt/WIDGETNAME_init()/ function
12216 which does the basic work of initializing the widget which is
12217 independent of the arguments passed to the <tt/_new()/
12218 function. Descendant widgets only call the <tt/_init/ function of
12219 their parent widget. But this division of labor doesn't work well for
12220 tables, which when created need to know the number of rows and
12221 columns in the table. Unless we want to duplicate most of the
12222 functionality of <tt/gtk_table_new()/ in our Tictactoe widget, we had
12223 best avoid deriving it from Table. For that reason, we derive it
12224 from VBox instead, and stick our table inside the VBox.
12226 <!-- ----------------------------------------------------------------- -->
12227 <sect2> The header file
12229 Each widget class has a header file which declares the object and
12230 class structures for that widget, along with public functions.
12231 A couple of features are worth pointing out. To prevent duplicate
12232 definitions, we wrap the entire header file in:
12235 #ifndef __TICTACTOE_H__
12236 #define __TICTACTOE_H__
12240 #endif /* __TICTACTOE_H__ */
12243 And to keep C++ programs that include the header file happy, in:
12248 #endif /* __cplusplus */
12254 #endif /* __cplusplus */
12257 Along with the functions and structures, we declare three standard
12258 macros in our header file, <tt/TICTACTOE(obj)/,
12259 <tt/TICTACTOE_CLASS(klass)/, and <tt/IS_TICTACTOE(obj)/, which cast a
12260 pointer into a pointer to the object or class structure, and check
12261 if an object is a Tictactoe widget respectively.
12263 Here is the complete header file:
12268 #ifndef __TICTACTOE_H__
12269 #define __TICTACTOE_H__
12271 #include <gdk/gdk.h>
12272 #include <gtk/gtkvbox.h>
12276 #endif /* __cplusplus */
12278 #define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
12279 #define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
12280 #define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
12283 typedef struct _Tictactoe Tictactoe;
12284 typedef struct _TictactoeClass TictactoeClass;
12290 GtkWidget *buttons[3][3];
12293 struct _TictactoeClass
12295 GtkVBoxClass parent_class;
12297 void (* tictactoe) (Tictactoe *ttt);
12300 guint tictactoe_get_type (void);
12301 GtkWidget* tictactoe_new (void);
12302 void tictactoe_clear (Tictactoe *ttt);
12306 #endif /* __cplusplus */
12308 #endif /* __TICTACTOE_H__ */
12312 <!-- ----------------------------------------------------------------- -->
12313 <sect2> The <tt/_get_type()/ function.
12315 We now continue on to the implementation of our widget. A core
12316 function for every widget is the function
12317 <tt/WIDGETNAME_get_type()/. This function, when first called, tells
12318 GTK about the widget class, and gets an ID that uniquely identifies
12319 the widget class. Upon subsequent calls, it just returns the ID.
12323 tictactoe_get_type ()
12325 static guint ttt_type = 0;
12329 GtkTypeInfo ttt_info =
12332 sizeof (Tictactoe),
12333 sizeof (TictactoeClass),
12334 (GtkClassInitFunc) tictactoe_class_init,
12335 (GtkObjectInitFunc) tictactoe_init,
12336 (GtkArgSetFunc) NULL,
12337 (GtkArgGetFunc) NULL
12340 ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
12347 The GtkTypeInfo structure has the following definition:
12350 struct _GtkTypeInfo
12355 GtkClassInitFunc class_init_func;
12356 GtkObjectInitFunc object_init_func;
12357 GtkArgSetFunc arg_set_func;
12358 GtkArgGetFunc arg_get_func;
12362 The fields of this structure are pretty self-explanatory. We'll ignore
12363 the <tt/arg_set_func/ and <tt/arg_get_func/ fields here: they have an important,
12365 unimplemented, role in allowing widget options to be conveniently set
12366 from interpreted languages. Once GTK has a correctly filled in copy of
12367 this structure, it knows how to create objects of a particular widget
12370 <!-- ----------------------------------------------------------------- -->
12371 <sect2> The <tt/_class_init()/ function
12373 The <tt/WIDGETNAME_class_init()/ function initializes the fields of
12374 the widget's class structure, and sets up any signals for the
12375 class. For our Tictactoe widget it looks like:
12384 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
12387 tictactoe_class_init (TictactoeClass *class)
12389 GtkObjectClass *object_class;
12391 object_class = (GtkObjectClass*) class;
12393 tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
12395 object_class->type,
12396 GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
12397 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
12400 gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
12402 class->tictactoe = NULL;
12406 Our widget has just one signal, the <tt/tictactoe/ signal that is
12407 invoked when a row, column, or diagonal is completely filled in. Not
12408 every composite widget needs signals, so if you are reading this for
12409 the first time, you may want to skip to the next section now, as
12410 things are going to get a bit complicated.
12415 gint gtk_signal_new( const gchar *name,
12416 GtkSignalRunType run_type,
12417 GtkType object_type,
12418 gint function_offset,
12419 GtkSignalMarshaller marshaller,
12420 GtkType return_val,
12425 Creates a new signal. The parameters are:
12428 <item> <tt/name/: The name of the signal.
12429 <item> <tt/run_type/: Whether the default handler runs before or after
12430 user handlers. Usually this will be <tt/GTK_RUN_FIRST/, or <tt/GTK_RUN_LAST/,
12431 although there are other possibilities.
12432 <item> <tt/object_type/: The ID of the object that this signal applies
12433 to. (It will also apply to that objects descendants.)
12434 <item> <tt/function_offset/: The offset within the class structure of
12435 a pointer to the default handler.
12436 <item> <tt/marshaller/: A function that is used to invoke the signal
12437 handler. For signal handlers that have no arguments other than the
12438 object that emitted the signal and user data, we can use the
12439 pre-supplied marshaller function <tt/gtk_signal_default_marshaller/.
12440 <item> <tt/return_val/: The type of the return val.
12441 <item> <tt/nparams/: The number of parameters of the signal handler
12442 (other than the two default ones mentioned above)
12443 <item> <tt/.../: The types of the parameters.
12446 When specifying types, the <tt/GtkType/ enumeration is used:
12471 /* it'd be great if the next two could be removed eventually */
12473 GTK_TYPE_C_CALLBACK,
12477 } GtkFundamentalType;
12480 <tt/gtk_signal_new()/ returns a unique integer identifier for the
12481 signal, that we store in the <tt/tictactoe_signals/ array, which we
12482 index using an enumeration. (Conventionally, the enumeration elements
12483 are the signal name, uppercased, but here there would be a conflict
12484 with the <tt/TICTACTOE()/ macro, so we called it <tt/TICTACTOE_SIGNAL/
12487 After creating our signals, we need to tell GTK to associate our
12488 signals with the Tictactoe class. We do that by calling
12489 <tt/gtk_object_class_add_signals()/. We then set the pointer which
12490 points to the default handler for the "tictactoe" signal to NULL,
12491 indicating that there is no default action.
12493 <!-- ----------------------------------------------------------------- -->
12494 <sect2> The <tt/_init()/ function.
12496 Each widget class also needs a function to initialize the object
12497 structure. Usually, this function has the fairly limited role of
12498 setting the fields of the structure to default values. For composite
12499 widgets, however, this function also creates the component widgets.
12503 tictactoe_init (Tictactoe *ttt)
12508 table = gtk_table_new (3, 3, TRUE);
12509 gtk_container_add (GTK_CONTAINER(ttt), table);
12510 gtk_widget_show (table);
12515 ttt->buttons[i][j] = gtk_toggle_button_new ();
12516 gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
12518 gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
12519 GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
12520 gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
12521 gtk_widget_show (ttt->buttons[i][j]);
12526 <!-- ----------------------------------------------------------------- -->
12527 <sect2> And the rest...
12529 There is one more function that every widget (except for base widget
12530 types like Bin that cannot be instantiated) needs to have - the
12531 function that the user calls to create an object of that type. This is
12532 conventionally called <tt/WIDGETNAME_new()/. In some
12533 widgets, though not for the Tictactoe widgets, this function takes
12534 arguments, and does some setup based on the arguments. The other two
12535 functions are specific to the Tictactoe widget.
12537 <tt/tictactoe_clear()/ is a public function that resets all the
12538 buttons in the widget to the up position. Note the use of
12539 <tt/gtk_signal_handler_block_by_data()/ to keep our signal handler for
12540 button toggles from being triggered unnecessarily.
12542 <tt/tictactoe_toggle()/ is the signal handler that is invoked when the
12543 user clicks on a button. It checks to see if there are any winning
12544 combinations that involve the toggled button, and if so, emits
12545 the "tictactoe" signal.
12551 return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
12555 tictactoe_clear (Tictactoe *ttt)
12562 gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
12563 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
12565 gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
12570 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
12574 static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
12575 { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
12576 { 0, 1, 2 }, { 0, 1, 2 } };
12577 static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
12578 { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
12579 { 0, 1, 2 }, { 2, 1, 0 } };
12581 int success, found;
12583 for (k=0; k<8; k++)
12590 success = success &&
12591 GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
12593 ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
12596 if (success && found)
12598 gtk_signal_emit (GTK_OBJECT (ttt),
12599 tictactoe_signals[TICTACTOE_SIGNAL]);
12606 And finally, an example program using our Tictactoe widget:
12609 #include <gtk/gtk.h>
12610 #include "tictactoe.h"
12612 /* Invoked when a row, column or diagonal is completed */
12614 win (GtkWidget *widget, gpointer data)
12616 g_print ("Yay!\n");
12617 tictactoe_clear (TICTACTOE (widget));
12621 main (int argc, char *argv[])
12626 gtk_init (&argc, &argv);
12628 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
12630 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
12632 gtk_signal_connect (GTK_OBJECT (window), "destroy",
12633 GTK_SIGNAL_FUNC (gtk_exit), NULL);
12635 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
12637 /* Create a new Tictactoe widget */
12638 ttt = tictactoe_new ();
12639 gtk_container_add (GTK_CONTAINER (window), ttt);
12640 gtk_widget_show (ttt);
12642 /* And attach to its "tictactoe" signal */
12643 gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
12644 GTK_SIGNAL_FUNC (win), NULL);
12646 gtk_widget_show (window);
12655 <!-- ----------------------------------------------------------------- -->
12656 <sect1> Creating a widget from scratch.
12658 <!-- ----------------------------------------------------------------- -->
12659 <sect2> Introduction
12661 In this section, we'll learn more about how widgets display themselves
12662 on the screen and interact with events. As an example of this, we'll
12663 create an analog dial widget with a pointer that the user can drag to
12666 <!-- ----------------------------------------------------------------- -->
12667 <sect2> Displaying a widget on the screen
12669 There are several steps that are involved in displaying on the screen.
12670 After the widget is created with a call to <tt/WIDGETNAME_new()/,
12671 several more functions are needed:
12674 <item> <tt/WIDGETNAME_realize()/ is responsible for creating an X
12675 window for the widget if it has one.
12676 <item> <tt/WIDGETNAME_map()/ is invoked after the user calls
12677 <tt/gtk_widget_show()/. It is responsible for making sure the widget
12678 is actually drawn on the screen (<em/mapped/). For a container class,
12679 it must also make calls to <tt/map()/> functions of any child widgets.
12680 <item> <tt/WIDGETNAME_draw()/ is invoked when <tt/gtk_widget_draw()/
12681 is called for the widget or one of its ancestors. It makes the actual
12682 calls to the drawing functions to draw the widget on the screen. For
12683 container widgets, this function must make calls to
12684 <tt/gtk_widget_draw()/ for its child widgets.
12685 <item> <tt/WIDGETNAME_expose()/ is a handler for expose events for the
12686 widget. It makes the necessary calls to the drawing functions to draw
12687 the exposed portion on the screen. For container widgets, this
12688 function must generate expose events for its child widgets which don't
12689 have their own windows. (If they have their own windows, then X will
12690 generate the necessary expose events.)
12693 You might notice that the last two functions are quite similar - each
12694 is responsible for drawing the widget on the screen. In fact many
12695 types of widgets don't really care about the difference between the
12696 two. The default <tt/draw()/ function in the widget class simply
12697 generates a synthetic expose event for the redrawn area. However, some
12698 types of widgets can save work by distinguishing between the two
12699 functions. For instance, if a widget has multiple X windows, then
12700 since expose events identify the exposed window, it can redraw only
12701 the affected window, which is not possible for calls to <tt/draw()/.
12703 Container widgets, even if they don't care about the difference for
12704 themselves, can't simply use the default <tt/draw()/ function because
12705 their child widgets might care about the difference. However,
12706 it would be wasteful to duplicate the drawing code between the two
12707 functions. The convention is that such widgets have a function called
12708 <tt/WIDGETNAME_paint()/ that does the actual work of drawing the
12709 widget, that is then called by the <tt/draw()/ and <tt/expose()/
12712 In our example approach, since the dial widget is not a container
12713 widget, and only has a single window, we can take the simplest
12714 approach and use the default <tt/draw()/ function and only implement
12715 an <tt/expose()/ function.
12717 <!-- ----------------------------------------------------------------- -->
12718 <sect2> The origins of the Dial Widget
12720 Just as all land animals are just variants on the first amphibian that
12721 crawled up out of the mud, GTK widgets tend to start off as variants
12722 of some other, previously written widget. Thus, although this section
12723 is entitled "Creating a Widget from Scratch", the Dial widget really
12724 began with the source code for the Range widget. This was picked as a
12725 starting point because it would be nice if our Dial had the same
12726 interface as the Scale widgets which are just specialized descendants
12727 of the Range widget. So, though the source code is presented below in
12728 finished form, it should not be implied that it was written, <em>ab
12729 initio</em> in this fashion. Also, if you aren't yet familiar with
12730 how scale widgets work from the application writer's point of view, it
12731 would be a good idea to look them over before continuing.
12733 <!-- ----------------------------------------------------------------- -->
12736 Quite a bit of our widget should look pretty familiar from the
12737 Tictactoe widget. First, we have a header file:
12740 /* GTK - The GIMP Toolkit
12741 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
12743 * This library is free software; you can redistribute it and/or
12744 * modify it under the terms of the GNU Library General Public
12745 * License as published by the Free Software Foundation; either
12746 * version 2 of the License, or (at your option) any later version.
12748 * This library is distributed in the hope that it will be useful,
12749 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12750 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12751 * Library General Public License for more details.
12753 * You should have received a copy of the GNU Library General Public
12754 * License along with this library; if not, write to the Free
12755 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
12758 #ifndef __GTK_DIAL_H__
12759 #define __GTK_DIAL_H__
12761 #include <gdk/gdk.h>
12762 #include <gtk/gtkadjustment.h>
12763 #include <gtk/gtkwidget.h>
12768 #endif /* __cplusplus */
12771 #define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
12772 #define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
12773 #define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
12776 typedef struct _GtkDial GtkDial;
12777 typedef struct _GtkDialClass GtkDialClass;
12783 /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
12786 /* Button currently pressed or 0 if none */
12789 /* Dimensions of dial components */
12791 gint pointer_width;
12793 /* ID of update timer, or 0 if none */
12796 /* Current angle */
12799 /* Old values from adjustment stored so we know when something changes */
12804 /* The adjustment object that stores the data for this dial */
12805 GtkAdjustment *adjustment;
12808 struct _GtkDialClass
12810 GtkWidgetClass parent_class;
12814 GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
12815 guint gtk_dial_get_type (void);
12816 GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
12817 void gtk_dial_set_update_policy (GtkDial *dial,
12818 GtkUpdateType policy);
12820 void gtk_dial_set_adjustment (GtkDial *dial,
12821 GtkAdjustment *adjustment);
12824 #endif /* __cplusplus */
12827 #endif /* __GTK_DIAL_H__ */
12830 Since there is quite a bit more going on in this widget than the last
12831 one, we have more fields in the data structure, but otherwise things
12832 are pretty similar.
12834 Next, after including header files and declaring a few constants,
12835 we have some functions to provide information about the widget
12841 #include <gtk/gtkmain.h>
12842 #include <gtk/gtksignal.h>
12844 #include "gtkdial.h"
12846 #define SCROLL_DELAY_LENGTH 300
12847 #define DIAL_DEFAULT_SIZE 100
12849 /* Forward declarations */
12851 [ omitted to save space ]
12855 static GtkWidgetClass *parent_class = NULL;
12858 gtk_dial_get_type ()
12860 static guint dial_type = 0;
12864 GtkTypeInfo dial_info =
12868 sizeof (GtkDialClass),
12869 (GtkClassInitFunc) gtk_dial_class_init,
12870 (GtkObjectInitFunc) gtk_dial_init,
12871 (GtkArgSetFunc) NULL,
12872 (GtkArgGetFunc) NULL,
12875 dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info);
12882 gtk_dial_class_init (GtkDialClass *class)
12884 GtkObjectClass *object_class;
12885 GtkWidgetClass *widget_class;
12887 object_class = (GtkObjectClass*) class;
12888 widget_class = (GtkWidgetClass*) class;
12890 parent_class = gtk_type_class (gtk_widget_get_type ());
12892 object_class->destroy = gtk_dial_destroy;
12894 widget_class->realize = gtk_dial_realize;
12895 widget_class->expose_event = gtk_dial_expose;
12896 widget_class->size_request = gtk_dial_size_request;
12897 widget_class->size_allocate = gtk_dial_size_allocate;
12898 widget_class->button_press_event = gtk_dial_button_press;
12899 widget_class->button_release_event = gtk_dial_button_release;
12900 widget_class->motion_notify_event = gtk_dial_motion_notify;
12904 gtk_dial_init (GtkDial *dial)
12907 dial->policy = GTK_UPDATE_CONTINUOUS;
12910 dial->pointer_width = 0;
12912 dial->old_value = 0.0;
12913 dial->old_lower = 0.0;
12914 dial->old_upper = 0.0;
12915 dial->adjustment = NULL;
12919 gtk_dial_new (GtkAdjustment *adjustment)
12923 dial = gtk_type_new (gtk_dial_get_type ());
12926 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
12928 gtk_dial_set_adjustment (dial, adjustment);
12930 return GTK_WIDGET (dial);
12934 gtk_dial_destroy (GtkObject *object)
12938 g_return_if_fail (object != NULL);
12939 g_return_if_fail (GTK_IS_DIAL (object));
12941 dial = GTK_DIAL (object);
12943 if (dial->adjustment)
12944 gtk_object_unref (GTK_OBJECT (dial->adjustment));
12946 if (GTK_OBJECT_CLASS (parent_class)->destroy)
12947 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
12951 Note that this <tt/init()/ function does less than for the Tictactoe
12952 widget, since this is not a composite widget, and the <tt/new()/
12953 function does more, since it now has an argument. Also, note that when
12954 we store a pointer to the Adjustment object, we increment its
12955 reference count, (and correspondingly decrement it when we no longer
12956 use it) so that GTK can keep track of when it can be safely destroyed.
12959 Also, there are a few function to manipulate the widget's options:
12963 gtk_dial_get_adjustment (GtkDial *dial)
12965 g_return_val_if_fail (dial != NULL, NULL);
12966 g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
12968 return dial->adjustment;
12972 gtk_dial_set_update_policy (GtkDial *dial,
12973 GtkUpdateType policy)
12975 g_return_if_fail (dial != NULL);
12976 g_return_if_fail (GTK_IS_DIAL (dial));
12978 dial->policy = policy;
12982 gtk_dial_set_adjustment (GtkDial *dial,
12983 GtkAdjustment *adjustment)
12985 g_return_if_fail (dial != NULL);
12986 g_return_if_fail (GTK_IS_DIAL (dial));
12988 if (dial->adjustment)
12990 gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
12991 gtk_object_unref (GTK_OBJECT (dial->adjustment));
12994 dial->adjustment = adjustment;
12995 gtk_object_ref (GTK_OBJECT (dial->adjustment));
12997 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
12998 (GtkSignalFunc) gtk_dial_adjustment_changed,
13000 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
13001 (GtkSignalFunc) gtk_dial_adjustment_value_changed,
13004 dial->old_value = adjustment->value;
13005 dial->old_lower = adjustment->lower;
13006 dial->old_upper = adjustment->upper;
13008 gtk_dial_update (dial);
13012 <sect2> <tt/gtk_dial_realize()/
13015 Now we come to some new types of functions. First, we have a function
13016 that does the work of creating the X window. Notice that a mask is
13017 passed to the function <tt/gdk_window_new()/ which specifies which fields of
13018 the GdkWindowAttr structure actually have data in them (the remaining
13019 fields will be given default values). Also worth noting is the way the
13020 event mask of the widget is created. We call
13021 <tt/gtk_widget_get_events()/ to retrieve the event mask that the user
13022 has specified for this widget (with <tt/gtk_widget_set_events()/), and
13023 add the events that we are interested in ourselves.
13026 After creating the window, we set its style and background, and put a
13027 pointer to the widget in the user data field of the GdkWindow. This
13028 last step allows GTK to dispatch events for this window to the correct
13033 gtk_dial_realize (GtkWidget *widget)
13036 GdkWindowAttr attributes;
13037 gint attributes_mask;
13039 g_return_if_fail (widget != NULL);
13040 g_return_if_fail (GTK_IS_DIAL (widget));
13042 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
13043 dial = GTK_DIAL (widget);
13045 attributes.x = widget->allocation.x;
13046 attributes.y = widget->allocation.y;
13047 attributes.width = widget->allocation.width;
13048 attributes.height = widget->allocation.height;
13049 attributes.wclass = GDK_INPUT_OUTPUT;
13050 attributes.window_type = GDK_WINDOW_CHILD;
13051 attributes.event_mask = gtk_widget_get_events (widget) |
13052 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
13053 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
13054 GDK_POINTER_MOTION_HINT_MASK;
13055 attributes.visual = gtk_widget_get_visual (widget);
13056 attributes.colormap = gtk_widget_get_colormap (widget);
13058 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
13059 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
13061 widget->style = gtk_style_attach (widget->style, widget->window);
13063 gdk_window_set_user_data (widget->window, widget);
13065 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
13069 <sect2> Size negotiation
13072 Before the first time that the window containing a widget is
13073 displayed, and whenever the layout of the window changes, GTK asks
13074 each child widget for its desired size. This request is handled by the
13075 function <tt/gtk_dial_size_request()/. Since our widget isn't a
13076 container widget, and has no real constraints on its size, we just
13077 return a reasonable default value.
13081 gtk_dial_size_request (GtkWidget *widget,
13082 GtkRequisition *requisition)
13084 requisition->width = DIAL_DEFAULT_SIZE;
13085 requisition->height = DIAL_DEFAULT_SIZE;
13090 After all the widgets have requested an ideal size, the layout of the
13091 window is computed and each child widget is notified of its actual
13092 size. Usually, this will be at least as large as the requested size,
13093 but if for instance the user has resized the window, it may
13094 occasionally be smaller than the requested size. The size notification
13095 is handled by the function <tt/gtk_dial_size_allocate()/. Notice that
13096 as well as computing the sizes of some component pieces for future
13097 use, this routine also does the grunt work of moving the widget's X
13098 window into the new position and size.
13102 gtk_dial_size_allocate (GtkWidget *widget,
13103 GtkAllocation *allocation)
13107 g_return_if_fail (widget != NULL);
13108 g_return_if_fail (GTK_IS_DIAL (widget));
13109 g_return_if_fail (allocation != NULL);
13111 widget->allocation = *allocation;
13112 if (GTK_WIDGET_REALIZED (widget))
13114 dial = GTK_DIAL (widget);
13116 gdk_window_move_resize (widget->window,
13117 allocation->x, allocation->y,
13118 allocation->width, allocation->height);
13120 dial->radius = MAX(allocation->width,allocation->height) * 0.45;
13121 dial->pointer_width = dial->radius / 5;
13126 <!-- ----------------------------------------------------------------- -->
13127 <sect2> <tt/gtk_dial_expose()/
13130 As mentioned above, all the drawing of this widget is done in the
13131 handler for expose events. There's not much to remark on here except
13132 the use of the function <tt/gtk_draw_polygon/ to draw the pointer with
13133 three dimensional shading according to the colors stored in the
13138 gtk_dial_expose (GtkWidget *widget,
13139 GdkEventExpose *event)
13142 GdkPoint points[3];
13149 g_return_val_if_fail (widget != NULL, FALSE);
13150 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13151 g_return_val_if_fail (event != NULL, FALSE);
13153 if (event->count > 0)
13156 dial = GTK_DIAL (widget);
13158 gdk_window_clear_area (widget->window,
13160 widget->allocation.width,
13161 widget->allocation.height);
13163 xc = widget->allocation.width/2;
13164 yc = widget->allocation.height/2;
13168 for (i=0; i<25; i++)
13170 theta = (i*M_PI/18. - M_PI/6.);
13174 tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
13176 gdk_draw_line (widget->window,
13177 widget->style->fg_gc[widget->state],
13178 xc + c*(dial->radius - tick_length),
13179 yc - s*(dial->radius - tick_length),
13180 xc + c*dial->radius,
13181 yc - s*dial->radius);
13186 s = sin(dial->angle);
13187 c = cos(dial->angle);
13190 points[0].x = xc + s*dial->pointer_width/2;
13191 points[0].y = yc + c*dial->pointer_width/2;
13192 points[1].x = xc + c*dial->radius;
13193 points[1].y = yc - s*dial->radius;
13194 points[2].x = xc - s*dial->pointer_width/2;
13195 points[2].y = yc - c*dial->pointer_width/2;
13197 gtk_draw_polygon (widget->style,
13208 <!-- ----------------------------------------------------------------- -->
13209 <sect2> Event handling
13211 The rest of the widget's code handles various types of events, and
13212 isn't too different from what would be found in many GTK
13213 applications. Two types of events can occur - either the user can
13214 click on the widget with the mouse and drag to move the pointer, or
13215 the value of the Adjustment object can change due to some external
13218 When the user clicks on the widget, we check to see if the click was
13219 appropriately near the pointer, and if so, store the button that the
13220 user clicked with in the <tt/button/ field of the widget
13221 structure, and grab all mouse events with a call to
13222 <tt/gtk_grab_add()/. Subsequent motion of the mouse causes the
13223 value of the control to be recomputed (by the function
13224 <tt/gtk_dial_update_mouse/). Depending on the policy that has been
13225 set, "value_changed" events are either generated instantly
13226 (<tt/GTK_UPDATE_CONTINUOUS/), after a delay in a timer added with
13227 <tt/gtk_timeout_add()/ (<tt/GTK_UPDATE_DELAYED/), or only when the
13228 button is released (<tt/GTK_UPDATE_DISCONTINUOUS/).
13232 gtk_dial_button_press (GtkWidget *widget,
13233 GdkEventButton *event)
13239 double d_perpendicular;
13241 g_return_val_if_fail (widget != NULL, FALSE);
13242 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13243 g_return_val_if_fail (event != NULL, FALSE);
13245 dial = GTK_DIAL (widget);
13247 /* Determine if button press was within pointer region - we
13248 do this by computing the parallel and perpendicular distance of
13249 the point where the mouse was pressed from the line passing through
13252 dx = event->x - widget->allocation.width / 2;
13253 dy = widget->allocation.height / 2 - event->y;
13255 s = sin(dial->angle);
13256 c = cos(dial->angle);
13258 d_parallel = s*dy + c*dx;
13259 d_perpendicular = fabs(s*dx - c*dy);
13261 if (!dial->button &&
13262 (d_perpendicular < dial->pointer_width/2) &&
13263 (d_parallel > - dial->pointer_width))
13265 gtk_grab_add (widget);
13267 dial->button = event->button;
13269 gtk_dial_update_mouse (dial, event->x, event->y);
13276 gtk_dial_button_release (GtkWidget *widget,
13277 GdkEventButton *event)
13281 g_return_val_if_fail (widget != NULL, FALSE);
13282 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13283 g_return_val_if_fail (event != NULL, FALSE);
13285 dial = GTK_DIAL (widget);
13287 if (dial->button == event->button)
13289 gtk_grab_remove (widget);
13293 if (dial->policy == GTK_UPDATE_DELAYED)
13294 gtk_timeout_remove (dial->timer);
13296 if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
13297 (dial->old_value != dial->adjustment->value))
13298 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13305 gtk_dial_motion_notify (GtkWidget *widget,
13306 GdkEventMotion *event)
13309 GdkModifierType mods;
13312 g_return_val_if_fail (widget != NULL, FALSE);
13313 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13314 g_return_val_if_fail (event != NULL, FALSE);
13316 dial = GTK_DIAL (widget);
13318 if (dial->button != 0)
13323 if (event->is_hint || (event->window != widget->window))
13324 gdk_window_get_pointer (widget->window, &x, &y, &mods);
13326 switch (dial->button)
13329 mask = GDK_BUTTON1_MASK;
13332 mask = GDK_BUTTON2_MASK;
13335 mask = GDK_BUTTON3_MASK;
13343 gtk_dial_update_mouse (dial, x,y);
13350 gtk_dial_timer (GtkDial *dial)
13352 g_return_val_if_fail (dial != NULL, FALSE);
13353 g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
13355 if (dial->policy == GTK_UPDATE_DELAYED)
13356 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13362 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
13367 g_return_if_fail (dial != NULL);
13368 g_return_if_fail (GTK_IS_DIAL (dial));
13370 xc = GTK_WIDGET(dial)->allocation.width / 2;
13371 yc = GTK_WIDGET(dial)->allocation.height / 2;
13373 old_value = dial->adjustment->value;
13374 dial->angle = atan2(yc-y, x-xc);
13376 if (dial->angle < -M_PI/2.)
13377 dial->angle += 2*M_PI;
13379 if (dial->angle < -M_PI/6)
13380 dial->angle = -M_PI/6;
13382 if (dial->angle > 7.*M_PI/6.)
13383 dial->angle = 7.*M_PI/6.;
13385 dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
13386 (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
13388 if (dial->adjustment->value != old_value)
13390 if (dial->policy == GTK_UPDATE_CONTINUOUS)
13392 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13396 gtk_widget_draw (GTK_WIDGET(dial), NULL);
13398 if (dial->policy == GTK_UPDATE_DELAYED)
13401 gtk_timeout_remove (dial->timer);
13403 dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
13404 (GtkFunction) gtk_dial_timer,
13412 Changes to the Adjustment by external means are communicated to our
13413 widget by the "changed" and "value_changed" signals. The handlers
13414 for these functions call <tt/gtk_dial_update()/ to validate the
13415 arguments, compute the new pointer angle, and redraw the widget (by
13416 calling <tt/gtk_widget_draw()/).
13420 gtk_dial_update (GtkDial *dial)
13424 g_return_if_fail (dial != NULL);
13425 g_return_if_fail (GTK_IS_DIAL (dial));
13427 new_value = dial->adjustment->value;
13429 if (new_value < dial->adjustment->lower)
13430 new_value = dial->adjustment->lower;
13432 if (new_value > dial->adjustment->upper)
13433 new_value = dial->adjustment->upper;
13435 if (new_value != dial->adjustment->value)
13437 dial->adjustment->value = new_value;
13438 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13441 dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
13442 (dial->adjustment->upper - dial->adjustment->lower);
13444 gtk_widget_draw (GTK_WIDGET(dial), NULL);
13448 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
13453 g_return_if_fail (adjustment != NULL);
13454 g_return_if_fail (data != NULL);
13456 dial = GTK_DIAL (data);
13458 if ((dial->old_value != adjustment->value) ||
13459 (dial->old_lower != adjustment->lower) ||
13460 (dial->old_upper != adjustment->upper))
13462 gtk_dial_update (dial);
13464 dial->old_value = adjustment->value;
13465 dial->old_lower = adjustment->lower;
13466 dial->old_upper = adjustment->upper;
13471 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
13476 g_return_if_fail (adjustment != NULL);
13477 g_return_if_fail (data != NULL);
13479 dial = GTK_DIAL (data);
13481 if (dial->old_value != adjustment->value)
13483 gtk_dial_update (dial);
13485 dial->old_value = adjustment->value;
13490 <!-- ----------------------------------------------------------------- -->
13491 <sect2> Possible Enhancements
13493 The Dial widget as we've described it so far runs about 670 lines of
13494 code. Although that might sound like a fair bit, we've really
13495 accomplished quite a bit with that much code, especially since much of
13496 that length is headers and boilerplate. However, there are quite a few
13497 more enhancements that could be made to this widget:
13500 <item> If you try this widget out, you'll find that there is some
13501 flashing as the pointer is dragged around. This is because the entire
13502 widget is erased every time the pointer is moved before being
13503 redrawn. Often, the best way to handle this problem is to draw to an
13504 offscreen pixmap, then copy the final results onto the screen in one
13505 step. (The ProgressBar widget draws itself in this fashion.)
13507 <item> The user should be able to use the up and down arrow keys to
13508 increase and decrease the value.
13510 <item> It would be nice if the widget had buttons to increase and
13511 decrease the value in small or large steps. Although it would be
13512 possible to use embedded Button widgets for this, we would also like
13513 the buttons to auto-repeat when held down, as the arrows on a
13514 scrollbar do. Most of the code to implement this type of behavior can
13515 be found in the Range widget.
13517 <item> The Dial widget could be made into a container widget with a
13518 single child widget positioned at the bottom between the buttons
13519 mentioned above. The user could then add their choice of a label or
13520 entry widget to display the current value of the dial.
13524 <!-- ----------------------------------------------------------------- -->
13525 <sect1> Learning More
13528 Only a small part of the many details involved in creating widgets
13529 could be described above. If you want to write your own widgets, the
13530 best source of examples is the GTK source itself. Ask yourself some
13531 questions about the widget you want to write: IS it a Container
13532 widget? Does it have its own window? Is it a modification of an
13533 existing widget? Then find a similar widget, and start making changes.
13536 <!-- ***************************************************************** -->
13537 <sect>Scribble, A Simple Example Drawing Program
13538 <!-- ***************************************************************** -->
13540 <!-- ----------------------------------------------------------------- -->
13543 In this section, we will build a simple drawing program. In the
13544 process, we will examine how to handle mouse events, how to draw in a
13545 window, and how to do drawing better by using a backing pixmap. After
13546 creating the simple drawing program, we will extend it by adding
13547 support for XInput devices, such as drawing tablets. GTK provides
13548 support routines which makes getting extended information, such as
13549 pressure and tilt, from such devices quite easy.
13551 <!-- ----------------------------------------------------------------- -->
13552 <sect1> Event Handling
13554 The GTK signals we have already discussed are for high-level actions,
13555 such as a menu item being selected. However, sometimes it is useful to
13556 learn about lower-level occurrences, such as the mouse being moved, or
13557 a key being pressed. There are also GTK signals corresponding to these
13558 low-level <em>events</em>. The handlers for these signals have an
13559 extra parameter which is a pointer to a structure containing
13560 information about the event. For instance, motion event handlers are
13561 passed a pointer to a GdkEventMotion structure which looks (in part)
13565 struct _GdkEventMotion
13578 <tt/type/ will be set to the event type, in this case
13579 <tt/GDK_MOTION_NOTIFY/, window is the window in which the event
13580 occurred. <tt/x/ and <tt/y/ give the coordinates of the event.
13581 <tt/state/ specifies the modifier state when the event
13582 occurred (that is, it specifies which modifier keys and mouse buttons
13583 were pressed). It is the bitwise OR of some of the following:
13601 As for other signals, to determine what happens when an event occurs
13602 we call <tt>gtk_signal_connect()</tt>. But we also need let GTK
13603 know which events we want to be notified about. To do this, we call
13607 void gtk_widget_set_events (GtkWidget *widget,
13611 The second field specifies the events we are interested in. It
13612 is the bitwise OR of constants that specify different types
13613 of events. For future reference the event types are:
13617 GDK_POINTER_MOTION_MASK
13618 GDK_POINTER_MOTION_HINT_MASK
13619 GDK_BUTTON_MOTION_MASK
13620 GDK_BUTTON1_MOTION_MASK
13621 GDK_BUTTON2_MOTION_MASK
13622 GDK_BUTTON3_MOTION_MASK
13623 GDK_BUTTON_PRESS_MASK
13624 GDK_BUTTON_RELEASE_MASK
13626 GDK_KEY_RELEASE_MASK
13627 GDK_ENTER_NOTIFY_MASK
13628 GDK_LEAVE_NOTIFY_MASK
13629 GDK_FOCUS_CHANGE_MASK
13631 GDK_PROPERTY_CHANGE_MASK
13632 GDK_PROXIMITY_IN_MASK
13633 GDK_PROXIMITY_OUT_MASK
13636 There are a few subtle points that have to be observed when calling
13637 <tt/gtk_widget_set_events()/. First, it must be called before the X window
13638 for a GTK widget is created. In practical terms, this means you
13639 should call it immediately after creating the widget. Second, the
13640 widget must have an associated X window. For efficiency, many widget
13641 types do not have their own window, but draw in their parent's window.
13664 To capture events for these widgets, you need to use an EventBox
13665 widget. See the section on the <ref id="sec_EventBox"
13666 name="EventBox"> widget for details.
13668 For our drawing program, we want to know when the mouse button is
13669 pressed and when the mouse is moved, so we specify
13670 <tt/GDK_POINTER_MOTION_MASK/ and <tt/GDK_BUTTON_PRESS_MASK/. We also
13671 want to know when we need to redraw our window, so we specify
13672 <tt/GDK_EXPOSURE_MASK/. Although we want to be notified via a
13673 Configure event when our window size changes, we don't have to specify
13674 the corresponding <tt/GDK_STRUCTURE_MASK/ flag, because it is
13675 automatically specified for all windows.
13677 It turns out, however, that there is a problem with just specifying
13678 <tt/GDK_POINTER_MOTION_MASK/. This will cause the server to add a new
13679 motion event to the event queue every time the user moves the mouse.
13680 Imagine that it takes us 0.1 seconds to handle a motion event, but the
13681 X server queues a new motion event every 0.05 seconds. We will soon
13682 get way behind the users drawing. If the user draws for 5 seconds,
13683 it will take us another 5 seconds to catch up after they release
13684 the mouse button! What we would like is to only get one motion
13685 event for each event we process. The way to do this is to
13686 specify <tt/GDK_POINTER_MOTION_HINT_MASK/.
13688 When we specify <tt/GDK_POINTER_MOTION_HINT_MASK/, the server sends
13689 us a motion event the first time the pointer moves after entering
13690 our window, or after a button press or release event. Subsequent
13691 motion events will be suppressed until we explicitly ask for
13692 the position of the pointer using the function:
13695 GdkWindow* gdk_window_get_pointer (GdkWindow *window,
13698 GdkModifierType *mask);
13701 (There is another function, <tt>gtk_widget_get_pointer()</tt> which
13702 has a simpler interface, but turns out not to be very useful, since
13703 it only retrieves the position of the mouse, not whether the buttons
13706 The code to set the events for our window then looks like:
13709 gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
13710 (GtkSignalFunc) expose_event, NULL);
13711 gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
13712 (GtkSignalFunc) configure_event, NULL);
13713 gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
13714 (GtkSignalFunc) motion_notify_event, NULL);
13715 gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
13716 (GtkSignalFunc) button_press_event, NULL);
13718 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
13719 | GDK_LEAVE_NOTIFY_MASK
13720 | GDK_BUTTON_PRESS_MASK
13721 | GDK_POINTER_MOTION_MASK
13722 | GDK_POINTER_MOTION_HINT_MASK);
13725 We'll save the "expose_event" and "configure_event" handlers for
13726 later. The "motion_notify_event" and "button_press_event" handlers
13731 button_press_event (GtkWidget *widget, GdkEventButton *event)
13733 if (event->button == 1 && pixmap != NULL)
13734 draw_brush (widget, event->x, event->y);
13740 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
13743 GdkModifierType state;
13745 if (event->is_hint)
13746 gdk_window_get_pointer (event->window, &x, &y, &state);
13751 state = event->state;
13754 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
13755 draw_brush (widget, x, y);
13761 <!-- ----------------------------------------------------------------- -->
13762 <sect1> The DrawingArea Widget, And Drawing
13764 We now turn to the process of drawing on the screen. The
13765 widget we use for this is the DrawingArea widget. A drawing area
13766 widget is essentially an X window and nothing more. It is a blank
13767 canvas in which we can draw whatever we like. A drawing area
13768 is created using the call:
13771 GtkWidget* gtk_drawing_area_new (void);
13774 A default size for the widget can be specified by calling:
13777 void gtk_drawing_area_size (GtkDrawingArea *darea,
13782 This default size can be overridden, as is true for all widgets,
13783 by calling <tt>gtk_widget_set_usize()</tt>, and that, in turn, can
13784 be overridden if the user manually resizes the the window containing
13787 It should be noted that when we create a DrawingArea widget, we are
13788 <em>completely</em> responsible for drawing the contents. If our
13789 window is obscured then uncovered, we get an exposure event and must
13790 redraw what was previously hidden.
13792 Having to remember everything that was drawn on the screen so we
13793 can properly redraw it can, to say the least, be a nuisance. In
13794 addition, it can be visually distracting if portions of the
13795 window are cleared, then redrawn step by step. The solution to
13796 this problem is to use an offscreen <em>backing pixmap</em>.
13797 Instead of drawing directly to the screen, we draw to an image
13798 stored in server memory but not displayed, then when the image
13799 changes or new portions of the image are displayed, we copy the
13800 relevant portions onto the screen.
13802 To create an offscreen pixmap, we call the function:
13805 GdkPixmap* gdk_pixmap_new (GdkWindow *window,
13811 The <tt>window</tt> parameter specifies a GDK window that this pixmap
13812 takes some of its properties from. <tt>width</tt> and <tt>height</tt>
13813 specify the size of the pixmap. <tt>depth</tt> specifies the <em>color
13814 depth</em>, that is the number of bits per pixel, for the new window.
13815 If the depth is specified as <tt>-1</tt>, it will match the depth
13816 of <tt>window</tt>.
13818 We create the pixmap in our "configure_event" handler. This event
13819 is generated whenever the window changes size, including when it
13820 is originally created.
13823 /* Backing pixmap for drawing area */
13824 static GdkPixmap *pixmap = NULL;
13826 /* Create a new backing pixmap of the appropriate size */
13828 configure_event (GtkWidget *widget, GdkEventConfigure *event)
13831 gdk_pixmap_unref(pixmap);
13833 pixmap = gdk_pixmap_new(widget->window,
13834 widget->allocation.width,
13835 widget->allocation.height,
13837 gdk_draw_rectangle (pixmap,
13838 widget->style->white_gc,
13841 widget->allocation.width,
13842 widget->allocation.height);
13848 The call to <tt>gdk_draw_rectangle()</tt> clears the pixmap
13849 initially to white. We'll say more about that in a moment.
13851 Our exposure event handler then simply copies the relevant portion
13852 of the pixmap onto the screen (we determine the area we need
13853 to redraw by using the event->area field of the exposure event):
13856 /* Redraw the screen from the backing pixmap */
13858 expose_event (GtkWidget *widget, GdkEventExpose *event)
13860 gdk_draw_pixmap(widget->window,
13861 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
13863 event->area.x, event->area.y,
13864 event->area.x, event->area.y,
13865 event->area.width, event->area.height);
13871 We've now seen how to keep the screen up to date with our pixmap, but
13872 how do we actually draw interesting stuff on our pixmap? There are a
13873 large number of calls in GTK's GDK library for drawing on
13874 <em>drawables</em>. A drawable is simply something that can be drawn
13875 upon. It can be a window, a pixmap, or a bitmap (a black and white
13876 image). We've already seen two such calls above,
13877 <tt>gdk_draw_rectangle()</tt> and <tt>gdk_draw_pixmap()</tt>. The
13882 gdk_draw_rectangle ()
13884 gdk_draw_polygon ()
13891 gdk_draw_segments ()
13894 See the reference documentation or the header file
13895 <tt><gdk/gdk.h></tt> for further details on these functions.
13896 These functions all share the same first two arguments. The first
13897 argument is the drawable to draw upon, the second argument is a
13898 <em>graphics context</em> (GC).
13900 A graphics context encapsulates information about things such as
13901 foreground and background color and line width. GDK has a full set of
13902 functions for creating and modifying graphics contexts, but to keep
13903 things simple we'll just use predefined graphics contexts. Each widget
13904 has an associated style. (Which can be modified in a gtkrc file, see
13905 the section GTK's rc file.) This, among other things, stores a number
13906 of graphics contexts. Some examples of accessing these graphics
13910 widget->style->white_gc
13911 widget->style->black_gc
13912 widget->style->fg_gc[GTK_STATE_NORMAL]
13913 widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
13916 The fields <tt>fg_gc</tt>, <tt>bg_gc</tt>, <tt>dark_gc</tt>, and
13917 <tt>light_gc</tt> are indexed by a parameter of type
13918 <tt>GtkStateType</tt> which can take on the values:
13923 GTK_STATE_PRELIGHT,
13924 GTK_STATE_SELECTED,
13925 GTK_STATE_INSENSITIVE
13928 For instance, for <tt/GTK_STATE_SELECTED/ the default foreground
13929 color is white and the default background color, dark blue.
13931 Our function <tt>draw_brush()</tt>, which does the actual drawing
13932 on the screen, is then:
13935 /* Draw a rectangle on the screen */
13937 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
13939 GdkRectangle update_rect;
13941 update_rect.x = x - 5;
13942 update_rect.y = y - 5;
13943 update_rect.width = 10;
13944 update_rect.height = 10;
13945 gdk_draw_rectangle (pixmap,
13946 widget->style->black_gc,
13948 update_rect.x, update_rect.y,
13949 update_rect.width, update_rect.height);
13950 gtk_widget_draw (widget, &update_rect);
13954 After we draw the rectangle representing the brush onto the pixmap,
13955 we call the function:
13958 void gtk_widget_draw (GtkWidget *widget,
13959 GdkRectangle *area);
13962 which notifies X that the area given by the <tt>area</tt> parameter
13963 needs to be updated. X will eventually generate an expose event
13964 (possibly combining the areas passed in several calls to
13965 <tt>gtk_widget_draw()</tt>) which will cause our expose event handler
13966 to copy the relevant portions to the screen.
13968 We have now covered the entire drawing program except for a few
13969 mundane details like creating the main window. The complete
13970 source code is available from the location from which you got
13971 this tutorial, or from:
13973 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
13974 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
13977 <!-- ----------------------------------------------------------------- -->
13978 <sect1> Adding XInput support
13980 It is now possible to buy quite inexpensive input devices such
13981 as drawing tablets, which allow drawing with a much greater
13982 ease of artistic expression than does a mouse. The simplest way
13983 to use such devices is simply as a replacement for the mouse,
13984 but that misses out many of the advantages of these devices,
13988 <item> Pressure sensitivity
13989 <item> Tilt reporting
13990 <item> Sub-pixel positioning
13991 <item> Multiple inputs (for example, a stylus with a point and eraser)
13994 For information about the XInput extension, see the <htmlurl
13995 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
13996 name="XInput-HOWTO">.
13998 If we examine the full definition of, for example, the GdkEventMotion
13999 structure, we see that it has fields to support extended device
14003 struct _GdkEventMotion
14015 GdkInputSource source;
14020 <tt/pressure/ gives the pressure as a floating point number between
14021 0 and 1. <tt/xtilt/ and <tt/ytilt/ can take on values between
14022 -1 and 1, corresponding to the degree of tilt in each direction.
14023 <tt/source/ and <tt/deviceid/ specify the device for which the
14024 event occurred in two different ways. <tt/source/ gives some simple
14025 information about the type of device. It can take the enumeration
14035 <tt/deviceid/ specifies a unique numeric ID for the device. This can
14036 be used to find out further information about the device using the
14037 <tt/gdk_input_list_devices()/ call (see below). The special value
14038 <tt/GDK_CORE_POINTER/ is used for the core pointer device. (Usually
14041 <sect2> Enabling extended device information
14043 To let GTK know about our interest in the extended device information,
14044 we merely have to add a single line to our program:
14047 gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
14050 By giving the value <tt/GDK_EXTENSION_EVENTS_CURSOR/ we say that
14051 we are interested in extension events, but only if we don't have
14052 to draw our own cursor. See the section <ref
14053 id="sec_Further_Sophistications" name="Further Sophistications"> below
14054 for more information about drawing the cursor. We could also
14055 give the values <tt/GDK_EXTENSION_EVENTS_ALL/ if we were willing
14056 to draw our own cursor, or <tt/GDK_EXTENSION_EVENTS_NONE/ to revert
14057 back to the default condition.
14059 This is not completely the end of the story however. By default,
14060 no extension devices are enabled. We need a mechanism to allow
14061 users to enable and configure their extension devices. GTK provides
14062 the InputDialog widget to automate this process. The following
14063 procedure manages an InputDialog widget. It creates the dialog if
14064 it isn't present, and raises it to the top otherwise.
14068 input_dialog_destroy (GtkWidget *w, gpointer data)
14070 *((GtkWidget **)data) = NULL;
14074 create_input_dialog ()
14076 static GtkWidget *inputd = NULL;
14080 inputd = gtk_input_dialog_new();
14082 gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
14083 (GtkSignalFunc)input_dialog_destroy, &inputd);
14084 gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
14086 (GtkSignalFunc)gtk_widget_hide,
14087 GTK_OBJECT(inputd));
14088 gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
14090 gtk_widget_show (inputd);
14094 if (!GTK_WIDGET_MAPPED(inputd))
14095 gtk_widget_show(inputd);
14097 gdk_window_raise(inputd->window);
14102 (You might want to take note of the way we handle this dialog. By
14103 connecting to the "destroy" signal, we make sure that we don't keep a
14104 pointer to dialog around after it is destroyed - that could lead to a
14107 The InputDialog has two buttons "Close" and "Save", which by default
14108 have no actions assigned to them. In the above function we make
14109 "Close" hide the dialog, hide the "Save" button, since we don't
14110 implement saving of XInput options in this program.
14112 <sect2> Using extended device information
14114 Once we've enabled the device, we can just use the extended
14115 device information in the extra fields of the event structures.
14116 In fact, it is always safe to use this information since these
14117 fields will have reasonable default values even when extended
14118 events are not enabled.
14120 Once change we do have to make is to call
14121 <tt/gdk_input_window_get_pointer()/ instead of
14122 <tt/gdk_window_get_pointer/. This is necessary because
14123 <tt/gdk_window_get_pointer/ doesn't return the extended device
14127 void gdk_input_window_get_pointer( GdkWindow *window,
14134 GdkModifierType *mask);
14137 When calling this function, we need to specify the device ID as
14138 well as the window. Usually, we'll get the device ID from the
14139 <tt/deviceid/ field of an event structure. Again, this function
14140 will return reasonable values when extension events are not
14141 enabled. (In this case, <tt/event->deviceid/ will have the value
14142 <tt/GDK_CORE_POINTER/).
14144 So the basic structure of our button-press and motion event handlers
14145 doesn't change much - we just need to add code to deal with the
14146 extended information.
14150 button_press_event (GtkWidget *widget, GdkEventButton *event)
14152 print_button_press (event->deviceid);
14154 if (event->button == 1 && pixmap != NULL)
14155 draw_brush (widget, event->source, event->x, event->y, event->pressure);
14161 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
14165 GdkModifierType state;
14167 if (event->is_hint)
14168 gdk_input_window_get_pointer (event->window, event->deviceid,
14169 &x, &y, &pressure, NULL, NULL, &state);
14174 pressure = event->pressure;
14175 state = event->state;
14178 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
14179 draw_brush (widget, event->source, x, y, pressure);
14185 We also need to do something with the new information. Our new
14186 <tt/draw_brush()/ function draws with a different color for
14187 each <tt/event->source/ and changes the brush size depending
14191 /* Draw a rectangle on the screen, size depending on pressure,
14192 and color on the type of device */
14194 draw_brush (GtkWidget *widget, GdkInputSource source,
14195 gdouble x, gdouble y, gdouble pressure)
14198 GdkRectangle update_rect;
14202 case GDK_SOURCE_MOUSE:
14203 gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
14205 case GDK_SOURCE_PEN:
14206 gc = widget->style->black_gc;
14208 case GDK_SOURCE_ERASER:
14209 gc = widget->style->white_gc;
14212 gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
14215 update_rect.x = x - 10 * pressure;
14216 update_rect.y = y - 10 * pressure;
14217 update_rect.width = 20 * pressure;
14218 update_rect.height = 20 * pressure;
14219 gdk_draw_rectangle (pixmap, gc, TRUE,
14220 update_rect.x, update_rect.y,
14221 update_rect.width, update_rect.height);
14222 gtk_widget_draw (widget, &update_rect);
14226 <sect2> Finding out more about a device
14228 As an example of how to find out more about a device, our program
14229 will print the name of the device that generates each button
14230 press. To find out the name of a device, we call the function:
14233 GList *gdk_input_list_devices (void);
14236 which returns a GList (a linked list type from the GLib library)
14237 of GdkDeviceInfo structures. The GdkDeviceInfo structure is defined
14241 struct _GdkDeviceInfo
14245 GdkInputSource source;
14251 GdkDeviceKey *keys;
14255 Most of these fields are configuration information that you can ignore
14256 unless you are implementing XInput configuration saving. The fieldwe
14257 are interested in here is <tt/name/ which is simply the name that X
14258 assigns to the device. The other field that isn't configuration
14259 information is <tt/has_cursor/. If <tt/has_cursor/ is false, then we
14260 we need to draw our own cursor. But since we've specified
14261 <tt/GDK_EXTENSION_EVENTS_CURSOR/, we don't have to worry about this.
14263 Our <tt/print_button_press()/ function simply iterates through
14264 the returned list until it finds a match, then prints out
14265 the name of the device.
14269 print_button_press (guint32 deviceid)
14273 /* gdk_input_list_devices returns an internal list, so we shouldn't
14274 free it afterwards */
14275 tmp_list = gdk_input_list_devices();
14279 GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
14281 if (info->deviceid == deviceid)
14283 printf("Button press on device '%s'\n", info->name);
14287 tmp_list = tmp_list->next;
14292 That completes the changes to "XInputize" our program. As with
14293 the first version, the complete source is available at the location
14294 from which you got this tutorial, or from:
14296 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
14297 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
14300 <sect2> Further sophistications <label id="sec_Further_Sophistications">
14302 Although our program now supports XInput quite well, it lacks some
14303 features we would want in a full-featured application. First, the user
14304 probably doesn't want to have to configure their device each time they
14305 run the program, so we should allow them to save the device
14306 configuration. This is done by iterating through the return of
14307 <tt/gdk_input_list_devices()/ and writing out the configuration to a
14310 To restore the state next time the program is run, GDK provides
14311 functions to change device configuration:
14314 gdk_input_set_extension_events()
14315 gdk_input_set_source()
14316 gdk_input_set_mode()
14317 gdk_input_set_axes()
14318 gdk_input_set_key()
14321 (The list returned from <tt/gdk_input_list_devices()/ should not be
14322 modified directly.) An example of doing this can be found in the
14323 drawing program gsumi. (Available from <htmlurl
14324 url="http://www.msc.cornell.edu/~otaylor/gsumi/"
14325 name="http://www.msc.cornell.edu/~otaylor/gsumi/">) Eventually, it
14326 would be nice to have a standard way of doing this for all
14327 applications. This probably belongs at a slightly higher level than
14328 GTK, perhaps in the GNOME library.
14330 Another major omission that we have mentioned above is the lack of
14331 cursor drawing. Platforms other than XFree86 currently do not allow
14332 simultaneously using a device as both the core pointer and directly by
14333 an application. See the <url
14334 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
14335 name="XInput-HOWTO"> for more information about this. This means that
14336 applications that want to support the widest audience need to draw
14339 An application that draws its own cursor needs to do two things:
14340 determine if the current device needs a cursor drawn or not, and
14341 determine if the current device is in proximity. (If the current
14342 device is a drawing tablet, it's a nice touch to make the cursor
14343 disappear when the stylus is lifted from the tablet. When the
14344 device is touching the stylus, that is called "in proximity.")
14345 The first is done by searching the device list, as we did
14346 to find out the device name. The second is achieved by selecting
14347 "proximity_out" events. An example of drawing one's own cursor is
14348 found in the "testinput" program found in the GTK distribution.
14350 <!-- ***************************************************************** -->
14351 <sect>Tips For Writing GTK Applications
14352 <!-- ***************************************************************** -->
14354 This section is simply a gathering of wisdom, general style guidelines
14355 and hints to creating good GTK applications. Currently this section
14356 is very short, but I hope it will get longer in future editions of
14359 Use GNU autoconf and automake! They are your friends :) Automake
14360 examines C files, determines how they depend on each other, and
14361 generates a Makefile so the files can be compiled in the correct
14362 order. Autoconf permits automatic configuration of software
14363 installation, handling a large number of system quirks to increase
14364 portability. I am planning to make a quick intro on them here.
14366 When writing C code, use only C comments (beginning with "/*" and
14367 ending with "*/"), and don't use C++-style comments ("//"). Although
14368 many C compilers understand C++ comments, others don't, and the ANSI C
14369 standard does not require that C++-style comments be processed as
14372 <!-- ***************************************************************** -->
14373 <sect>Contributing <label id="sec_Contributing">
14374 <!-- ***************************************************************** -->
14376 This document, like so much other great software out there, was
14377 created for free by volunteers. If you are at all knowledgeable about
14378 any aspect of GTK that does not already have documentation, please
14379 consider contributing to this document.
14381 If you do decide to contribute, please mail your text to Tony Gale,
14382 <tt><htmlurl url="mailto:gale@gtk.org"
14383 name="gale@gtk.org"></tt>. Also, be aware that the entirety of this
14384 document is free, and any addition by you provide must also be
14385 free. That is, people may use any portion of your examples in their
14386 programs, and copies of this document may be distributed at will, etc.
14390 <!-- ***************************************************************** -->
14392 <!-- ***************************************************************** -->
14394 We would like to thank the following for their contributions to this text.
14397 <item>Bawer Dagdeviren, <tt><htmlurl url="mailto:chamele0n@geocities.com"
14398 name="chamele0n@geocities.com"></tt> for the menus tutorial.
14400 <item>Raph Levien, <tt><htmlurl url="mailto:raph@acm.org"
14401 name="raph@acm.org"></tt>
14402 for hello world ala GTK, widget packing, and general all around wisdom.
14403 He's also generously donated a home for this tutorial.
14405 <item>Peter Mattis, <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
14406 name="petm@xcf.berkeley.edu"></tt> for the simplest GTK program..
14407 and the ability to make it :)
14409 <item>Werner Koch <tt><htmlurl url="mailto:werner.koch@guug.de"
14410 name="werner.koch@guug.de"></tt> for converting the original plain text to
14411 SGML, and the widget class hierarchy.
14413 <item>Mark Crichton <tt><htmlurl
14414 url="mailto:crichton@expert.cc.purdue.edu"
14415 name="crichton@expert.cc.purdue.edu"></tt> for the menu factory code,
14416 and the table packing tutorial.
14418 <item>Owen Taylor <tt><htmlurl url="mailto:owt1@cornell.edu"
14419 name="owt1@cornell.edu"></tt> for the EventBox widget section (and the
14420 patch to the distro). He's also responsible for the selections code
14421 and tutorial, as well as the sections on writing your own GTK widgets,
14422 and the example application. Thanks a lot Owen for all you help!
14424 <item>Mark VanderBoom <tt><htmlurl url="mailto:mvboom42@calvin.edu"
14425 name="mvboom42@calvin.edu"></tt> for his wonderful work on the
14426 Notebook, Progress Bar, Dialogs, and File selection widgets. Thanks a
14427 lot Mark! You've been a great help.
14429 <item>Tim Janik <tt><htmlurl url="mailto:timj@gtk.org"
14430 name="timj@psynet.net"></tt> for his great job on the Lists
14431 Widget. His excellent work on automatically extracting the widget tree
14432 and signal information from GTK. Thanks Tim :)
14434 <item>Rajat Datta <tt><htmlurl url="mailto:rajat@ix.netcom.com"
14435 name="rajat@ix.netcom.com"</tt> for the excellent job on the Pixmap
14438 <item>Michael K. Johnson <tt><htmlurl url="mailto:johnsonm@redhat.com"
14439 name="johnsonm@redhat.com"></tt> for info and code for popup menus.
14441 <item>David Huggins-Daines <tt><htmlurl
14442 url="mailto:bn711@freenet.carleton.ca"
14443 name="bn711@freenet.carleton.ca"></tt> for the Range Widgets and Tree
14446 <item>Stefan Mars <tt><htmlurl url="mailto:mars@lysator.liu.se"
14447 name="mars@lysator.liu.se"></tt> for the CList section.
14449 <item>David A. Wheeler <tt><htmlurl url="mailto:dwheeler@ida.org"
14450 name="dwheeler@ida.org"></tt> for portions of the text on GLib
14451 and various tutorial fixups and improvements.
14452 The GLib text was in turn based on material developed by Damon Chaplin
14453 <tt><htmlurl url="mailto:DAChaplin@msn.com" name="DAChaplin@msn.com"></tt>
14455 <item>David King for style checking this entire document.
14458 And to all of you who commented on and helped refine this document.
14462 <!-- ***************************************************************** -->
14463 <sect> Tutorial Copyright and Permissions Notice
14464 <!-- ***************************************************************** -->
14467 The GTK Tutorial is Copyright (C) 1997 Ian Main.
14469 Copyright (C) 1998-1999 Tony Gale.
14471 Permission is granted to make and distribute verbatim copies of this
14472 manual provided the copyright notice and this permission notice are
14473 preserved on all copies.
14475 Permission is granted to copy and distribute modified versions of
14476 this document under the conditions for verbatim copying, provided that
14477 this copyright notice is included exactly as in the original,
14478 and that the entire resulting derived work is distributed under
14479 the terms of a permission notice identical to this one.
14480 <P>Permission is granted to copy and distribute translations of this
14481 document into another language, under the above conditions for modified
14484 If you are intending to incorporate this document into a published
14485 work, please contact the maintainer, and we will make an effort
14486 to ensure that you have the most up to date information available.
14488 There is no guarantee that this document lives up to its intended
14489 purpose. This is simply provided as a free resource. As such,
14490 the authors and maintainers of the information provided within can
14491 not make any guarantee that the information is even accurate.
14493 <!-- ***************************************************************** -->
14495 <!-- ***************************************************************** -->
14497 <!-- ***************************************************************** -->
14498 <sect> GTK Signals <label id="sec_GTK_Signals">
14499 <!-- ***************************************************************** -->
14501 As GTK is an object oriented widget set, it has a hierarchy of
14502 inheritance. This inheritance mechanism applies for
14503 signals. Therefore, you should refer to the widget hierarchy tree when
14504 using the signals listed in this section.
14506 <!-- ----------------------------------------------------------------- -->
14508 <!-- ----------------------------------------------------------------- -->
14511 void GtkObject::destroy (GtkObject *,
14515 <!-- ----------------------------------------------------------------- -->
14517 <!-- ----------------------------------------------------------------- -->
14521 void GtkWidget::show (GtkWidget *,
14523 void GtkWidget::hide (GtkWidget *,
14525 void GtkWidget::map (GtkWidget *,
14527 void GtkWidget::unmap (GtkWidget *,
14529 void GtkWidget::realize (GtkWidget *,
14531 void GtkWidget::unrealize (GtkWidget *,
14533 void GtkWidget::draw (GtkWidget *,
14536 void GtkWidget::draw-focus (GtkWidget *,
14538 void GtkWidget::draw-default (GtkWidget *,
14540 void GtkWidget::size-request (GtkWidget *,
14543 void GtkWidget::size-allocate (GtkWidget *,
14546 void GtkWidget::state-changed (GtkWidget *,
14549 void GtkWidget::parent-set (GtkWidget *,
14552 void GtkWidget::style-set (GtkWidget *,
14555 void GtkWidget::add-accelerator (GtkWidget *,
14562 void GtkWidget::remove-accelerator (GtkWidget *,
14567 gboolean GtkWidget::event (GtkWidget *,
14570 gboolean GtkWidget::button-press-event (GtkWidget *,
14573 gboolean GtkWidget::button-release-event (GtkWidget *,
14576 gboolean GtkWidget::motion-notify-event (GtkWidget *,
14579 gboolean GtkWidget::delete-event (GtkWidget *,
14582 gboolean GtkWidget::destroy-event (GtkWidget *,
14585 gboolean GtkWidget::expose-event (GtkWidget *,
14588 gboolean GtkWidget::key-press-event (GtkWidget *,
14591 gboolean GtkWidget::key-release-event (GtkWidget *,
14594 gboolean GtkWidget::enter-notify-event (GtkWidget *,
14597 gboolean GtkWidget::leave-notify-event (GtkWidget *,
14600 gboolean GtkWidget::configure-event (GtkWidget *,
14603 gboolean GtkWidget::focus-in-event (GtkWidget *,
14606 gboolean GtkWidget::focus-out-event (GtkWidget *,
14609 gboolean GtkWidget::map-event (GtkWidget *,
14612 gboolean GtkWidget::unmap-event (GtkWidget *,
14615 gboolean GtkWidget::property-notify-event (GtkWidget *,
14618 gboolean GtkWidget::selection-clear-event (GtkWidget *,
14621 gboolean GtkWidget::selection-request-event (GtkWidget *,
14624 gboolean GtkWidget::selection-notify-event (GtkWidget *,
14627 void GtkWidget::selection-get (GtkWidget *,
14628 GtkSelectionData *,
14631 void GtkWidget::selection-received (GtkWidget *,
14632 GtkSelectionData *,
14635 gboolean GtkWidget::proximity-in-event (GtkWidget *,
14638 gboolean GtkWidget::proximity-out-event (GtkWidget *,
14641 void GtkWidget::drag-begin (GtkWidget *,
14644 void GtkWidget::drag-end (GtkWidget *,
14647 void GtkWidget::drag-data-delete (GtkWidget *,
14650 void GtkWidget::drag-leave (GtkWidget *,
14654 gboolean GtkWidget::drag-motion (GtkWidget *,
14660 gboolean GtkWidget::drag-drop (GtkWidget *,
14666 void GtkWidget::drag-data-get (GtkWidget *,
14668 GtkSelectionData *,
14672 void GtkWidget::drag-data-received (GtkWidget *,
14676 GtkSelectionData *,
14680 gboolean GtkWidget::client-event (GtkWidget *,
14683 gboolean GtkWidget::no-expose-event (GtkWidget *,
14686 gboolean GtkWidget::visibility-notify-event (GtkWidget *,
14689 void GtkWidget::debug-msg (GtkWidget *,
14694 <!-- ----------------------------------------------------------------- -->
14696 <!-- ----------------------------------------------------------------- -->
14699 void GtkData::disconnect (GtkData *,
14703 <!-- ----------------------------------------------------------------- -->
14704 <sect1>GtkContainer
14705 <!-- ----------------------------------------------------------------- -->
14708 void GtkContainer::add (GtkContainer *,
14711 void GtkContainer::remove (GtkContainer *,
14714 void GtkContainer::check-resize (GtkContainer *,
14716 GtkDirectionType GtkContainer::focus (GtkContainer *,
14719 void GtkContainer::set-focus-child (GtkContainer *,
14724 <!-- ----------------------------------------------------------------- -->
14726 <!-- ----------------------------------------------------------------- -->
14729 void GtkCalendar::month-changed (GtkCalendar *,
14731 void GtkCalendar::day-selected (GtkCalendar *,
14733 void GtkCalendar::day-selected-double-click (GtkCalendar *,
14735 void GtkCalendar::prev-month (GtkCalendar *,
14737 void GtkCalendar::next-month (GtkCalendar *,
14739 void GtkCalendar::prev-year (GtkCalendar *,
14741 void GtkCalendar::next-year (GtkCalendar *,
14745 <!-- ----------------------------------------------------------------- -->
14747 <!-- ----------------------------------------------------------------- -->
14750 void GtkEditable::changed (GtkEditable *,
14752 void GtkEditable::insert-text (GtkEditable *,
14757 void GtkEditable::delete-text (GtkEditable *,
14761 void GtkEditable::activate (GtkEditable *,
14763 void GtkEditable::set-editable (GtkEditable *,
14766 void GtkEditable::move-cursor (GtkEditable *,
14770 void GtkEditable::move-word (GtkEditable *,
14773 void GtkEditable::move-page (GtkEditable *,
14777 void GtkEditable::move-to-row (GtkEditable *,
14780 void GtkEditable::move-to-column (GtkEditable *,
14783 void GtkEditable::kill-char (GtkEditable *,
14786 void GtkEditable::kill-word (GtkEditable *,
14789 void GtkEditable::kill-line (GtkEditable *,
14792 void GtkEditable::cut-clipboard (GtkEditable *,
14794 void GtkEditable::copy-clipboard (GtkEditable *,
14796 void GtkEditable::paste-clipboard (GtkEditable *,
14800 <!-- ----------------------------------------------------------------- -->
14801 <sect1>GtkTipsQuery
14802 <!-- ----------------------------------------------------------------- -->
14805 void GtkTipsQuery::start-query (GtkTipsQuery *,
14807 void GtkTipsQuery::stop-query (GtkTipsQuery *,
14809 void GtkTipsQuery::widget-entered (GtkTipsQuery *,
14814 gboolean GtkTipsQuery::widget-selected (GtkTipsQuery *,
14822 <!-- ----------------------------------------------------------------- -->
14824 <!-- ----------------------------------------------------------------- -->
14827 void GtkCList::select-row (GtkCList *,
14832 void GtkCList::unselect-row (GtkCList *,
14837 void GtkCList::row-move (GtkCList *,
14841 void GtkCList::click-column (GtkCList *,
14844 void GtkCList::resize-column (GtkCList *,
14848 void GtkCList::toggle-focus-row (GtkCList *,
14850 void GtkCList::select-all (GtkCList *,
14852 void GtkCList::unselect-all (GtkCList *,
14854 void GtkCList::undo-selection (GtkCList *,
14856 void GtkCList::start-selection (GtkCList *,
14858 void GtkCList::end-selection (GtkCList *,
14860 void GtkCList::toggle-add-mode (GtkCList *,
14862 void GtkCList::extend-selection (GtkCList *,
14867 void GtkCList::scroll-vertical (GtkCList *,
14871 void GtkCList::scroll-horizontal (GtkCList *,
14875 void GtkCList::abort-column-resize (GtkCList *,
14879 <!-- ----------------------------------------------------------------- -->
14881 <!-- ----------------------------------------------------------------- -->
14884 void GtkNotebook::switch-page (GtkNotebook *,
14891 <!-- ----------------------------------------------------------------- -->
14893 <!-- ----------------------------------------------------------------- -->
14896 void GtkList::selection-changed (GtkList *,
14898 void GtkList::select-child (GtkList *,
14901 void GtkList::unselect-child (GtkList *,
14906 <!-- ----------------------------------------------------------------- -->
14907 <sect1>GtkMenuShell
14908 <!-- ----------------------------------------------------------------- -->
14911 void GtkMenuShell::deactivate (GtkMenuShell *,
14913 void GtkMenuShell::selection-done (GtkMenuShell *,
14915 void GtkMenuShell::move-current (GtkMenuShell *,
14916 GtkMenuDirectionType,
14918 void GtkMenuShell::activate-current (GtkMenuShell *,
14921 void GtkMenuShell::cancel (GtkMenuShell *,
14925 <!-- ----------------------------------------------------------------- -->
14927 <!-- ----------------------------------------------------------------- -->
14930 void GtkToolbar::orientation-changed (GtkToolbar *,
14933 void GtkToolbar::style-changed (GtkToolbar *,
14938 <!-- ----------------------------------------------------------------- -->
14940 <!-- ----------------------------------------------------------------- -->
14943 void GtkTree::selection-changed (GtkTree *,
14945 void GtkTree::select-child (GtkTree *,
14948 void GtkTree::unselect-child (GtkTree *,
14953 <!-- ----------------------------------------------------------------- -->
14955 <!-- ----------------------------------------------------------------- -->
14958 void GtkButton::pressed (GtkButton *,
14960 void GtkButton::released (GtkButton *,
14962 void GtkButton::clicked (GtkButton *,
14964 void GtkButton::enter (GtkButton *,
14966 void GtkButton::leave (GtkButton *,
14970 <!-- ----------------------------------------------------------------- -->
14972 <!-- ----------------------------------------------------------------- -->
14975 void GtkItem::select (GtkItem *,
14977 void GtkItem::deselect (GtkItem *,
14979 void GtkItem::toggle (GtkItem *,
14983 <!-- ----------------------------------------------------------------- -->
14985 <!-- ----------------------------------------------------------------- -->
14988 void GtkWindow::set-focus (GtkWindow *,
14993 <!-- ----------------------------------------------------------------- -->
14994 <sect1>GtkHandleBox
14995 <!-- ----------------------------------------------------------------- -->
14998 void GtkHandleBox::child-attached (GtkHandleBox *,
15001 void GtkHandleBox::child-detached (GtkHandleBox *,
15006 <!-- ----------------------------------------------------------------- -->
15007 <sect1>GtkToggleButton
15008 <!-- ----------------------------------------------------------------- -->
15011 void GtkToggleButton::toggled (GtkToggleButton *,
15016 <!-- ----------------------------------------------------------------- -->
15018 <!-- ----------------------------------------------------------------- -->
15021 void GtkMenuItem::activate (GtkMenuItem *,
15023 void GtkMenuItem::activate-item (GtkMenuItem *,
15027 <!-- ----------------------------------------------------------------- -->
15029 <!-- ----------------------------------------------------------------- -->
15032 void GtkListItem::toggle-focus-row (GtkListItem *,
15034 void GtkListItem::select-all (GtkListItem *,
15036 void GtkListItem::unselect-all (GtkListItem *,
15038 void GtkListItem::undo-selection (GtkListItem *,
15040 void GtkListItem::start-selection (GtkListItem *,
15042 void GtkListItem::end-selection (GtkListItem *,
15044 void GtkListItem::toggle-add-mode (GtkListItem *,
15046 void GtkListItem::extend-selection (GtkListItem *,
15051 void GtkListItem::scroll-vertical (GtkListItem *,
15055 void GtkListItem::scroll-horizontal (GtkListItem *,
15061 <!-- ----------------------------------------------------------------- -->
15063 <!-- ----------------------------------------------------------------- -->
15066 void GtkTreeItem::collapse (GtkTreeItem *,
15068 void GtkTreeItem::expand (GtkTreeItem *,
15072 <!-- ----------------------------------------------------------------- -->
15073 <sect1>GtkCheckMenuItem
15074 <!-- ----------------------------------------------------------------- -->
15077 void GtkCheckMenuItem::toggled (GtkCheckMenuItem *,
15081 <!-- ----------------------------------------------------------------- -->
15082 <sect1>GtkInputDialog
15083 <!-- ----------------------------------------------------------------- -->
15086 void GtkInputDialog::enable-device (GtkInputDialog *,
15089 void GtkInputDialog::disable-device (GtkInputDialog *,
15094 <!-- ----------------------------------------------------------------- -->
15095 <sect1>GtkColorSelection
15096 <!-- ----------------------------------------------------------------- -->
15099 void GtkColorSelection::color-changed (GtkColorSelection *,
15103 <!-- ----------------------------------------------------------------- -->
15104 <sect1>GtkStatusBar
15105 <!-- ----------------------------------------------------------------- -->
15108 void GtkStatusbar::text-pushed (GtkStatusbar *,
15112 void GtkStatusbar::text-popped (GtkStatusbar *,
15118 <!-- ----------------------------------------------------------------- -->
15120 <!-- ----------------------------------------------------------------- -->
15123 void GtkCTree::tree-select-row (GtkCTree *,
15127 void GtkCTree::tree-unselect-row (GtkCTree *,
15131 void GtkCTree::tree-expand (GtkCTree *,
15134 void GtkCTree::tree-collapse (GtkCTree *,
15137 void GtkCTree::tree-move (GtkCTree *,
15142 void GtkCTree::change-focus-row-expansion (GtkCTree *,
15143 GtkCTreeExpansionType,
15147 <!-- ----------------------------------------------------------------- -->
15149 <!-- ----------------------------------------------------------------- -->
15152 void GtkCurve::curve-type-changed (GtkCurve *,
15156 <!-- ----------------------------------------------------------------- -->
15157 <sect1>GtkAdjustment
15158 <!-- ----------------------------------------------------------------- -->
15161 void GtkAdjustment::changed (GtkAdjustment *,
15163 void GtkAdjustment::value-changed (GtkAdjustment *,
15167 <!-- ***************************************************************** -->
15168 <sect> GDK Event Types<label id="sec_GDK_Event_Types">
15169 <!-- ***************************************************************** -->
15171 The following data types are passed into event handlers by GTK+. For
15172 each data type listed, the signals that use this data type are listed.
15177 <item>drag_end_event
15180 <item> GdkEventType
15185 <item>destroy_event
15188 <item>no_expose_event
15191 <item> GdkEventExpose
15196 <item> GdkEventNoExpose
15198 <item> GdkEventVisibility
15200 <item> GdkEventMotion
15202 <item>motion_notify_event
15205 <item> GdkEventButton
15207 <item>button_press_event
15208 <item>button_release_event
15213 <item>key_press_event
15214 <item>key_release_event
15217 <item> GdkEventCrossing
15219 <item>enter_notify_event
15220 <item>leave_notify_event
15223 <item> GdkEventFocus
15225 <item>focus_in_event
15226 <item>focus_out_event
15229 <item> GdkEventConfigure
15231 <item>configure_event
15234 <item> GdkEventProperty
15236 <item>property_notify_event
15239 <item> GdkEventSelection
15241 <item>selection_clear_event
15242 <item>selection_request_event
15243 <item>selection_notify_event
15246 <item> GdkEventProximity
15248 <item>proximity_in_event
15249 <item>proximity_out_event
15252 <item> GdkEventDragBegin
15254 <item>drag_begin_event
15257 <item> GdkEventDragRequest
15259 <item>drag_request_event
15262 <item> GdkEventDropEnter
15264 <item>drop_enter_event
15267 <item> GdkEventDropLeave
15269 <item>drop_leave_event
15272 <item> GdkEventDropDataAvailable
15274 <item>drop_data_available_event
15277 <item> GdkEventClient
15282 <item> GdkEventOther
15288 The data type <tt/GdkEventType/ is a special data type that is used by
15289 all the other data types as an indicator of the data type being passed
15290 to the signal handler. As you will see below, each of the event data
15291 structures has a member of this type. It is defined as an enumeration
15301 GDK_MOTION_NOTIFY = 3,
15302 GDK_BUTTON_PRESS = 4,
15303 GDK_2BUTTON_PRESS = 5,
15304 GDK_3BUTTON_PRESS = 6,
15305 GDK_BUTTON_RELEASE = 7,
15307 GDK_KEY_RELEASE = 9,
15308 GDK_ENTER_NOTIFY = 10,
15309 GDK_LEAVE_NOTIFY = 11,
15310 GDK_FOCUS_CHANGE = 12,
15311 GDK_CONFIGURE = 13,
15314 GDK_PROPERTY_NOTIFY = 16,
15315 GDK_SELECTION_CLEAR = 17,
15316 GDK_SELECTION_REQUEST = 18,
15317 GDK_SELECTION_NOTIFY = 19,
15318 GDK_PROXIMITY_IN = 20,
15319 GDK_PROXIMITY_OUT = 21,
15320 GDK_DRAG_BEGIN = 22,
15321 GDK_DRAG_REQUEST = 23,
15322 GDK_DROP_ENTER = 24,
15323 GDK_DROP_LEAVE = 25,
15324 GDK_DROP_DATA_AVAIL = 26,
15325 GDK_CLIENT_EVENT = 27,
15326 GDK_VISIBILITY_NOTIFY = 28,
15327 GDK_NO_EXPOSE = 29,
15328 GDK_OTHER_EVENT = 9999 /* Deprecated, use filters instead */
15332 The other event type that is different from the others is
15333 <tt/GdkEvent/ itself. This is a union of all the other
15334 data types, which allows it to be cast to a specific
15335 event data type within a signal handler.
15337 <!-- Just a big list for now, needs expanding upon - TRG -->
15338 So, the event data types are defined as follows:
15341 struct _GdkEventAny
15348 struct _GdkEventExpose
15354 gint count; /* If non-zero, how many more events follow. */
15357 struct _GdkEventNoExpose
15362 /* XXX: does anyone need the X major_code or minor_code fields? */
15365 struct _GdkEventVisibility
15370 GdkVisibilityState state;
15373 struct _GdkEventMotion
15386 GdkInputSource source;
15388 gdouble x_root, y_root;
15391 struct _GdkEventButton
15404 GdkInputSource source;
15406 gdouble x_root, y_root;
15409 struct _GdkEventKey
15421 struct _GdkEventCrossing
15426 GdkWindow *subwindow;
15427 GdkNotifyType detail;
15430 struct _GdkEventFocus
15438 struct _GdkEventConfigure
15448 struct _GdkEventProperty
15458 struct _GdkEventSelection
15470 /* This event type will be used pretty rarely. It only is important
15471 for XInput aware programs that are drawing their own cursor */
15473 struct _GdkEventProximity
15479 GdkInputSource source;
15483 struct _GdkEventDragRequest
15491 guint protocol_version:4;
15493 guint willaccept:1;
15494 guint delete_data:1; /* Do *not* delete if link is sent, only
15501 guint8 isdrop; /* This gdk event can be generated by a couple of
15502 X events - this lets the app know whether the
15503 drop really occurred or we just set the data */
15505 GdkPoint drop_coords;
15510 struct _GdkEventDragBegin
15517 guint protocol_version:4;
15524 struct _GdkEventDropEnter
15532 guint protocol_version:4;
15534 guint extended_typelist:1;
15541 struct _GdkEventDropLeave
15549 guint protocol_version:4;
15556 struct _GdkEventDropDataAvailable
15564 guint protocol_version:4;
15570 gchar *data_type; /* MIME type */
15571 gulong data_numbytes;
15577 struct _GdkEventClient
15582 GdkAtom message_type;
15583 gushort data_format;
15591 struct _GdkEventOther
15600 <!-- ***************************************************************** -->
15601 <sect> Code Examples
15602 <!-- ***************************************************************** -->
15604 Below are the code examples that are used in the above text
15605 which are not included in complete form elsewhere.
15607 <!-- ----------------------------------------------------------------- -->
15609 <!-- ----------------------------------------------------------------- -->
15613 /* example-start tictactoe tictactoe.h */
15615 /* GTK - The GIMP Toolkit
15616 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15618 * This library is free software; you can redistribute it and/or
15619 * modify it under the terms of the GNU Library General Public
15620 * License as published by the Free Software Foundation; either
15621 * version 2 of the License, or (at your option) any later version.
15623 * This library is distributed in the hope that it will be useful,
15624 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15625 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15626 * Library General Public License for more details.
15628 * You should have received a copy of the GNU Library General Public
15629 * License along with this library; if not, write to the
15630 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15631 * Boston, MA 02111-1307, USA.
15633 #ifndef __TICTACTOE_H__
15634 #define __TICTACTOE_H__
15637 #include <gdk/gdk.h>
15638 #include <gtk/gtkvbox.h>
15643 #endif /* __cplusplus */
15645 #define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
15646 #define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
15647 #define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
15650 typedef struct _Tictactoe Tictactoe;
15651 typedef struct _TictactoeClass TictactoeClass;
15657 GtkWidget *buttons[3][3];
15660 struct _TictactoeClass
15662 GtkVBoxClass parent_class;
15664 void (* tictactoe) (Tictactoe *ttt);
15667 guint tictactoe_get_type (void);
15668 GtkWidget* tictactoe_new (void);
15669 void tictactoe_clear (Tictactoe *ttt);
15673 #endif /* __cplusplus */
15675 #endif /* __TICTACTOE_H__ */
15680 <!-- ----------------------------------------------------------------- -->
15684 /* example-start tictactoe tictactoe.c */
15686 /* GTK - The GIMP Toolkit
15687 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15689 * This library is free software; you can redistribute it and/or
15690 * modify it under the terms of the GNU Library General Public
15691 * License as published by the Free Software Foundation; either
15692 * version 2 of the License, or (at your option) any later version.
15694 * This library is distributed in the hope that it will be useful,
15695 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15696 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15697 * Library General Public License for more details.
15699 * You should have received a copy of the GNU Library General Public
15700 * License along with this library; if not, write to the
15701 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15702 * Boston, MA 02111-1307, USA.
15704 #include "gtk/gtksignal.h"
15705 #include "gtk/gtktable.h"
15706 #include "gtk/gtktogglebutton.h"
15707 #include "tictactoe.h"
15714 static void tictactoe_class_init (TictactoeClass *klass);
15715 static void tictactoe_init (Tictactoe *ttt);
15716 static void tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt);
15718 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
15721 tictactoe_get_type ()
15723 static guint ttt_type = 0;
15727 GtkTypeInfo ttt_info =
15730 sizeof (Tictactoe),
15731 sizeof (TictactoeClass),
15732 (GtkClassInitFunc) tictactoe_class_init,
15733 (GtkObjectInitFunc) tictactoe_init,
15734 (GtkArgSetFunc) NULL,
15735 (GtkArgGetFunc) NULL
15738 ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
15745 tictactoe_class_init (TictactoeClass *class)
15747 GtkObjectClass *object_class;
15749 object_class = (GtkObjectClass*) class;
15751 tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
15753 object_class->type,
15754 GTK_SIGNAL_OFFSET (TictactoeClass,
15756 gtk_signal_default_marshaller,
15760 gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
15762 class->tictactoe = NULL;
15766 tictactoe_init (Tictactoe *ttt)
15771 table = gtk_table_new (3, 3, TRUE);
15772 gtk_container_add (GTK_CONTAINER(ttt), table);
15773 gtk_widget_show (table);
15778 ttt->buttons[i][j] = gtk_toggle_button_new ();
15779 gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
15781 gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
15782 GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
15783 gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
15784 gtk_widget_show (ttt->buttons[i][j]);
15791 return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
15795 tictactoe_clear (Tictactoe *ttt)
15802 gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
15803 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
15805 gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
15810 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
15814 static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
15815 { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
15816 { 0, 1, 2 }, { 0, 1, 2 } };
15817 static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
15818 { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
15819 { 0, 1, 2 }, { 2, 1, 0 } };
15821 int success, found;
15823 for (k=0; k<8; k++)
15830 success = success &&
15831 GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
15833 ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
15836 if (success && found)
15838 gtk_signal_emit (GTK_OBJECT (ttt),
15839 tictactoe_signals[TICTACTOE_SIGNAL]);
15848 <!-- ----------------------------------------------------------------- -->
15852 /* example-start tictactoe ttt_test.c */
15854 #include <gtk/gtk.h>
15855 #include "tictactoe.h"
15858 win (GtkWidget *widget, gpointer data)
15860 g_print ("Yay!\n");
15861 tictactoe_clear (TICTACTOE (widget));
15865 main (int argc, char *argv[])
15870 gtk_init (&argc, &argv);
15872 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
15874 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
15876 gtk_signal_connect (GTK_OBJECT (window), "destroy",
15877 GTK_SIGNAL_FUNC (gtk_exit), NULL);
15879 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
15881 ttt = tictactoe_new ();
15883 gtk_container_add (GTK_CONTAINER (window), ttt);
15884 gtk_widget_show (ttt);
15886 gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
15887 GTK_SIGNAL_FUNC (win), NULL);
15889 gtk_widget_show (window);
15899 <!-- ----------------------------------------------------------------- -->
15902 <!-- ----------------------------------------------------------------- -->
15906 /* example-start gtkdial gtkdial.h */
15908 /* GTK - The GIMP Toolkit
15909 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15911 * This library is free software; you can redistribute it and/or
15912 * modify it under the terms of the GNU Library General Public
15913 * License as published by the Free Software Foundation; either
15914 * version 2 of the License, or (at your option) any later version.
15916 * This library is distributed in the hope that it will be useful,
15917 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15918 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15919 * Library General Public License for more details.
15921 * You should have received a copy of the GNU Library General Public
15922 * License along with this library; if not, write to the
15923 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15924 * Boston, MA 02111-1307, USA.
15926 #ifndef __GTK_DIAL_H__
15927 #define __GTK_DIAL_H__
15930 #include <gdk/gdk.h>
15931 #include <gtk/gtkadjustment.h>
15932 #include <gtk/gtkwidget.h>
15937 #endif /* __cplusplus */
15940 #define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
15941 #define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
15942 #define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
15945 typedef struct _GtkDial GtkDial;
15946 typedef struct _GtkDialClass GtkDialClass;
15952 /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
15955 /* Button currently pressed or 0 if none */
15958 /* Dimensions of dial components */
15960 gint pointer_width;
15962 /* ID of update timer, or 0 if none */
15965 /* Current angle */
15968 /* Old values from adjustment stored so we know when something changes */
15973 /* The adjustment object that stores the data for this dial */
15974 GtkAdjustment *adjustment;
15977 struct _GtkDialClass
15979 GtkWidgetClass parent_class;
15983 GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
15984 guint gtk_dial_get_type (void);
15985 GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
15986 void gtk_dial_set_update_policy (GtkDial *dial,
15987 GtkUpdateType policy);
15989 void gtk_dial_set_adjustment (GtkDial *dial,
15990 GtkAdjustment *adjustment);
15993 #endif /* __cplusplus */
15996 #endif /* __GTK_DIAL_H__ */
16000 <!-- ----------------------------------------------------------------- -->
16004 /* example-start gtkdial gtkdial.c */
16006 /* GTK - The GIMP Toolkit
16007 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
16009 * This library is free software; you can redistribute it and/or
16010 * modify it under the terms of the GNU Library General Public
16011 * License as published by the Free Software Foundation; either
16012 * version 2 of the License, or (at your option) any later version.
16014 * This library is distributed in the hope that it will be useful,
16015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16017 * Library General Public License for more details.
16019 * You should have received a copy of the GNU Library General Public
16020 * License along with this library; if not, write to the
16021 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16022 * Boston, MA 02111-1307, USA.
16026 #include <gtk/gtkmain.h>
16027 #include <gtk/gtksignal.h>
16029 #include "gtkdial.h"
16031 #define SCROLL_DELAY_LENGTH 300
16032 #define DIAL_DEFAULT_SIZE 100
16034 /* Forward declarations */
16036 static void gtk_dial_class_init (GtkDialClass *klass);
16037 static void gtk_dial_init (GtkDial *dial);
16038 static void gtk_dial_destroy (GtkObject *object);
16039 static void gtk_dial_realize (GtkWidget *widget);
16040 static void gtk_dial_size_request (GtkWidget *widget,
16041 GtkRequisition *requisition);
16042 static void gtk_dial_size_allocate (GtkWidget *widget,
16043 GtkAllocation *allocation);
16044 static gint gtk_dial_expose (GtkWidget *widget,
16045 GdkEventExpose *event);
16046 static gint gtk_dial_button_press (GtkWidget *widget,
16047 GdkEventButton *event);
16048 static gint gtk_dial_button_release (GtkWidget *widget,
16049 GdkEventButton *event);
16050 static gint gtk_dial_motion_notify (GtkWidget *widget,
16051 GdkEventMotion *event);
16052 static gint gtk_dial_timer (GtkDial *dial);
16054 static void gtk_dial_update_mouse (GtkDial *dial, gint x, gint y);
16055 static void gtk_dial_update (GtkDial *dial);
16056 static void gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
16058 static void gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
16063 static GtkWidgetClass *parent_class = NULL;
16066 gtk_dial_get_type ()
16068 static guint dial_type = 0;
16072 GtkTypeInfo dial_info =
16076 sizeof (GtkDialClass),
16077 (GtkClassInitFunc) gtk_dial_class_init,
16078 (GtkObjectInitFunc) gtk_dial_init,
16079 (GtkArgSetFunc) NULL,
16080 (GtkArgGetFunc) NULL,
16083 dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info);
16090 gtk_dial_class_init (GtkDialClass *class)
16092 GtkObjectClass *object_class;
16093 GtkWidgetClass *widget_class;
16095 object_class = (GtkObjectClass*) class;
16096 widget_class = (GtkWidgetClass*) class;
16098 parent_class = gtk_type_class (gtk_widget_get_type ());
16100 object_class->destroy = gtk_dial_destroy;
16102 widget_class->realize = gtk_dial_realize;
16103 widget_class->expose_event = gtk_dial_expose;
16104 widget_class->size_request = gtk_dial_size_request;
16105 widget_class->size_allocate = gtk_dial_size_allocate;
16106 widget_class->button_press_event = gtk_dial_button_press;
16107 widget_class->button_release_event = gtk_dial_button_release;
16108 widget_class->motion_notify_event = gtk_dial_motion_notify;
16112 gtk_dial_init (GtkDial *dial)
16115 dial->policy = GTK_UPDATE_CONTINUOUS;
16118 dial->pointer_width = 0;
16120 dial->old_value = 0.0;
16121 dial->old_lower = 0.0;
16122 dial->old_upper = 0.0;
16123 dial->adjustment = NULL;
16127 gtk_dial_new (GtkAdjustment *adjustment)
16131 dial = gtk_type_new (gtk_dial_get_type ());
16134 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0,
16137 gtk_dial_set_adjustment (dial, adjustment);
16139 return GTK_WIDGET (dial);
16143 gtk_dial_destroy (GtkObject *object)
16147 g_return_if_fail (object != NULL);
16148 g_return_if_fail (GTK_IS_DIAL (object));
16150 dial = GTK_DIAL (object);
16152 if (dial->adjustment)
16153 gtk_object_unref (GTK_OBJECT (dial->adjustment));
16155 if (GTK_OBJECT_CLASS (parent_class)->destroy)
16156 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
16160 gtk_dial_get_adjustment (GtkDial *dial)
16162 g_return_val_if_fail (dial != NULL, NULL);
16163 g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
16165 return dial->adjustment;
16169 gtk_dial_set_update_policy (GtkDial *dial,
16170 GtkUpdateType policy)
16172 g_return_if_fail (dial != NULL);
16173 g_return_if_fail (GTK_IS_DIAL (dial));
16175 dial->policy = policy;
16179 gtk_dial_set_adjustment (GtkDial *dial,
16180 GtkAdjustment *adjustment)
16182 g_return_if_fail (dial != NULL);
16183 g_return_if_fail (GTK_IS_DIAL (dial));
16185 if (dial->adjustment)
16187 gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment),
16189 gtk_object_unref (GTK_OBJECT (dial->adjustment));
16192 dial->adjustment = adjustment;
16193 gtk_object_ref (GTK_OBJECT (dial->adjustment));
16195 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
16196 (GtkSignalFunc) gtk_dial_adjustment_changed,
16198 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
16199 (GtkSignalFunc) gtk_dial_adjustment_value_changed,
16202 dial->old_value = adjustment->value;
16203 dial->old_lower = adjustment->lower;
16204 dial->old_upper = adjustment->upper;
16206 gtk_dial_update (dial);
16210 gtk_dial_realize (GtkWidget *widget)
16213 GdkWindowAttr attributes;
16214 gint attributes_mask;
16216 g_return_if_fail (widget != NULL);
16217 g_return_if_fail (GTK_IS_DIAL (widget));
16219 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
16220 dial = GTK_DIAL (widget);
16222 attributes.x = widget->allocation.x;
16223 attributes.y = widget->allocation.y;
16224 attributes.width = widget->allocation.width;
16225 attributes.height = widget->allocation.height;
16226 attributes.wclass = GDK_INPUT_OUTPUT;
16227 attributes.window_type = GDK_WINDOW_CHILD;
16228 attributes.event_mask = gtk_widget_get_events (widget) |
16229 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
16230 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
16231 GDK_POINTER_MOTION_HINT_MASK;
16232 attributes.visual = gtk_widget_get_visual (widget);
16233 attributes.colormap = gtk_widget_get_colormap (widget);
16235 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
16236 widget->window = gdk_window_new (widget->parent->window,
16240 widget->style = gtk_style_attach (widget->style, widget->window);
16242 gdk_window_set_user_data (widget->window, widget);
16244 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
16248 gtk_dial_size_request (GtkWidget *widget,
16249 GtkRequisition *requisition)
16251 requisition->width = DIAL_DEFAULT_SIZE;
16252 requisition->height = DIAL_DEFAULT_SIZE;
16256 gtk_dial_size_allocate (GtkWidget *widget,
16257 GtkAllocation *allocation)
16261 g_return_if_fail (widget != NULL);
16262 g_return_if_fail (GTK_IS_DIAL (widget));
16263 g_return_if_fail (allocation != NULL);
16265 widget->allocation = *allocation;
16266 dial = GTK_DIAL (widget);
16268 if (GTK_WIDGET_REALIZED (widget))
16271 gdk_window_move_resize (widget->window,
16272 allocation->x, allocation->y,
16273 allocation->width, allocation->height);
16276 dial->radius = MIN(allocation->width,allocation->height) * 0.45;
16277 dial->pointer_width = dial->radius / 5;
16281 gtk_dial_expose (GtkWidget *widget,
16282 GdkEventExpose *event)
16285 GdkPoint points[3];
16292 g_return_val_if_fail (widget != NULL, FALSE);
16293 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16294 g_return_val_if_fail (event != NULL, FALSE);
16296 if (event->count > 0)
16299 dial = GTK_DIAL (widget);
16301 gdk_window_clear_area (widget->window,
16303 widget->allocation.width,
16304 widget->allocation.height);
16306 xc = widget->allocation.width/2;
16307 yc = widget->allocation.height/2;
16311 for (i=0; i<25; i++)
16313 theta = (i*M_PI/18. - M_PI/6.);
16317 tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
16319 gdk_draw_line (widget->window,
16320 widget->style->fg_gc[widget->state],
16321 xc + c*(dial->radius - tick_length),
16322 yc - s*(dial->radius - tick_length),
16323 xc + c*dial->radius,
16324 yc - s*dial->radius);
16329 s = sin(dial->angle);
16330 c = cos(dial->angle);
16333 points[0].x = xc + s*dial->pointer_width/2;
16334 points[0].y = yc + c*dial->pointer_width/2;
16335 points[1].x = xc + c*dial->radius;
16336 points[1].y = yc - s*dial->radius;
16337 points[2].x = xc - s*dial->pointer_width/2;
16338 points[2].y = yc - c*dial->pointer_width/2;
16340 gtk_draw_polygon (widget->style,
16351 gtk_dial_button_press (GtkWidget *widget,
16352 GdkEventButton *event)
16358 double d_perpendicular;
16360 g_return_val_if_fail (widget != NULL, FALSE);
16361 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16362 g_return_val_if_fail (event != NULL, FALSE);
16364 dial = GTK_DIAL (widget);
16366 /* Determine if button press was within pointer region - we
16367 do this by computing the parallel and perpendicular distance of
16368 the point where the mouse was pressed from the line passing through
16371 dx = event->x - widget->allocation.width / 2;
16372 dy = widget->allocation.height / 2 - event->y;
16374 s = sin(dial->angle);
16375 c = cos(dial->angle);
16377 d_parallel = s*dy + c*dx;
16378 d_perpendicular = fabs(s*dx - c*dy);
16380 if (!dial->button &&
16381 (d_perpendicular < dial->pointer_width/2) &&
16382 (d_parallel > - dial->pointer_width))
16384 gtk_grab_add (widget);
16386 dial->button = event->button;
16388 gtk_dial_update_mouse (dial, event->x, event->y);
16395 gtk_dial_button_release (GtkWidget *widget,
16396 GdkEventButton *event)
16400 g_return_val_if_fail (widget != NULL, FALSE);
16401 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16402 g_return_val_if_fail (event != NULL, FALSE);
16404 dial = GTK_DIAL (widget);
16406 if (dial->button == event->button)
16408 gtk_grab_remove (widget);
16412 if (dial->policy == GTK_UPDATE_DELAYED)
16413 gtk_timeout_remove (dial->timer);
16415 if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
16416 (dial->old_value != dial->adjustment->value))
16417 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment),
16425 gtk_dial_motion_notify (GtkWidget *widget,
16426 GdkEventMotion *event)
16429 GdkModifierType mods;
16432 g_return_val_if_fail (widget != NULL, FALSE);
16433 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16434 g_return_val_if_fail (event != NULL, FALSE);
16436 dial = GTK_DIAL (widget);
16438 if (dial->button != 0)
16443 if (event->is_hint || (event->window != widget->window))
16444 gdk_window_get_pointer (widget->window, &x, &y, &mods);
16446 switch (dial->button)
16449 mask = GDK_BUTTON1_MASK;
16452 mask = GDK_BUTTON2_MASK;
16455 mask = GDK_BUTTON3_MASK;
16462 if (mods & mask)
16463 gtk_dial_update_mouse (dial, x,y);
16470 gtk_dial_timer (GtkDial *dial)
16472 g_return_val_if_fail (dial != NULL, FALSE);
16473 g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
16475 if (dial->policy == GTK_UPDATE_DELAYED)
16476 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment),
16483 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
16488 g_return_if_fail (dial != NULL);
16489 g_return_if_fail (GTK_IS_DIAL (dial));
16491 xc = GTK_WIDGET(dial)->allocation.width / 2;
16492 yc = GTK_WIDGET(dial)->allocation.height / 2;
16494 old_value = dial->adjustment->value;
16495 dial->angle = atan2(yc-y, x-xc);
16497 if (dial->angle < -M_PI/2.)
16498 dial->angle += 2*M_PI;
16500 if (dial->angle < -M_PI/6)
16501 dial->angle = -M_PI/6;
16503 if (dial->angle > 7.*M_PI/6.)
16504 dial->angle = 7.*M_PI/6.;
16506 dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
16507 (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
16509 if (dial->adjustment->value != old_value)
16511 if (dial->policy == GTK_UPDATE_CONTINUOUS)
16513 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment),
16518 gtk_widget_draw (GTK_WIDGET(dial), NULL);
16520 if (dial->policy == GTK_UPDATE_DELAYED)
16523 gtk_timeout_remove (dial->timer);
16525 dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
16526 (GtkFunction) gtk_dial_timer,
16534 gtk_dial_update (GtkDial *dial)
16538 g_return_if_fail (dial != NULL);
16539 g_return_if_fail (GTK_IS_DIAL (dial));
16541 new_value = dial->adjustment->value;
16543 if (new_value < dial->adjustment->lower)
16544 new_value = dial->adjustment->lower;
16546 if (new_value > dial->adjustment->upper)
16547 new_value = dial->adjustment->upper;
16549 if (new_value != dial->adjustment->value)
16551 dial->adjustment->value = new_value;
16552 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
16555 dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) *
16557 (dial->adjustment->upper - dial->adjustment->lower);
16559 gtk_widget_draw (GTK_WIDGET(dial), NULL);
16563 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
16568 g_return_if_fail (adjustment != NULL);
16569 g_return_if_fail (data != NULL);
16571 dial = GTK_DIAL (data);
16573 if ((dial->old_value != adjustment->value) ||
16574 (dial->old_lower != adjustment->lower) ||
16575 (dial->old_upper != adjustment->upper))
16577 gtk_dial_update (dial);
16579 dial->old_value = adjustment->value;
16580 dial->old_lower = adjustment->lower;
16581 dial->old_upper = adjustment->upper;
16586 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
16591 g_return_if_fail (adjustment != NULL);
16592 g_return_if_fail (data != NULL);
16594 dial = GTK_DIAL (data);
16596 if (dial->old_value != adjustment->value)
16598 gtk_dial_update (dial);
16600 dial->old_value = adjustment->value;
16606 <!-- ----------------------------------------------------------------- -->
16610 /* example-start scribble-simple scribble-simple.c */
16612 /* GTK - The GIMP Toolkit
16613 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
16615 * This library is free software; you can redistribute it and/or
16616 * modify it under the terms of the GNU Library General Public
16617 * License as published by the Free Software Foundation; either
16618 * version 2 of the License, or (at your option) any later version.
16620 * This library is distributed in the hope that it will be useful,
16621 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16622 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16623 * Library General Public License for more details.
16625 * You should have received a copy of the GNU Library General Public
16626 * License along with this library; if not, write to the
16627 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16628 * Boston, MA 02111-1307, USA.
16631 #include <gtk/gtk.h>
16633 /* Backing pixmap for drawing area */
16634 static GdkPixmap *pixmap = NULL;
16636 /* Create a new backing pixmap of the appropriate size */
16638 configure_event (GtkWidget *widget, GdkEventConfigure *event)
16641 gdk_pixmap_unref(pixmap);
16643 pixmap = gdk_pixmap_new(widget->window,
16644 widget->allocation.width,
16645 widget->allocation.height,
16647 gdk_draw_rectangle (pixmap,
16648 widget->style->white_gc,
16651 widget->allocation.width,
16652 widget->allocation.height);
16657 /* Redraw the screen from the backing pixmap */
16659 expose_event (GtkWidget *widget, GdkEventExpose *event)
16661 gdk_draw_pixmap(widget->window,
16662 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
16664 event->area.x, event->area.y,
16665 event->area.x, event->area.y,
16666 event->area.width, event->area.height);
16671 /* Draw a rectangle on the screen */
16673 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
16675 GdkRectangle update_rect;
16677 update_rect.x = x - 5;
16678 update_rect.y = y - 5;
16679 update_rect.width = 10;
16680 update_rect.height = 10;
16681 gdk_draw_rectangle (pixmap,
16682 widget->style->black_gc,
16684 update_rect.x, update_rect.y,
16685 update_rect.width, update_rect.height);
16686 gtk_widget_draw (widget, &update_rect);
16690 button_press_event (GtkWidget *widget, GdkEventButton *event)
16692 if (event->button == 1 && pixmap != NULL)
16693 draw_brush (widget, event->x, event->y);
16699 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
16702 GdkModifierType state;
16704 if (event->is_hint)
16705 gdk_window_get_pointer (event->window, &x, &y, &state);
16710 state = event->state;
16713 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
16714 draw_brush (widget, x, y);
16726 main (int argc, char *argv[])
16729 GtkWidget *drawing_area;
16734 gtk_init (&argc, &argv);
16736 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
16737 gtk_widget_set_name (window, "Test Input");
16739 vbox = gtk_vbox_new (FALSE, 0);
16740 gtk_container_add (GTK_CONTAINER (window), vbox);
16741 gtk_widget_show (vbox);
16743 gtk_signal_connect (GTK_OBJECT (window), "destroy",
16744 GTK_SIGNAL_FUNC (quit), NULL);
16746 /* Create the drawing area */
16748 drawing_area = gtk_drawing_area_new ();
16749 gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200);
16750 gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
16752 gtk_widget_show (drawing_area);
16754 /* Signals used to handle backing pixmap */
16756 gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
16757 (GtkSignalFunc) expose_event, NULL);
16758 gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
16759 (GtkSignalFunc) configure_event, NULL);
16761 /* Event signals */
16763 gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
16764 (GtkSignalFunc) motion_notify_event, NULL);
16765 gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
16766 (GtkSignalFunc) button_press_event, NULL);
16768 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
16769 | GDK_LEAVE_NOTIFY_MASK
16770 | GDK_BUTTON_PRESS_MASK
16771 | GDK_POINTER_MOTION_MASK
16772 | GDK_POINTER_MOTION_HINT_MASK);
16774 /* .. And a quit button */
16775 button = gtk_button_new_with_label ("Quit");
16776 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
16778 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
16779 GTK_SIGNAL_FUNC (gtk_widget_destroy),
16780 GTK_OBJECT (window));
16781 gtk_widget_show (button);
16783 gtk_widget_show (window);
16792 <!-- ***************************************************************** -->
16794 <!-- ***************************************************************** -->
16796 NOTE: The List widget has been superseded by the CList widget. It is
16797 detailed here just for completeness.
16799 The List widget is designed to act as a vertical container for
16800 widgets that should be of the type ListItem.
16802 A List widget has its own window to receive events and its own
16803 background color which is usually white. As it is directly derived
16804 from a Container it can be treated as such by using the
16805 GTK_CONTAINER(List) macro, see the Container widget for more on
16806 this. One should already be familiar with the usage of a GList and
16807 its related functions g_list_*() to be able to use the List widget
16810 There is one field inside the structure definition of the List
16811 widget that will be of greater interest to us, this is:
16818 guint selection_mode;
16823 The selection field of a List points to a linked list of all items
16824 that are currently selected, or NULL if the selection is empty. So to
16825 learn about the current selection we read the GTK_LIST()->selection
16826 field, but do not modify it since the internal fields are maintained
16827 by the gtk_list_*() functions.
16829 The selection_mode of the List determines the selection facilities
16830 of a List and therefore the contents of the GTK_LIST()->selection
16831 field. The selection_mode may be one of the following:
16834 <item> <tt/GTK_SELECTION_SINGLE/ - The selection is either NULL
16835 or contains a GList pointer
16836 for a single selected item.
16838 <item> <tt/GTK_SELECTION_BROWSE/ - The selection is NULL if the list
16839 contains no widgets or insensitive
16840 ones only, otherwise it contains
16841 a GList pointer for one GList
16842 structure, and therefore exactly
16845 <item> <tt/GTK_SELECTION_MULTIPLE/ - The selection is NULL if no list
16846 items are selected or a GList pointer
16847 for the first selected item. That
16848 in turn points to a GList structure
16849 for the second selected item and so
16852 <item> <tt/GTK_SELECTION_EXTENDED/ - The selection is always NULL.
16855 The default is <tt/GTK_SELECTION_MULTIPLE/.
16857 <!-- ----------------------------------------------------------------- -->
16861 void selection_changed( GtkList *list );
16864 This signal will be invoked whenever the selection field of a List
16865 has changed. This happens when a child of thekList got selected or
16869 void select_child( GtkList *list,
16873 This signal is invoked when a child of the List is about to get
16874 selected. This happens mainly on calls to gtk_list_select_item(),
16875 gtk_list_select_child(), button presses and sometimes indirectly
16876 triggered on some else occasions where children get added to or
16877 removed from the List.
16880 void unselect_child( GtkList *list,
16881 GtkWidget *child );
16884 This signal is invoked when a child of the List is about to get
16885 deselected. This happens mainly on calls to gtk_list_unselect_item(),
16886 gtk_list_unselect_child(), button presses and sometimes indirectly
16887 triggered on some else occasions where children get added to or
16888 removed from the List.
16890 <!-- ----------------------------------------------------------------- -->
16894 guint gtk_list_get_type( void );
16897 Returns the "GtkList" type identifier.
16900 GtkWidget *gtk_list_new( void );
16903 Create a new List object. The new widget is returned as a pointer
16904 to a GtkWidget object. NULL is returned on failure.
16907 void gtk_list_insert_items( GtkList *list,
16912 Insert list items into the list, starting at <tt/position/.
16913 <tt/items/ is a doubly linked list where each nodes data pointer is
16914 expected to point to a newly created ListItem. The GList nodes of
16915 <tt/items/ are taken over by the list.
16918 void gtk_list_append_items( GtkList *list,
16922 Insert list items just like gtk_list_insert_items() at the end of the
16923 list. The GList nodes of <tt/items/ are taken over by the list.
16926 void gtk_list_prepend_items( GtkList *list,
16930 Insert list items just like gtk_list_insert_items() at the very
16931 beginning of the list. The GList nodes of <tt/items/ are taken over by
16935 void gtk_list_remove_items( GtkList *list,
16939 Remove list items from the list. <tt/items/ is a doubly linked list
16940 where each nodes data pointer is expected to point to a direct child
16941 of list. It is the callers responsibility to make a call to
16942 g_list_free(items) afterwards. Also the caller has to destroy the list
16946 void gtk_list_clear_items( GtkList *list,
16951 Remove and destroy list items from the list. A widget is affected if
16952 its current position within the list is in the range specified by
16953 <tt/start/ and <tt/end/.
16956 void gtk_list_select_item( GtkList *list,
16960 Invoke the select_child signal for a list item specified through its
16961 current position within the list.
16964 void gtk_list_unselect_item( GtkList *list,
16968 Invoke the unselect_child signal for a list item specified through its
16969 current position within the list.
16972 void gtk_list_select_child( GtkList *list,
16976 Invoke the select_child signal for the specified child.
16979 void gtk_list_unselect_child( GtkList *list,
16983 Invoke the unselect_child signal for the specified child.
16986 gint gtk_list_child_position( GtkList *list,
16990 Return the position of <tt/child/ within the list. "-1" is returned on
16994 void gtk_list_set_selection_mode( GtkList *list,
16995 GtkSelectionMode mode );
16998 Set the selection mode MODE which can be of GTK_SELECTION_SINGLE,
16999 GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE or
17000 GTK_SELECTION_EXTENDED.
17003 GtkList *GTK_LIST( gpointer obj );
17006 Cast a generic pointer to "GtkList *".
17009 GtkListClass *GTK_LIST_CLASS( gpointer class);
17012 Cast a generic pointer to "GtkListClass *".
17015 gint GTK_IS_LIST( gpointer obj);
17018 Determine if a generic pointer refers to a "GtkList" object.
17020 <!-- ----------------------------------------------------------------- -->
17023 Following is an example program that will print out the changes of the
17024 selection of a List, and lets you "arrest" list items into a prison
17025 by selecting them with the rightmost mouse button.
17028 /* example-start list list.c */
17030 /* Include the GTK header files
17031 * Include stdio.h, we need that for the printf() function
17033 #include <gtk/gtk.h>
17036 /* This is our data identification string to store
17037 * data in list items
17039 const gchar *list_item_data_key="list_item_data";
17042 /* prototypes for signal handler that we are going to connect
17043 * to the List widget
17045 static void sigh_print_selection( GtkWidget *gtklist,
17046 gpointer func_data);
17048 static void sigh_button_event( GtkWidget *gtklist,
17049 GdkEventButton *event,
17050 GtkWidget *frame );
17053 /* Main function to set up the user interface */
17055 gint main (int argc,
17058 GtkWidget *separator;
17061 GtkWidget *scrolled_window;
17063 GtkWidget *gtklist;
17065 GtkWidget *list_item;
17071 /* Initialize GTK (and subsequently GDK) */
17073 gtk_init(&argc, &argv);
17076 /* Create a window to put all the widgets in
17077 * connect gtk_main_quit() to the "destroy" event of
17078 * the window to handle window manager close-window-events
17080 window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
17081 gtk_window_set_title(GTK_WINDOW(window), "GtkList Example");
17082 gtk_signal_connect(GTK_OBJECT(window),
17084 GTK_SIGNAL_FUNC(gtk_main_quit),
17088 /* Inside the window we need a box to arrange the widgets
17090 vbox=gtk_vbox_new(FALSE, 5);
17091 gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
17092 gtk_container_add(GTK_CONTAINER(window), vbox);
17093 gtk_widget_show(vbox);
17095 /* This is the scrolled window to put the List widget inside */
17096 scrolled_window=gtk_scrolled_window_new(NULL, NULL);
17097 gtk_widget_set_usize(scrolled_window, 250, 150);
17098 gtk_container_add(GTK_CONTAINER(vbox), scrolled_window);
17099 gtk_widget_show(scrolled_window);
17101 /* Create thekList widget.
17102 * Connect the sigh_print_selection() signal handler
17103 * function to the "selection_changed" signal of the List
17104 * to print out the selected items each time the selection
17106 gtklist=gtk_list_new();
17107 gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(scrolled_window),
17109 gtk_widget_show(gtklist);
17110 gtk_signal_connect(GTK_OBJECT(gtklist),
17111 "selection_changed",
17112 GTK_SIGNAL_FUNC(sigh_print_selection),
17115 /* We create a "Prison" to put a list item in ;) */
17116 frame=gtk_frame_new("Prison");
17117 gtk_widget_set_usize(frame, 200, 50);
17118 gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
17119 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
17120 gtk_container_add(GTK_CONTAINER(vbox), frame);
17121 gtk_widget_show(frame);
17123 /* Connect the sigh_button_event() signal handler to the List
17124 * which will handle the "arresting" of list items
17126 gtk_signal_connect(GTK_OBJECT(gtklist),
17127 "button_release_event",
17128 GTK_SIGNAL_FUNC(sigh_button_event),
17131 /* Create a separator */
17132 separator=gtk_hseparator_new();
17133 gtk_container_add(GTK_CONTAINER(vbox), separator);
17134 gtk_widget_show(separator);
17136 /* Finally create a button and connect its "clicked" signal
17137 * to the destruction of the window */
17138 button=gtk_button_new_with_label("Close");
17139 gtk_container_add(GTK_CONTAINER(vbox), button);
17140 gtk_widget_show(button);
17141 gtk_signal_connect_object(GTK_OBJECT(button),
17143 GTK_SIGNAL_FUNC(gtk_widget_destroy),
17144 GTK_OBJECT(window));
17147 /* Now we create 5 list items, each having its own
17148 * label and add them to the List using gtk_container_add()
17149 * Also we query the text string from the label and
17150 * associate it with the list_item_data_key for each list item
17152 for (i=0; i<5; i++) {
17156 sprintf(buffer, "ListItemContainer with Label #%d", i);
17157 label=gtk_label_new(buffer);
17158 list_item=gtk_list_item_new();
17159 gtk_container_add(GTK_CONTAINER(list_item), label);
17160 gtk_widget_show(label);
17161 gtk_container_add(GTK_CONTAINER(gtklist), list_item);
17162 gtk_widget_show(list_item);
17163 gtk_label_get(GTK_LABEL(label), &string);
17164 gtk_object_set_data(GTK_OBJECT(list_item),
17165 list_item_data_key,
17168 /* Here, we are creating another 5 labels, this time
17169 * we use gtk_list_item_new_with_label() for the creation
17170 * we can't query the text string from the label because
17171 * we don't have the labels pointer and therefore
17172 * we just associate the list_item_data_key of each
17173 * list item with the same text string.
17174 * For adding of the list items we put them all into a doubly
17175 * linked list (GList), and then add them by a single call to
17176 * gtk_list_append_items().
17177 * Because we use g_list_prepend() to put the items into the
17178 * doubly linked list, their order will be descending (instead
17179 * of ascending when using g_list_append())
17182 for (; i<10; i++) {
17183 sprintf(buffer, "List Item with Label %d", i);
17184 list_item=gtk_list_item_new_with_label(buffer);
17185 dlist=g_list_prepend(dlist, list_item);
17186 gtk_widget_show(list_item);
17187 gtk_object_set_data(GTK_OBJECT(list_item),
17188 list_item_data_key,
17189 "ListItem with integrated Label");
17191 gtk_list_append_items(GTK_LIST(gtklist), dlist);
17193 /* Finally we want to see the window, don't we? ;) */
17194 gtk_widget_show(window);
17196 /* Fire up the main event loop of gtk */
17199 /* We get here after gtk_main_quit() has been called which
17200 * happens if the main window gets destroyed
17205 /* This is the signal handler that got connected to button
17206 * press/release events of the List
17208 void sigh_button_event( GtkWidget *gtklist,
17209 GdkEventButton *event,
17212 /* We only do something if the third (rightmost mouse button
17215 if (event->type==GDK_BUTTON_RELEASE &&
17216 event->button==3) {
17217 GList *dlist, *free_list;
17218 GtkWidget *new_prisoner;
17220 /* Fetch the currently selected list item which
17221 * will be our next prisoner ;)
17223 dlist=GTK_LIST(gtklist)->selection;
17225 new_prisoner=GTK_WIDGET(dlist->data);
17229 /* Look for already imprisoned list items, we
17230 * will put them back into the list.
17231 * Remember to free the doubly linked list that
17232 * gtk_container_children() returns
17234 dlist=gtk_container_children(GTK_CONTAINER(frame));
17237 GtkWidget *list_item;
17239 list_item=dlist->data;
17241 gtk_widget_reparent(list_item, gtklist);
17245 g_list_free(free_list);
17247 /* If we have a new prisoner, remove him from the
17248 * List and put him into the frame "Prison".
17249 * We need to unselect the item first.
17251 if (new_prisoner) {
17252 GList static_dlist;
17254 static_dlist.data=new_prisoner;
17255 static_dlist.next=NULL;
17256 static_dlist.prev=NULL;
17258 gtk_list_unselect_child(GTK_LIST(gtklist),
17260 gtk_widget_reparent(new_prisoner, frame);
17265 /* This is the signal handler that gets called if List
17266 * emits the "selection_changed" signal
17268 void sigh_print_selection( GtkWidget *gtklist,
17269 gpointer func_data)
17273 /* Fetch the doubly linked list of selected items
17274 * of the List, remember to treat this as read-only!
17276 dlist=GTK_LIST(gtklist)->selection;
17278 /* If there are no selected items there is nothing more
17279 * to do than just telling the user so
17282 g_print("Selection cleared\n");
17285 /* Ok, we got a selection and so we print it
17287 g_print("The selection is a ");
17289 /* Get the list item from the doubly linked list
17290 * and then query the data associated with list_item_data_key.
17291 * We then just print it */
17293 GtkObject *list_item;
17294 gchar *item_data_string;
17296 list_item=GTK_OBJECT(dlist->data);
17297 item_data_string=gtk_object_get_data(list_item,
17298 list_item_data_key);
17299 g_print("%s ", item_data_string);
17308 <!-- ----------------------------------------------------------------- -->
17309 <sect1> List Item Widget
17311 The ListItem widget is designed to act as a container holding up to
17312 one child, providing functions for selection/deselection just like the
17313 List widget requires them for its children.
17315 A ListItem has its own window to receive events and has its own
17316 background color which is usually white.
17318 As it is directly derived from an Item it can be treated as such by
17319 using the GTK_ITEM(ListItem) macro, see the Item widget for more on
17320 this. Usually a ListItem just holds a label to identify, e.g., a
17321 filename within a List -- therefore the convenience function
17322 gtk_list_item_new_with_label() is provided. The same effect can be
17323 achieved by creating a Label on its own, setting its alignment to
17324 xalign=0 and yalign=0.5 with a subsequent container addition to the
17327 As one is not forced to add a GtkLabel to a GtkListItem, you could
17328 also add a GtkVBox or a GtkArrow etc. to the GtkListItem.
17330 <!-- ----------------------------------------------------------------- -->
17333 AkListItem does not create new signals on its own, but inherits
17334 the signals of a Item.
17336 <!-- ----------------------------------------------------------------- -->
17340 guint gtk_list_item_get_type( void );
17343 Returns the "GtkListItem" type identifier.
17346 GtkWidget *gtk_list_item_new( void );
17349 Create a new ListItem object. The new widget is returned as a
17350 pointer to a GtkWidget object. NULL is returned on failure.
17353 GtkWidget *gtk_list_item_new_with_label( gchar *label );
17356 Create a new ListItem object, having a single GtkLabel as the sole
17357 child. The new widget is returned as a pointer to a GtkWidget
17358 object. NULL is returned on failure.
17361 void gtk_list_item_select( GtkListItem *list_item );
17364 This function is basically a wrapper around a call to gtk_item_select
17365 (GTK_ITEM (list_item)) which will emit the select signal. *Note
17366 GtkItem::, for more info.
17369 void gtk_list_item_deselect( GtkListItem *list_item );
17372 This function is basically a wrapper around a call to
17373 gtk_item_deselect (GTK_ITEM (list_item)) which will emit the deselect
17374 signal. *Note GtkItem::, for more info.
17377 GtkListItem *GTK_LIST_ITEM( gpointer obj );
17380 Cast a generic pointer to "GtkListItem *".
17383 GtkListItemClass *GTK_LIST_ITEM_CLASS( gpointer class );
17386 Cast a generic pointer to GtkListItemClass*. *Note Standard Macros::,
17390 gint GTK_IS_LIST_ITEM( gpointer obj );
17393 Determine if a generic pointer refers to a `GtkListItem' object.
17394 *Note Standard Macros::, for more info.
17396 <!-- ----------------------------------------------------------------- -->
17399 Please see the List example on this, which covers the usage of a