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>
14 <date>April 10th, 1999
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 = TRUE, 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;
8391 GtkWidget *scrolled_window, *clist;
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 a scrolled window to pack the CList widget into */
8412 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
8413 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
8414 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
8416 gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0);
8417 gtk_widget_show (scrolled_window);
8419 /* Create the CList. For this example we use 2 columns */
8420 clist = gtk_clist_new_with_titles( 2, titles);
8422 /* When a selection is made, we want to know about it. The callback
8423 * used is selection_made, and its code can be found further down */
8424 gtk_signal_connect(GTK_OBJECT(clist), "select_row",
8425 GTK_SIGNAL_FUNC(selection_made),
8428 /* It isn't necessary to shadow the border, but it looks nice :) */
8429 gtk_clist_set_shadow_type (GTK_CLIST(clist), GTK_SHADOW_OUT);
8431 /* What however is important, is that we set the column widths as
8432 * they will never be right otherwise. Note that the columns are
8433 * numbered from 0 and up (to 1 in this case).
8435 gtk_clist_set_column_width (GTK_CLIST(clist), 0, 150);
8437 /* Add the CList widget to the vertical box and show it. */
8438 gtk_container_add(GTK_CONTAINER(scrolled_window), clist);
8439 gtk_widget_show(clist);
8441 /* Create the buttons and add them to the window. See the button
8442 * tutorial for more examples and comments on this.
8444 hbox = gtk_hbox_new(FALSE, 0);
8445 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
8446 gtk_widget_show(hbox);
8448 button_add = gtk_button_new_with_label("Add List");
8449 button_clear = gtk_button_new_with_label("Clear List");
8450 button_hide_show = gtk_button_new_with_label("Hide/Show titles");
8452 gtk_box_pack_start(GTK_BOX(hbox), button_add, TRUE, TRUE, 0);
8453 gtk_box_pack_start(GTK_BOX(hbox), button_clear, TRUE, TRUE, 0);
8454 gtk_box_pack_start(GTK_BOX(hbox), button_hide_show, TRUE, TRUE, 0);
8456 /* Connect our callbacks to the three buttons */
8457 gtk_signal_connect_object(GTK_OBJECT(button_add), "clicked",
8458 GTK_SIGNAL_FUNC(button_add_clicked),
8460 gtk_signal_connect_object(GTK_OBJECT(button_clear), "clicked",
8461 GTK_SIGNAL_FUNC(button_clear_clicked),
8463 gtk_signal_connect_object(GTK_OBJECT(button_hide_show), "clicked",
8464 GTK_SIGNAL_FUNC(button_hide_show_clicked),
8467 gtk_widget_show(button_add);
8468 gtk_widget_show(button_clear);
8469 gtk_widget_show(button_hide_show);
8471 /* The interface is completely set up so we show the window and
8472 * enter the gtk_main loop.
8474 gtk_widget_show(window);
8482 <!-- ***************************************************************** -->
8483 <sect> Tree Widget <label id="sec_Tree_Widgets">
8484 <!-- ***************************************************************** -->
8486 The purpose of tree widgets is to display hierarchically-organized
8487 data. The Tree widget itself is a vertical container for widgets of
8488 type TreeItem. Tree itself is not terribly different from
8489 CList - both are derived directly from Container, and the
8490 Container methods work in the same way on Tree widgets as on
8491 CList widgets. The difference is that Tree widgets can be nested
8492 within other Tree widgets. We'll see how to do this shortly.
8494 The Tree widget has its own window, and defaults to a white
8495 background, as does CList. Also, most of the Tree methods work in
8496 the same way as the corresponding CList ones. However, Tree is
8497 not derived from CList, so you cannot use them interchangeably.
8500 <sect1> Creating a Tree
8502 A Tree is created in the usual way, using:
8505 GtkWidget *gtk_tree_new( void );
8508 Like the CList widget, a Tree will simply keep growing as more
8509 items are added to it, as well as when subtrees are expanded. For
8510 this reason, they are almost always packed into a
8511 ScrolledWindow. You might want to use gtk_widget_set_usize() on the
8512 scrolled window to ensure that it is big enough to see the tree's
8513 items, as the default size for ScrolledWindow is quite small.
8515 Now that you have a tree, you'll probably want to add some items to
8516 it. <ref id="sec_Tree_Item_Widget" name="The Tree Item Widget"> below
8517 explains the gory details of TreeItem. For now, it'll suffice to
8521 GtkWidget *gtk_tree_item_new_with_label( gchar *label );
8524 You can then add it to the tree using one of the following (see
8525 <ref id="sec_Tree_Functions" name="Functions and Macros">
8526 below for more options):
8529 void gtk_tree_append( GtkTree *tree,
8530 GtkWidget *tree_item );
8532 void gtk_tree_prepend( GtkTree *tree,
8533 GtkWidget *tree_item );
8536 Note that you must add items to a Tree one at a time - there is no
8537 equivalent to gtk_list_*_items().
8539 <!-- ----------------------------------------------------------------- -->
8540 <sect1> Adding a Subtree
8542 A subtree is created like any other Tree widget. A subtree is added
8543 to another tree beneath a tree item, using:
8546 void gtk_tree_item_set_subtree( GtkTreeItem *tree_item,
8547 GtkWidget *subtree );
8550 You do not need to call gtk_widget_show() on a subtree before or after
8551 adding it to a TreeItem. However, you <em>must</em> have added the
8552 TreeItem in question to a parent tree before calling
8553 gtk_tree_item_set_subtree(). This is because, technically, the parent
8554 of the subtree is <em>not</em> the GtkTreeItem which "owns" it, but
8555 rather the GtkTree which holds that GtkTreeItem.
8557 When you add a subtree to a TreeItem, a plus or minus sign appears
8558 beside it, which the user can click on to "expand" or "collapse" it,
8559 meaning, to show or hide its subtree. TreeItems are collapsed by
8560 default. Note that when you collapse a TreeItem, any selected
8561 items in its subtree remain selected, which may not be what the user
8564 <!-- ----------------------------------------------------------------- -->
8565 <sect1> Handling the Selection List
8567 As with CList, the Tree type has a <tt>selection</tt> field, and
8568 it is possible to control the behaviour of the tree (somewhat) by
8569 setting the selection type using:
8572 void gtk_tree_set_selection_mode( GtkTree *tree,
8573 GtkSelectionMode mode );
8576 The semantics associated with the various selection modes are
8577 described in the section on the CList widget. As with the CList
8578 widget, the "select_child", "unselect_child" (not really - see <ref
8579 id="sec_Tree_Signals" name="Signals"> below for an explanation),
8580 and "selection_changed" signals are emitted when list items are
8581 selected or unselected. However, in order to take advantage of these
8582 signals, you need to know <em>which</em> Tree widget they will be
8583 emitted by, and where to find the list of selected items.
8585 This is a source of potential confusion. The best way to explain this
8586 is that though all Tree widgets are created equal, some are more equal
8587 than others. All Tree widgets have their own X window, and can
8588 therefore receive events such as mouse clicks (if their TreeItems or
8589 their children don't catch them first!). However, to make
8590 <tt/GTK_SELECTION_SINGLE/ and <tt/GTK_SELECTION_BROWSE/ selection
8591 types behave in a sane manner, the list of selected items is specific
8592 to the topmost Tree widget in a hierarchy, known as the "root tree".
8594 Thus, accessing the <tt>selection</tt> field directly in an arbitrary
8595 Tree widget is not a good idea unless you <em>know</em> it's the root
8596 tree. Instead, use the <tt/GTK_TREE_SELECTION (Tree)/ macro, which
8597 gives the root tree's selection list as a GList pointer. Of course,
8598 this list can include items that are not in the subtree in question if
8599 the selection type is <tt/GTK_SELECTION_MULTIPLE/.
8601 Finally, the "select_child" (and "unselect_child", in theory) signals
8602 are emitted by all trees, but the "selection_changed" signal is only
8603 emitted by the root tree. Consequently, if you want to handle the
8604 "select_child" signal for a tree and all its subtrees, you will have
8605 to call gtk_signal_connect() for every subtree.
8607 <sect1> Tree Widget Internals
8609 The Tree's struct definition looks like this:
8614 GtkContainer container;
8618 GtkTree* root_tree; /* owner of selection list */
8619 GtkWidget* tree_owner;
8623 guint current_indent;
8624 guint selection_mode : 2;
8625 guint view_mode : 1;
8626 guint view_line : 1;
8630 The perils associated with accessing the <tt>selection</tt> field
8631 directly have already been mentioned. The other important fields of
8632 the struct can also be accessed with handy macros or class functions.
8633 <tt/GTK_IS_ROOT_TREE (Tree)/ returns a boolean value which
8634 indicates whether a tree is the root tree in a Tree hierarchy, while
8635 <tt/GTK_TREE_ROOT_TREE (Tree)/ returns the root tree, an object of
8636 type GtkTree (so, remember to cast it using <tt/GTK_WIDGET (Tree)/ if
8637 you want to use one of the gtk_widget_*() functions on it).
8639 Instead of directly accessing the children field of a Tree widget,
8640 it's probably best to cast it using >tt/GTK_CONTAINER (Tree)/, and
8641 pass it to the gtk_container_children() function. This creates a
8642 duplicate of the original list, so it's advisable to free it up using
8643 g_list_free() after you're done with it, or to iterate on it
8644 destructively, like this:
8647 children = gtk_container_children (GTK_CONTAINER (tree));
8649 do_something_nice (GTK_TREE_ITEM (children->data));
8650 children = g_list_remove_link (children, children);
8654 The <tt>tree_owner</tt> field is defined only in subtrees, where it
8655 points to the TreeItem widget which holds the tree in question.
8656 The <tt>level</tt> field indicates how deeply nested a particular tree
8657 is; root trees have level 0, and each successive level of subtrees has
8658 a level one greater than the parent level. This field is set only
8659 after a Tree widget is actually mapped (i.e. drawn on the screen).
8661 <sect2> Signals<label id="sec_Tree_Signals">
8664 void selection_changed( GtkTree *tree );
8667 This signal will be emitted whenever the <tt>selection</tt> field of a
8668 Tree has changed. This happens when a child of the Tree is
8669 selected or deselected.
8672 void select_child( GtkTree *tree,
8676 This signal is emitted when a child of the Tree is about to get
8677 selected. This happens on calls to gtk_tree_select_item(),
8678 gtk_tree_select_child(), on <em>all</em> button presses and calls to
8679 gtk_tree_item_toggle() and gtk_item_toggle(). It may sometimes be
8680 indirectly triggered on other occasions where children get added to or
8681 removed from the Tree.
8684 void unselect_child (GtkTree *tree,
8688 This signal is emitted when a child of the Tree is about to get
8689 deselected. As of GTK 1.0.4, this seems to only occur on calls to
8690 gtk_tree_unselect_item() or gtk_tree_unselect_child(), and perhaps on
8691 other occasions, but <em>not</em> when a button press deselects a
8692 child, nor on emission of the "toggle" signal by gtk_item_toggle().
8694 <sect2> Functions and Macros<label id="sec_Tree_Functions">
8697 guint gtk_tree_get_type( void );
8700 Returns the "GtkTree" type identifier.
8703 GtkWidget* gtk_tree_new( void );
8706 Create a new Tree object. The new widget is returned as a pointer to a
8707 GtkWidget object. NULL is returned on failure.
8710 void gtk_tree_append( GtkTree *tree,
8711 GtkWidget *tree_item );
8714 Append a tree item to a Tree.
8717 void gtk_tree_prepend( GtkTree *tree,
8718 GtkWidget *tree_item );
8721 Prepend a tree item to a Tree.
8724 void gtk_tree_insert( GtkTree *tree,
8725 GtkWidget *tree_item,
8729 Insert a tree item into a Tree at the position in the list
8730 specified by <tt>position.</tt>
8733 void gtk_tree_remove_items( GtkTree *tree,
8737 Remove a list of items (in the form of a GList *) from a Tree.
8738 Note that removing an item from a tree dereferences (and thus usually)
8739 destroys it <em>and</em> its subtree, if it has one, <em>and</em> all
8740 subtrees in that subtree. If you want to remove only one item, you
8741 can use gtk_container_remove().
8744 void gtk_tree_clear_items( GtkTree *tree,
8749 Remove the items from position <tt>start</tt> to position <tt>end</tt>
8750 from a Tree. The same warning about dereferencing applies here, as
8751 gtk_tree_clear_items() simply constructs a list and passes it to
8752 gtk_tree_remove_items().
8755 void gtk_tree_select_item( GtkTree *tree,
8759 Emits the "select_item" signal for the child at position
8760 <tt>item</tt>, thus selecting the child (unless you unselect it in a
8764 void gtk_tree_unselect_item( GtkTree *tree,
8768 Emits the "unselect_item" signal for the child at position
8769 <tt>item</tt>, thus unselecting the child.
8772 void gtk_tree_select_child( GtkTree *tree,
8773 GtkWidget *tree_item );
8776 Emits the "select_item" signal for the child <tt>tree_item</tt>, thus
8780 void gtk_tree_unselect_child( GtkTree *tree,
8781 GtkWidget *tree_item );
8784 Emits the "unselect_item" signal for the child <tt>tree_item</tt>,
8785 thus unselecting it.
8788 gint gtk_tree_child_position( GtkTree *tree,
8792 Returns the position in the tree of <tt>child</tt>, unless
8793 <tt>child</tt> is not in the tree, in which case it returns -1.
8796 void gtk_tree_set_selection_mode( GtkTree *tree,
8797 GtkSelectionMode mode );
8800 Sets the selection mode, which can be one of <tt/GTK_SELECTION_SINGLE/ (the
8801 default), <tt/GTK_SELECTION_BROWSE/, <tt/GTK_SELECTION_MULTIPLE/, or
8802 <tt/GTK_SELECTION_EXTENDED/. This is only defined for root trees, which
8803 makes sense, since the root tree "owns" the selection. Setting it for
8804 subtrees has no effect at all; the value is simply ignored.
8807 void gtk_tree_set_view_mode( GtkTree *tree,
8808 GtkTreeViewMode mode );
8811 Sets the "view mode", which can be either <tt/GTK_TREE_VIEW_LINE/ (the
8812 default) or <tt/GTK_TREE_VIEW_ITEM/. The view mode propagates from a
8813 tree to its subtrees, and can't be set exclusively to a subtree (this
8814 is not exactly true - see the example code comments).
8816 The term "view mode" is rather ambiguous - basically, it controls the
8817 way the highlight is drawn when one of a tree's children is selected.
8818 If it's <tt/GTK_TREE_VIEW_LINE/, the entire TreeItem widget is
8819 highlighted, while for <tt/GTK_TREE_VIEW_ITEM/, only the child widget
8820 (i.e., usually the label) is highlighted.
8823 void gtk_tree_set_view_lines( GtkTree *tree,
8827 Controls whether connecting lines between tree items are drawn.
8828 <tt>flag</tt> is either TRUE, in which case they are, or FALSE, in
8829 which case they aren't.
8832 GtkTree *GTK_TREE (gpointer obj);
8835 Cast a generic pointer to "GtkTree *".
8838 GtkTreeClass *GTK_TREE_CLASS (gpointer class);
8841 Cast a generic pointer to "GtkTreeClass *".
8844 gint GTK_IS_TREE (gpointer obj);
8847 Determine if a generic pointer refers to a "GtkTree" object.
8850 gint GTK_IS_ROOT_TREE (gpointer obj)
8853 Determine if a generic pointer refers to a "GtkTree" object
8854 <em>and</em> is a root tree. Though this will accept any pointer, the
8855 results of passing it a pointer that does not refer to a Tree are
8856 undefined and possibly harmful.
8859 GtkTree *GTK_TREE_ROOT_TREE (gpointer obj)
8862 Return the root tree of a pointer to a "GtkTree" object. The above
8866 GList *GTK_TREE_SELECTION( gpointer obj)
8869 Return the selection list of the root tree of a "GtkTree" object. The
8870 above warning applies here, too.
8872 <sect1> Tree Item Widget<label id="sec_Tree_Item_Widget">
8874 The TreeItem widget, like CListItem, is derived from Item,
8875 which in turn is derived from Bin. Therefore, the item itself is a
8876 generic container holding exactly one child widget, which can be of
8877 any type. The TreeItem widget has a number of extra fields, but
8878 the only one we need be concerned with is the <tt>subtree</tt> field.
8880 The definition for the TreeItem struct looks like this:
8888 GtkWidget *pixmaps_box;
8889 GtkWidget *plus_pix_widget, *minus_pix_widget;
8891 GList *pixmaps; /* pixmap node for this items color depth */
8897 The <tt>pixmaps_box</tt> field is an EventBox which catches clicks on
8898 the plus/minus symbol which controls expansion and collapsing. The
8899 <tt>pixmaps</tt> field points to an internal data structure. Since
8900 you can always obtain the subtree of a TreeItem in a (relatively)
8901 type-safe manner with the <tt/GTK_TREE_ITEM_SUBTREE (Item)/ macro,
8902 it's probably advisable never to touch the insides of a TreeItem
8903 unless you <em>really</em> know what you're doing.
8905 Since it is directly derived from an Item it can be treated as such by
8906 using the <tt/GTK_ITEM (TreeItem)/ macro. A TreeItem usually holds a
8907 label, so the convenience function gtk_list_item_new_with_label() is
8908 provided. The same effect can be achieved using code like the
8909 following, which is actually copied verbatim from
8910 gtk_tree_item_new_with_label():
8913 tree_item = gtk_tree_item_new ();
8914 label_widget = gtk_label_new (label);
8915 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
8917 gtk_container_add (GTK_CONTAINER (tree_item), label_widget);
8918 gtk_widget_show (label_widget);
8921 As one is not forced to add a Label to a TreeItem, you could
8922 also add an HBox or an Arrow, or even a Notebook (though your
8923 app will likely be quite unpopular in this case) to the TreeItem.
8925 If you remove all the items from a subtree, it will be destroyed and
8926 unparented, unless you reference it beforehand, and the TreeItem
8927 which owns it will be collapsed. So, if you want it to stick around,
8928 do something like the following:
8931 gtk_widget_ref (tree);
8932 owner = GTK_TREE(tree)->tree_owner;
8933 gtk_container_remove (GTK_CONTAINER(tree), item);
8934 if (tree->parent == NULL){
8935 gtk_tree_item_expand (GTK_TREE_ITEM(owner));
8936 gtk_tree_item_set_subtree (GTK_TREE_ITEM(owner), tree);
8939 gtk_widget_unref (tree);
8942 Finally, drag-n-drop <em>does</em> work with TreeItems. You just
8943 have to make sure that the TreeItem you want to make into a drag
8944 item or a drop site has not only been added to a Tree, but that
8945 each successive parent widget has a parent itself, all the way back to
8946 a toplevel or dialog window, when you call gtk_widget_dnd_drag_set()
8947 or gtk_widget_dnd_drop_set(). Otherwise, strange things will happen.
8951 TreeItem inherits the "select", "deselect", and "toggle" signals
8952 from Item. In addition, it adds two signals of its own, "expand"
8956 void select( GtkItem *tree_item );
8959 This signal is emitted when an item is about to be selected, either
8960 after it has been clicked on by the user, or when the program calls
8961 gtk_tree_item_select(), gtk_item_select(), or gtk_tree_select_child().
8964 void deselect( GtkItem *tree_item );
8967 This signal is emitted when an item is about to be unselected, either
8968 after it has been clicked on by the user, or when the program calls
8969 gtk_tree_item_deselect() or gtk_item_deselect(). In the case of
8970 TreeItems, it is also emitted by gtk_tree_unselect_child(), and
8971 sometimes gtk_tree_select_child().
8974 void toggle( GtkItem *tree_item );
8977 This signal is emitted when the program calls gtk_item_toggle(). The
8978 effect it has when emitted on a TreeItem is to call
8979 gtk_tree_select_child() (and never gtk_tree_unselect_child()) on the
8980 item's parent tree, if the item has a parent tree. If it doesn't,
8981 then the highlight is reversed on the item.
8984 void expand( GtkTreeItem *tree_item );
8987 This signal is emitted when the tree item's subtree is about to be
8988 expanded, that is, when the user clicks on the plus sign next to the
8989 item, or when the program calls gtk_tree_item_expand().
8992 void collapse( GtkTreeItem *tree_item );
8995 This signal is emitted when the tree item's subtree is about to be
8996 collapsed, that is, when the user clicks on the minus sign next to the
8997 item, or when the program calls gtk_tree_item_collapse().
8999 <sect2> Functions and Macros
9002 guint gtk_tree_item_get_type( void );
9005 Returns the "GtkTreeItem" type identifier.
9008 GtkWidget* gtk_tree_item_new( void );
9011 Create a new TreeItem object. The new widget is returned as a
9012 pointer to a GtkWidget object. NULL is returned on failure.
9015 GtkWidget* gtk_tree_item_new_with_label (gchar *label);
9018 Create a new TreeItem object, having a single GtkLabel as the sole
9019 child. The new widget is returned as a pointer to a GtkWidget
9020 object. NULL is returned on failure.
9023 void gtk_tree_item_select( GtkTreeItem *tree_item );
9026 This function is basically a wrapper around a call to
9027 <tt>gtk_item_select (GTK_ITEM (tree_item))</tt> which will emit the
9031 void gtk_tree_item_deselect( GtkTreeItem *tree_item );
9034 This function is basically a wrapper around a call to
9035 gtk_item_deselect (GTK_ITEM (tree_item)) which will emit the deselect
9039 void gtk_tree_item_set_subtree( GtkTreeItem *tree_item,
9040 GtkWidget *subtree );
9043 This function adds a subtree to tree_item, showing it if tree_item is
9044 expanded, or hiding it if tree_item is collapsed. Again, remember that
9045 the tree_item must have already been added to a tree for this to work.
9048 void gtk_tree_item_remove_subtree( GtkTreeItem *tree_item );
9051 This removes all of tree_item's subtree's children (thus unreferencing
9052 and destroying it, any of its children's subtrees, and so on...), then
9053 removes the subtree itself, and hides the plus/minus sign.
9056 void gtk_tree_item_expand( GtkTreeItem *tree_item );
9059 This emits the "expand" signal on tree_item, which expands it.
9062 void gtk_tree_item_collapse( GtkTreeItem *tree_item );
9065 This emits the "collapse" signal on tree_item, which collapses it.
9068 GtkTreeItem *GTK_TREE_ITEM (gpointer obj)
9071 Cast a generic pointer to "GtkTreeItem *".
9074 GtkTreeItemClass *GTK_TREE_ITEM_CLASS (gpointer obj)
9077 Cast a generic pointer to "GtkTreeItemClass".
9080 gint GTK_IS_TREE_ITEM (gpointer obj)
9083 Determine if a generic pointer refers to a "GtkTreeItem" object.
9086 GtkWidget GTK_TREE_ITEM_SUBTREE (gpointer obj)
9089 Returns a tree item's subtree (<tt/obj/ should point to a
9090 "GtkTreeItem" object).
9092 <sect1> Tree Example
9094 This is somewhat like the tree example in testgtk.c, but a lot less
9095 complete (although much better commented). It puts up a window with a
9096 tree, and connects all the signals for the relevant objects, so you
9097 can see when they are emitted.
9100 /* example-start tree tree.c */
9102 #include <gtk/gtk.h>
9104 /* for all the GtkItem:: and GtkTreeItem:: signals */
9105 static void cb_itemsignal (GtkWidget *item, gchar *signame)
9110 /* It's a Bin, so it has one child, which we know to be a
9111 label, so get that */
9112 label = GTK_LABEL (GTK_BIN (item)->child);
9113 /* Get the text of the label */
9114 gtk_label_get (label, &name);
9115 /* Get the level of the tree which the item is in */
9116 g_print ("%s called for item %s->%p, level %d\n", signame, name,
9117 item, GTK_TREE (item->parent)->level);
9120 /* Note that this is never called */
9121 static void cb_unselect_child (GtkWidget *root_tree, GtkWidget *child,
9124 g_print ("unselect_child called for root tree %p, subtree %p, child %p\n",
9125 root_tree, subtree, child);
9128 /* Note that this is called every time the user clicks on an item,
9129 whether it is already selected or not. */
9130 static void cb_select_child (GtkWidget *root_tree, GtkWidget *child,
9133 g_print ("select_child called for root tree %p, subtree %p, child %p\n",
9134 root_tree, subtree, child);
9137 static void cb_selection_changed (GtkWidget *tree)
9141 g_print ("selection_change called for tree %p\n", tree);
9142 g_print ("selected objects are:\n");
9144 i = GTK_TREE_SELECTION(tree);
9150 /* Get a GtkWidget pointer from the list node */
9151 item = GTK_WIDGET (i->data);
9152 label = GTK_LABEL (GTK_BIN (item)->child);
9153 gtk_label_get (label, &name);
9154 g_print ("\t%s on level %d\n", name, GTK_TREE
9155 (item->parent)->level);
9160 int main (int argc, char *argv[])
9162 GtkWidget *window, *scrolled_win, *tree;
9163 static gchar *itemnames[] = {"Foo", "Bar", "Baz", "Quux",
9167 gtk_init (&argc, &argv);
9169 /* a generic toplevel window */
9170 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9171 gtk_signal_connect (GTK_OBJECT(window), "delete_event",
9172 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
9173 gtk_container_set_border_width (GTK_CONTAINER(window), 5);
9175 /* A generic scrolled window */
9176 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
9177 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
9178 GTK_POLICY_AUTOMATIC,
9179 GTK_POLICY_AUTOMATIC);
9180 gtk_widget_set_usize (scrolled_win, 150, 200);
9181 gtk_container_add (GTK_CONTAINER(window), scrolled_win);
9182 gtk_widget_show (scrolled_win);
9184 /* Create the root tree */
9185 tree = gtk_tree_new();
9186 g_print ("root tree is %p\n", tree);
9187 /* connect all GtkTree:: signals */
9188 gtk_signal_connect (GTK_OBJECT(tree), "select_child",
9189 GTK_SIGNAL_FUNC(cb_select_child), tree);
9190 gtk_signal_connect (GTK_OBJECT(tree), "unselect_child",
9191 GTK_SIGNAL_FUNC(cb_unselect_child), tree);
9192 gtk_signal_connect (GTK_OBJECT(tree), "selection_changed",
9193 GTK_SIGNAL_FUNC(cb_selection_changed), tree);
9194 /* Add it to the scrolled window */
9195 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW(scrolled_win),
9197 /* Set the selection mode */
9198 gtk_tree_set_selection_mode (GTK_TREE(tree),
9199 GTK_SELECTION_MULTIPLE);
9201 gtk_widget_show (tree);
9203 for (i = 0; i < 5; i++){
9204 GtkWidget *subtree, *item;
9207 /* Create a tree item */
9208 item = gtk_tree_item_new_with_label (itemnames[i]);
9209 /* Connect all GtkItem:: and GtkTreeItem:: signals */
9210 gtk_signal_connect (GTK_OBJECT(item), "select",
9211 GTK_SIGNAL_FUNC(cb_itemsignal), "select");
9212 gtk_signal_connect (GTK_OBJECT(item), "deselect",
9213 GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
9214 gtk_signal_connect (GTK_OBJECT(item), "toggle",
9215 GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
9216 gtk_signal_connect (GTK_OBJECT(item), "expand",
9217 GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
9218 gtk_signal_connect (GTK_OBJECT(item), "collapse",
9219 GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
9220 /* Add it to the parent tree */
9221 gtk_tree_append (GTK_TREE(tree), item);
9222 /* Show it - this can be done at any time */
9223 gtk_widget_show (item);
9224 /* Create this item's subtree */
9225 subtree = gtk_tree_new();
9226 g_print ("-> item %s->%p, subtree %p\n", itemnames[i], item,
9229 /* This is still necessary if you want these signals to be called
9230 for the subtree's children. Note that selection_change will be
9231 signalled for the root tree regardless. */
9232 gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
9233 GTK_SIGNAL_FUNC(cb_select_child), subtree);
9234 gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
9235 GTK_SIGNAL_FUNC(cb_unselect_child), subtree);
9236 /* This has absolutely no effect, because it is completely ignored
9238 gtk_tree_set_selection_mode (GTK_TREE(subtree),
9239 GTK_SELECTION_SINGLE);
9240 /* Neither does this, but for a rather different reason - the
9241 view_mode and view_line values of a tree are propagated to
9242 subtrees when they are mapped. So, setting it later on would
9243 actually have a (somewhat unpredictable) effect */
9244 gtk_tree_set_view_mode (GTK_TREE(subtree), GTK_TREE_VIEW_ITEM);
9245 /* Set this item's subtree - note that you cannot do this until
9246 AFTER the item has been added to its parent tree! */
9247 gtk_tree_item_set_subtree (GTK_TREE_ITEM(item), subtree);
9249 for (j = 0; j < 5; j++){
9252 /* Create a subtree item, in much the same way */
9253 subitem = gtk_tree_item_new_with_label (itemnames[j]);
9254 /* Connect all GtkItem:: and GtkTreeItem:: signals */
9255 gtk_signal_connect (GTK_OBJECT(subitem), "select",
9256 GTK_SIGNAL_FUNC(cb_itemsignal), "select");
9257 gtk_signal_connect (GTK_OBJECT(subitem), "deselect",
9258 GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
9259 gtk_signal_connect (GTK_OBJECT(subitem), "toggle",
9260 GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
9261 gtk_signal_connect (GTK_OBJECT(subitem), "expand",
9262 GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
9263 gtk_signal_connect (GTK_OBJECT(subitem), "collapse",
9264 GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
9265 g_print ("-> -> item %s->%p\n", itemnames[j], subitem);
9266 /* Add it to its parent tree */
9267 gtk_tree_append (GTK_TREE(subtree), subitem);
9269 gtk_widget_show (subitem);
9273 /* Show the window and loop endlessly */
9274 gtk_widget_show (window);
9281 <!-- ***************************************************************** -->
9283 <!-- ***************************************************************** -->
9285 There are two ways to create menus: there's the easy way, and there's
9286 the hard way. Both have their uses, but you can usually use the
9287 Itemfactory (the easy way). The "hard" way is to create all the menus
9288 using the calls directly. The easy way is to use the gtk_item_factory
9289 calls. This is much simpler, but there are advantages and
9290 disadvantages to each approach.
9292 The Itemfactory is much easier to use, and to add new menus to,
9293 although writing a few wrapper functions to create menus using the
9294 manual method could go a long way towards usability. With the
9295 Itemfactory, it is not possible to add images or the character '/' to
9298 <!-- ----------------------------------------------------------------- -->
9299 <sect1>Manual Menu Creation
9301 In the true tradition of teaching, we'll show you the hard way
9304 There are three widgets that go into making a menubar and submenus:
9306 <item>a menu item, which is what the user wants to select, e.g.,
9308 <item>a menu, which acts as a container for the menu items, and
9309 <item>a menubar, which is a container for each of the individual
9313 This is slightly complicated by the fact that menu item widgets are
9314 used for two different things. They are both the widgets that are
9315 packed into the menu, and the widget that is packed into the menubar,
9316 which, when selected, activates the menu.
9318 Let's look at the functions that are used to create menus and
9319 menubars. This first function is used to create a new menubar.
9323 GtkWidget *gtk_menu_bar_new( void );
9327 This rather self explanatory function creates a new menubar. You use
9328 gtk_container_add to pack this into a window, or the box_pack
9329 functions to pack it into a box - the same as buttons.
9332 GtkWidget *gtk_menu_new( void );
9335 This function returns a pointer to a new menu; it is never actually
9336 shown (with gtk_widget_show), it is just a container for the menu
9337 items. I hope this will become more clear when you look at the
9340 The next two calls are used to create menu items that are packed into
9341 the menu (and menubar).
9344 GtkWidget *gtk_menu_item_new( void );
9350 GtkWidget *gtk_menu_item_new_with_label( const char *label );
9353 These calls are used to create the menu items that are to be
9354 displayed. Remember to differentiate between a "menu" as created with
9355 gtk_menu_new and a "menu item" as created by the gtk_menu_item_new
9356 functions. The menu item will be an actual button with an associated
9357 action, whereas a menu will be a container holding menu items.
9359 The gtk_menu_new_with_label and gtk_menu_new functions are just as
9360 you'd expect after reading about the buttons. One creates a new menu
9361 item with a label already packed into it, and the other just creates a
9364 Once you've created a menu item you have to put it into a menu. This
9365 is done using the function gtk_menu_append. In order to capture when
9366 the item is selected by the user, we need to connect to the
9367 <tt/activate/ signal in the usual way. So, if we wanted to create a
9368 standard <tt/File/ menu, with the options <tt/Open/, <tt/Save/, and
9369 <tt/Quit/, the code would look something like:
9372 file_menu = gtk_menu_new (); /* Don't need to show menus */
9374 /* Create the menu items */
9375 open_item = gtk_menu_item_new_with_label ("Open");
9376 save_item = gtk_menu_item_new_with_label ("Save");
9377 quit_item = gtk_menu_item_new_with_label ("Quit");
9379 /* Add them to the menu */
9380 gtk_menu_append (GTK_MENU (file_menu), open_item);
9381 gtk_menu_append (GTK_MENU (file_menu), save_item);
9382 gtk_menu_append (GTK_MENU (file_menu), quit_item);
9384 /* Attach the callback functions to the activate signal */
9385 gtk_signal_connect_object (GTK_OBJECT (open_items), "activate",
9386 GTK_SIGNAL_FUNC (menuitem_response),
9387 (gpointer) "file.open");
9388 gtk_signal_connect_object (GTK_OBJECT (save_items), "activate",
9389 GTK_SIGNAL_FUNC (menuitem_response),
9390 (gpointer) "file.save");
9392 /* We can attach the Quit menu item to our exit function */
9393 gtk_signal_connect_object (GTK_OBJECT (quit_items), "activate",
9394 GTK_SIGNAL_FUNC (destroy),
9395 (gpointer) "file.quit");
9397 /* We do need to show menu items */
9398 gtk_widget_show (open_item);
9399 gtk_widget_show (save_item);
9400 gtk_widget_show (quit_item);
9403 At this point we have our menu. Now we need to create a menubar and a
9404 menu item for the <tt/File/ entry, to which we add our menu. The code
9408 menu_bar = gtk_menu_bar_new ();
9409 gtk_container_add (GTK_CONTAINER (window), menu_bar);
9410 gtk_widget_show (menu_bar);
9412 file_item = gtk_menu_item_new_with_label ("File");
9413 gtk_widget_show (file_item);
9416 Now we need to associate the menu with <tt/file_item/. This is done
9420 void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
9421 GtkWidget *submenu );
9424 So, our example would continue with
9427 gtk_menu_item_set_submenu (GTK_MENU_ITEM (file_item), file_menu);
9430 All that is left to do is to add the menu to the menubar, which is
9431 accomplished using the function
9434 void gtk_menu_bar_append( GtkMenuBar *menu_bar,
9435 GtkWidget *menu_item );
9438 which in our case looks like this:
9441 gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), file_item);
9444 If we wanted the menu right justified on the menubar, such as help
9445 menus often are, we can use the following function (again on
9446 <tt/file_item/ in the current example) before attaching it to the
9450 void gtk_menu_item_right_justify( GtkMenuItem *menu_item );
9453 Here is a summary of the steps needed to create a menu bar with menus
9457 <item> Create a new menu using gtk_menu_new()
9458 <item> Use multiple calls to gtk_menu_item_new() for each item you
9459 wish to have on your menu. And use gtk_menu_append() to put each of
9460 these new items on to the menu.
9461 <item> Create a menu item using gtk_menu_item_new(). This will be the
9462 root of the menu, the text appearing here will be on the menubar
9464 <item>Use gtk_menu_item_set_submenu() to attach the menu to the root
9465 menu item (the one created in the above step).
9466 <item> Create a new menubar using gtk_menu_bar_new. This step only
9467 needs to be done once when creating a series of menus on one menu bar.
9468 <item> Use gtk_menu_bar_append() to put the root menu onto the menubar.
9471 Creating a popup menu is nearly the same. The difference is that the
9472 menu is not posted "automatically" by a menubar, but explicitly by
9473 calling the function gtk_menu_popup() from a button-press event, for
9474 example. Take these steps:
9477 <item>Create an event handling function. It needs to have the
9480 static gint handler (GtkWidget *widget,
9483 and it will use the event to find out where to pop up the menu.
9484 <item>In the event handler, if the event is a mouse button press,
9485 treat <tt>event</tt> as a button event (which it is) and use it as
9486 shown in the sample code to pass information to gtk_menu_popup().
9487 <item>Bind that event handler to a widget with
9489 gtk_signal_connect_object (GTK_OBJECT (widget), "event",
9490 GTK_SIGNAL_FUNC (handler),
9493 where <tt>widget</tt> is the widget you are binding to,
9494 <tt>handler</tt> is the handling function, and <tt>menu</tt> is a menu
9495 created with gtk_menu_new(). This can be a menu which is also posted
9496 by a menu bar, as shown in the sample code.
9499 <!-- ----------------------------------------------------------------- -->
9500 <sect1>Manual Menu Example
9502 That should about do it. Let's take a look at an example to help clarify.
9505 /* example-start menu menu.c */
9507 #include <gtk/gtk.h>
9509 static gint button_press (GtkWidget *, GdkEvent *);
9510 static void menuitem_response (gchar *);
9518 GtkWidget *menu_bar;
9519 GtkWidget *root_menu;
9520 GtkWidget *menu_items;
9526 gtk_init (&argc, &argv);
9528 /* create a new window */
9529 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9530 gtk_widget_set_usize (GTK_WIDGET (window), 200, 100);
9531 gtk_window_set_title (GTK_WINDOW (window), "GTK Menu Test");
9532 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
9533 (GtkSignalFunc) gtk_main_quit, NULL);
9535 /* Init the menu-widget, and remember -- never
9536 * gtk_show_widget() the menu widget!!
9537 * This is the menu that holds the menu items, the one that
9538 * will pop up when you click on the "Root Menu" in the app */
9539 menu = gtk_menu_new ();
9541 /* Next we make a little loop that makes three menu-entries for "test-menu".
9542 * Notice the call to gtk_menu_append. Here we are adding a list of
9543 * menu items to our menu. Normally, we'd also catch the "clicked"
9544 * signal on each of the menu items and setup a callback for it,
9545 * but it's omitted here to save space. */
9547 for (i = 0; i < 3; i++)
9549 /* Copy the names to the buf. */
9550 sprintf (buf, "Test-undermenu - %d", i);
9552 /* Create a new menu-item with a name... */
9553 menu_items = gtk_menu_item_new_with_label (buf);
9555 /* ...and add it to the menu. */
9556 gtk_menu_append (GTK_MENU (menu), menu_items);
9558 /* Do something interesting when the menuitem is selected */
9559 gtk_signal_connect_object (GTK_OBJECT (menu_items), "activate",
9560 GTK_SIGNAL_FUNC (menuitem_response), (gpointer) g_strdup (buf));
9562 /* Show the widget */
9563 gtk_widget_show (menu_items);
9566 /* This is the root menu, and will be the label
9567 * displayed on the menu bar. There won't be a signal handler attached,
9568 * as it only pops up the rest of the menu when pressed. */
9569 root_menu = gtk_menu_item_new_with_label ("Root Menu");
9571 gtk_widget_show (root_menu);
9573 /* Now we specify that we want our newly created "menu" to be the menu
9574 * for the "root menu" */
9575 gtk_menu_item_set_submenu (GTK_MENU_ITEM (root_menu), menu);
9577 /* A vbox to put a menu and a button in: */
9578 vbox = gtk_vbox_new (FALSE, 0);
9579 gtk_container_add (GTK_CONTAINER (window), vbox);
9580 gtk_widget_show (vbox);
9582 /* Create a menu-bar to hold the menus and add it to our main window */
9583 menu_bar = gtk_menu_bar_new ();
9584 gtk_box_pack_start (GTK_BOX (vbox), menu_bar, FALSE, FALSE, 2);
9585 gtk_widget_show (menu_bar);
9587 /* Create a button to which to attach menu as a popup */
9588 button = gtk_button_new_with_label ("press me");
9589 gtk_signal_connect_object (GTK_OBJECT (button), "event",
9590 GTK_SIGNAL_FUNC (button_press), GTK_OBJECT (menu));
9591 gtk_box_pack_end (GTK_BOX (vbox), button, TRUE, TRUE, 2);
9592 gtk_widget_show (button);
9594 /* And finally we append the menu-item to the menu-bar -- this is the
9595 * "root" menu-item I have been raving about =) */
9596 gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), root_menu);
9598 /* always display the window as the last step so it all splashes on
9599 * the screen at once. */
9600 gtk_widget_show (window);
9607 /* Respond to a button-press by posting a menu passed in as widget.
9609 * Note that the "widget" argument is the menu being posted, NOT
9610 * the button that was pressed.
9613 static gint button_press (GtkWidget *widget, GdkEvent *event)
9616 if (event->type == GDK_BUTTON_PRESS) {
9617 GdkEventButton *bevent = (GdkEventButton *) event;
9618 gtk_menu_popup (GTK_MENU (widget), NULL, NULL, NULL, NULL,
9619 bevent->button, bevent->time);
9620 /* Tell calling code that we have handled this event; the buck
9625 /* Tell calling code that we have not handled this event; pass it on. */
9630 /* Print a string when a menu item is selected */
9632 static void menuitem_response (gchar *string)
9634 printf ("%s\n", string);
9639 You may also set a menu item to be insensitive and, using an accelerator
9640 table, bind keys to menu functions.
9642 <!-- ----------------------------------------------------------------- -->
9643 <sect1>Using ItemFactory
9645 Now that we've shown you the hard way, here's how you do it using the
9646 gtk_item_factory calls.
9648 <!-- ----------------------------------------------------------------- -->
9649 <sect1>Item Factory Example
9651 Here is an example using the GTK item factory.
9654 /* example-start menu itemfactory.c */
9656 #include <gtk/gtk.h>
9657 #include <strings.h>
9659 /* Obligatory basic callback */
9660 static void print_hello( GtkWidget *w,
9663 g_message ("Hello, World!\n");
9666 /* This is the GtkItemFactoryEntry structure used to generate new menus.
9667 Item 1: The menu path. The letter after the underscore indicates an
9668 accelerator key once the menu is open.
9669 Item 2: The accelerator key for the entry
9670 Item 3: The callback function.
9671 Item 4: The callback action. This changes the parameters with
9672 which the function is called. The default is 0.
9673 Item 5: The item type, used to define what kind of an item it is.
9674 Here are the possible values:
9678 "<Title>" -> create a title item
9679 "<Item>" -> create a simple item
9680 "<CheckItem>" -> create a check item
9681 "<ToggleItem>" -> create a toggle item
9682 "<RadioItem>" -> create a radio item
9683 <path> -> path of a radio item to link against
9684 "<Separator>" -> create a separator
9685 "<Branch>" -> create an item to hold sub items (optional)
9686 "<LastBranch>" -> create a right justified branch
9689 static GtkItemFactoryEntry menu_items[] = {
9690 { "/_File", NULL, NULL, 0, "<Branch>" },
9691 { "/File/_New", "<control>N", print_hello, 0, NULL },
9692 { "/File/_Open", "<control>O", print_hello, 0, NULL },
9693 { "/File/_Save", "<control>S", print_hello, 0, NULL },
9694 { "/File/Save _As", NULL, NULL, 0, NULL },
9695 { "/File/sep1", NULL, NULL, 0, "<Separator>" },
9696 { "/File/Quit", "<control>Q", gtk_main_quit, 0, NULL },
9697 { "/_Options", NULL, NULL, 0, "<Branch>" },
9698 { "/Options/Test", NULL, NULL, 0, NULL },
9699 { "/_Help", NULL, NULL, 0, "<LastBranch>" },
9700 { "/_Help/About", NULL, NULL, 0, NULL },
9704 void get_main_menu( GtkWidget *window,
9705 GtkWidget **menubar )
9707 GtkItemFactory *item_factory;
9708 GtkAccelGroup *accel_group;
9709 gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
9711 accel_group = gtk_accel_group_new ();
9713 /* This function initializes the item factory.
9714 Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
9715 or GTK_TYPE_OPTION_MENU.
9716 Param 2: The path of the menu.
9717 Param 3: A pointer to a gtk_accel_group. The item factory sets up
9718 the accelerator table while generating menus.
9721 item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>",
9724 /* This function generates the menu items. Pass the item factory,
9725 the number of items in the array, the array itself, and any
9726 callback data for the the menu items. */
9727 gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
9729 /* Attach the new accelerator group to the window. */
9730 gtk_accel_group_attach (accel_group, GTK_OBJECT (window));
9733 /* Finally, return the actual menu bar created by the item factory. */
9734 *menubar = gtk_item_factory_get_widget (item_factory, "<main>");
9741 GtkWidget *main_vbox;
9744 gtk_init (&argc, &argv);
9746 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9747 gtk_signal_connect (GTK_OBJECT (window), "destroy",
9748 GTK_SIGNAL_FUNC (gtk_main_quit),
9750 gtk_window_set_title (GTK_WINDOW(window), "Item Factory");
9751 gtk_widget_set_usize (GTK_WIDGET(window), 300, 200);
9753 main_vbox = gtk_vbox_new (FALSE, 1);
9754 gtk_container_border_width (GTK_CONTAINER (main_vbox), 1);
9755 gtk_container_add (GTK_CONTAINER (window), main_vbox);
9756 gtk_widget_show (main_vbox);
9758 get_main_menu (window, &menubar);
9759 gtk_box_pack_start (GTK_BOX (main_vbox), menubar, FALSE, TRUE, 0);
9760 gtk_widget_show (menubar);
9762 gtk_widget_show (window);
9771 For now, there's only this example. An explanation and lots 'o' comments
9774 <!-- ***************************************************************** -->
9776 <!-- ***************************************************************** -->
9778 The Text widget allows multiple lines of text to be displayed and
9779 edited. It supports both multi-colored and multi-font text, allowing
9780 them to be mixed in any way we wish. It also has a wide set of key
9781 based text editing commands, which are compatible with Emacs.
9783 The text widget supports full cut-and-paste facilities, including the
9784 use of double- and triple-click to select a word and a whole line,
9787 <!-- ----------------------------------------------------------------- -->
9788 <sect1>Creating and Configuring a Text box
9790 There is only one function for creating a new Text widget.
9793 GtkWidget *gtk_text_new( GtkAdjustment *hadj,
9794 GtkAdjustment *vadj );
9797 The arguments allow us to give the Text widget pointers to Adjustments
9798 that can be used to track the viewing position of the widget. Passing
9799 NULL values to either or both of these arguments will cause the
9800 gtk_text_new function to create its own.
9803 void gtk_text_set_adjustments( GtkText *text,
9804 GtkAdjustment *hadj,
9805 GtkAdjustment *vadj );
9808 The above function allows the horizontal and vertical adjustments of a
9809 text widget to be changed at any time.
9811 The text widget will not automatically create its own scrollbars when
9812 the amount of text to be displayed is too long for the display
9813 window. We therefore have to create and add them to the display layout
9817 vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
9818 gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, FALSE, 0);
9819 gtk_widget_show (vscrollbar);
9822 The above code snippet creates a new vertical scrollbar, and attaches
9823 it to the vertical adjustment of the text widget, <tt/text/. It then
9824 packs it into a box in the normal way.
9826 Note, currently the Text widget does not support horizontal
9829 There are two main ways in which a Text widget can be used: to allow
9830 the user to edit a body of text, or to allow us to display multiple
9831 lines of text to the user. In order for us to switch between these
9832 modes of operation, the text widget has the following function:
9835 void gtk_text_set_editable( GtkText *text,
9839 The <tt/editable/ argument is a TRUE or FALSE value that specifies
9840 whether the user is permitted to edit the contents of the Text
9841 widget. When the text widget is editable, it will display a cursor at
9842 the current insertion point.
9844 You are not, however, restricted to just using the text widget in
9845 these two modes. You can toggle the editable state of the text widget
9846 at any time, and can insert text at any time.
9848 The text widget wraps lines of text that are too long to fit onto a
9849 single line of the display window. Its default behaviour is to break
9850 words across line breaks. This can be changed using the next function:
9853 void gtk_text_set_word_wrap( GtkText *text,
9857 Using this function allows us to specify that the text widget should
9858 wrap long lines on word boundaries. The <tt/word_wrap/ argument is a
9859 TRUE or FALSE value.
9861 <!-- ----------------------------------------------------------------- -->
9862 <sect1>Text Manipulation
9864 The current insertion point of a Text widget can be set using
9866 void gtk_text_set_point( GtkText *text,
9870 where <tt/index/ is the position to set the insertion point.
9872 Analogous to this is the function for getting the current insertion
9876 guint gtk_text_get_point( GtkText *text );
9879 A function that is useful in combination with the above two functions
9883 guint gtk_text_get_length( GtkText *text );
9886 which returns the current length of the Text widget. The length is the
9887 number of characters that are within the text block of the widget,
9888 including characters such as newline, which marks the end of
9891 In order to insert text at the current insertion point of a Text
9892 widget, the function gtk_text_insert is used, which also allows us to
9893 specify background and foreground colors and a font for the text.
9896 void gtk_text_insert( GtkText *text,
9904 Passing a value of <tt/NULL/ in as the value for the foreground color,
9905 background color or font will result in the values set within the
9906 widget style to be used. Using a value of <tt/-1/ for the length
9907 parameter will result in the whole of the text string given being
9910 The text widget is one of the few within GTK that redraws itself
9911 dynamically, outside of the gtk_main function. This means that all
9912 changes to the contents of the text widget take effect
9913 immediately. This may be undesirable when performing multiple changes
9914 to the text widget. In order to allow us to perform multiple updates
9915 to the text widget without it continuously redrawing, we can freeze
9916 the widget, which temporarily stops it from automatically redrawing
9917 itself every time it is changed. We can then thaw the widget after our
9918 updates are complete.
9920 The following two functions perform this freeze and thaw action:
9923 void gtk_text_freeze( GtkText *text );
9925 void gtk_text_thaw( GtkText *text );
9928 Text is deleted from the text widget relative to the current insertion
9929 point by the following two functions. The return value is a TRUE or
9930 FALSE indicator of whether the operation was successful.
9933 gint gtk_text_backward_delete( GtkText *text,
9936 gint gtk_text_forward_delete ( GtkText *text,
9940 If you want to retrieve the contents of the text widget, then the
9941 macro <tt/GTK_TEXT_INDEX(t, index)/ allows you to retrieve the
9942 character at position <tt/index/ within the text widget <tt/t/.
9944 To retrieve larger blocks of text, we can use the function
9947 gchar *gtk_editable_get_chars( GtkEditable *editable,
9952 This is a function of the parent class of the text widget. A value of
9953 -1 as <tt/end_pos/ signifies the end of the text. The index of the
9956 The function allocates a new chunk of memory for the text block, so
9957 don't forget to free it with a call to g_free when you have finished
9960 <!-- ----------------------------------------------------------------- -->
9961 <sect1>Keyboard Shortcuts
9963 The text widget has a number of pre-installed keyboard shortcuts for
9964 common editing, motion and selection functions. These are accessed
9965 using Control and Alt key combinations.
9967 In addition to these, holding down the Control key whilst using cursor
9968 key movement will move the cursor by words rather than
9969 characters. Holding down Shift whilst using cursor movement will
9970 extend the selection.
9972 <sect2>Motion Shortcuts
9975 <item> Ctrl-A Beginning of line
9976 <item> Ctrl-E End of line
9977 <item> Ctrl-N Next Line
9978 <item> Ctrl-P Previous Line
9979 <item> Ctrl-B Backward one character
9980 <item> Ctrl-F Forward one character
9981 <item> Alt-B Backward one word
9982 <item> Alt-F Forward one word
9985 <sect2>Editing Shortcuts
9988 <item> Ctrl-H Delete Backward Character (Backspace)
9989 <item> Ctrl-D Delete Forward Character (Delete)
9990 <item> Ctrl-W Delete Backward Word
9991 <item> Alt-D Delete Forward Word
9992 <item> Ctrl-K Delete to end of line
9993 <item> Ctrl-U Delete line
9996 <sect2>Selection Shortcuts
9999 <item> Ctrl-X Cut to clipboard
10000 <item> Ctrl-C Copy to clipboard
10001 <item> Ctrl-V Paste from clipboard
10004 <!-- ----------------------------------------------------------------- -->
10005 <sect1>A GtkText Example
10008 /* example-start text text.c */
10013 #include <gtk/gtk.h>
10015 void text_toggle_editable (GtkWidget *checkbutton,
10018 gtk_text_set_editable(GTK_TEXT(text),
10019 GTK_TOGGLE_BUTTON(checkbutton)->active);
10022 void text_toggle_word_wrap (GtkWidget *checkbutton,
10025 gtk_text_set_word_wrap(GTK_TEXT(text),
10026 GTK_TOGGLE_BUTTON(checkbutton)->active);
10029 void close_application( GtkWidget *widget, gpointer data )
10034 int main (int argc, char *argv[])
10042 GtkWidget *separator;
10044 GtkWidget *vscrollbar;
10048 GdkFont *fixed_font;
10052 gtk_init (&argc, &argv);
10054 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
10055 gtk_widget_set_usize (window, 600, 500);
10056 gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, FALSE);
10057 gtk_signal_connect (GTK_OBJECT (window), "destroy",
10058 GTK_SIGNAL_FUNC(close_application),
10060 gtk_window_set_title (GTK_WINDOW (window), "Text Widget Example");
10061 gtk_container_set_border_width (GTK_CONTAINER (window), 0);
10064 box1 = gtk_vbox_new (FALSE, 0);
10065 gtk_container_add (GTK_CONTAINER (window), box1);
10066 gtk_widget_show (box1);
10069 box2 = gtk_vbox_new (FALSE, 10);
10070 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
10071 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
10072 gtk_widget_show (box2);
10075 table = gtk_table_new (2, 2, FALSE);
10076 gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
10077 gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
10078 gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
10079 gtk_widget_show (table);
10081 /* Create the GtkText widget */
10082 text = gtk_text_new (NULL, NULL);
10083 gtk_text_set_editable (GTK_TEXT (text), TRUE);
10084 gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
10085 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
10086 GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
10087 gtk_widget_show (text);
10089 /* Add a vertical scrollbar to the GtkText widget */
10090 vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
10091 gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
10092 GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
10093 gtk_widget_show (vscrollbar);
10095 /* Get the system color map and allocate the color red */
10096 cmap = gdk_colormap_get_system();
10097 color.red = 0xffff;
10100 if (!gdk_color_alloc(cmap, &color)) {
10101 g_error("couldn't allocate color");
10104 /* Load a fixed font */
10105 fixed_font = gdk_font_load ("-misc-fixed-medium-r-*-*-*-140-*-*-*-*-*-*");
10107 /* Realizing a widget creates a window for it,
10108 * ready for us to insert some text */
10109 gtk_widget_realize (text);
10111 /* Freeze the text widget, ready for multiple updates */
10112 gtk_text_freeze (GTK_TEXT (text));
10114 /* Insert some colored text */
10115 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
10117 gtk_text_insert (GTK_TEXT (text), NULL, &color, NULL,
10119 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
10120 "text and different ", -1);
10121 gtk_text_insert (GTK_TEXT (text), fixed_font, &text->style->black, NULL,
10124 /* Load the file text.c into the text window */
10126 infile = fopen("text.c", "r");
10134 nchars = fread(buffer, 1, 1024, infile);
10135 gtk_text_insert (GTK_TEXT (text), fixed_font, NULL,
10136 NULL, buffer, nchars);
10145 /* Thaw the text widget, allowing the updates to become visible */
10146 gtk_text_thaw (GTK_TEXT (text));
10148 hbox = gtk_hbutton_box_new ();
10149 gtk_box_pack_start (GTK_BOX (box2), hbox, FALSE, FALSE, 0);
10150 gtk_widget_show (hbox);
10152 check = gtk_check_button_new_with_label("Editable");
10153 gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, FALSE, 0);
10154 gtk_signal_connect (GTK_OBJECT(check), "toggled",
10155 GTK_SIGNAL_FUNC(text_toggle_editable), text);
10156 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);
10157 gtk_widget_show (check);
10158 check = gtk_check_button_new_with_label("Wrap Words");
10159 gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, TRUE, 0);
10160 gtk_signal_connect (GTK_OBJECT(check), "toggled",
10161 GTK_SIGNAL_FUNC(text_toggle_word_wrap), text);
10162 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), FALSE);
10163 gtk_widget_show (check);
10165 separator = gtk_hseparator_new ();
10166 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
10167 gtk_widget_show (separator);
10169 box2 = gtk_vbox_new (FALSE, 10);
10170 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
10171 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
10172 gtk_widget_show (box2);
10174 button = gtk_button_new_with_label ("close");
10175 gtk_signal_connect (GTK_OBJECT (button), "clicked",
10176 GTK_SIGNAL_FUNC(close_application),
10178 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
10179 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
10180 gtk_widget_grab_default (button);
10181 gtk_widget_show (button);
10183 gtk_widget_show (window);
10193 <!-- ***************************************************************** -->
10194 <sect> Undocumented Widgets
10195 <!-- ***************************************************************** -->
10197 These all require authors! :) Please consider contributing to our
10200 If you must use one of these widgets that are undocumented, I strongly
10201 suggest you take a look at their respective header files in the GTK
10202 distribution. GTK's function names are very descriptive. Once you
10203 have an understanding of how things work, it's not difficult to figure
10204 out how to use a widget simply by looking at its function
10205 declarations. This, along with a few examples from others' code, and
10206 it should be no problem.
10208 When you do come to understand all the functions of a new undocumented
10209 widget, please consider writing a tutorial on it so others may benefit
10212 <!-- ----------------------------------------------------------------- -->
10215 <!-- ----------------------------------------------------------------- -->
10218 <!-- ----------------------------------------------------------------- -->
10221 <!-- ----------------------------------------------------------------- -->
10222 <sect1> Drawing Area
10224 <!-- ----------------------------------------------------------------- -->
10225 <sect1> Font Selection Dialog
10227 <!-- ----------------------------------------------------------------- -->
10228 <sect1> Gamma Curve
10230 <!-- ----------------------------------------------------------------- -->
10233 <!-- ----------------------------------------------------------------- -->
10236 <!-- ----------------------------------------------------------------- -->
10237 <sect1> Plugs and Sockets
10239 <!-- ----------------------------------------------------------------- -->
10245 (This may need to be rewritten to follow the style of the rest of the tutorial)
10249 Previews serve a number of purposes in GIMP/GTK. The most important one is
10250 this. High quality images may take up to tens of megabytes of memory - easily!
10251 Any operation on an image that big is bound to take a long time. If it takes
10252 you 5-10 trial-and-errors (i.e., 10-20 steps, since you have to revert after
10253 you make an error) to choose the desired modification, it make take you
10254 literally hours to make the right one - if you don't run out of memory
10255 first. People who have spent hours in color darkrooms know the feeling.
10256 Previews to the rescue!
10258 But the annoyance of the delay is not the only issue. Oftentimes it is
10259 helpful to compare the Before and After versions side-by-side or at least
10260 back-to-back. If you're working with big images and 10 second delays,
10261 obtaining the Before and After impressions is, to say the least, difficult.
10262 For 30M images (4"x6", 600dpi, 24 bit) the side-by-side comparison is right
10263 out for most people, while back-to-back is more like back-to-1001, 1002,
10264 ..., 1010-back! Previews to the rescue!
10266 But there's more. Previews allow for side-by-side pre-previews. In other
10267 words, you write a plug-in (e.g., the filterpack simulation) which would have
10268 a number of here's-what-it-would-look-like-if-you-were-to-do-this previews.
10269 An approach like this acts as a sort of a preview palette and is very
10270 effective for subtle changes. Let's go previews!
10272 There's more. For certain plug-ins real-time image-specific human
10273 intervention maybe necessary. In the SuperNova plug-in, for example, the
10274 user is asked to enter the coordinates of the center of the future
10275 supernova. The easiest way to do this, really, is to present the user with a
10276 preview and ask him to interactively select the spot. Let's go previews!
10278 Finally, a couple of misc uses. One can use previews even when not working
10279 with big images. For example, they are useful when rendering complicated
10280 patterns. (Just check out the venerable Diffraction plug-in + many other
10281 ones!) As another example, take a look at the colormap rotation plug-in
10282 (work in progress). You can also use previews for little logos inside you
10283 plug-ins and even for an image of yourself, The Author. Let's go previews!
10285 When Not to Use Previews
10287 Don't use previews for graphs, drawing, etc. GDK is much faster for that. Use
10288 previews only for rendered images!
10292 You can stick a preview into just about anything. In a vbox, an hbox, a
10293 table, a button, etc. But they look their best in tight frames around them.
10294 Previews by themselves do not have borders and look flat without them. (Of
10295 course, if the flat look is what you want...) Tight frames provide the
10300 Previews in many ways are like any other widgets in GTK (whatever that
10301 means) except they possess an additional feature: they need to be filled with
10302 some sort of an image! First, we will deal exclusively with the GTK aspect
10303 of previews and then we'll discuss how to fill them.
10305 GtkWidget *preview!
10309 /* Create a preview widget,
10310 set its size, an show it */
10311 GtkWidget *preview;
10312 preview=gtk_preview_new(GTK_PREVIEW_COLOR)
10314 GTK_PREVIEW_GRAYSCALE);*/
10315 gtk_preview_size (GTK_PREVIEW (preview), WIDTH, HEIGHT);
10316 gtk_widget_show(preview);
10317 my_preview_rendering_function(preview);
10319 Oh yeah, like I said, previews look good inside frames, so how about:
10321 GtkWidget *create_a_preview(int Width,
10325 GtkWidget *preview;
10328 frame = gtk_frame_new(NULL);
10329 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
10330 gtk_container_set_border_width (GTK_CONTAINER(frame),0);
10331 gtk_widget_show(frame);
10333 preview=gtk_preview_new (Colorfulness?GTK_PREVIEW_COLOR
10334 :GTK_PREVIEW_GRAYSCALE);
10335 gtk_preview_size (GTK_PREVIEW (preview), Width, Height);
10336 gtk_container_add(GTK_CONTAINER(frame),preview);
10337 gtk_widget_show(preview);
10339 my_preview_rendering_function(preview);
10343 That's my basic preview. This routine returns the "parent" frame so you can
10344 place it somewhere else in your interface. Of course, you can pass the
10345 parent frame to this routine as a parameter. In many situations, however,
10346 the contents of the preview are changed continually by your application. In
10347 this case you may want to pass a pointer to the preview to a
10348 "create_a_preview()" and thus have control of it later.
10350 One more important note that may one day save you a lot of time. Sometimes
10351 it is desirable to label you preview. For example, you may label the preview
10352 containing the original image as "Original" and the one containing the
10353 modified image as "Less Original". It might occur to you to pack the
10354 preview along with the appropriate label into a vbox. The unexpected caveat
10355 is that if the label is wider than the preview (which may happen for a
10356 variety of reasons unforseeable to you, from the dynamic decision on the
10357 size of the preview to the size of the font) the frame expands and no longer
10358 fits tightly over the preview. The same problem can probably arise in other
10359 situations as well.
10363 The solution is to place the preview and the label into a 2x1 table and by
10364 attaching them with the following parameters (this is one possible variations
10365 of course. The key is no GTK_FILL in the second attachment):
10367 gtk_table_attach(GTK_TABLE(table),label,0,1,0,1,
10369 GTK_EXPAND|GTK_FILL,
10371 gtk_table_attach(GTK_TABLE(table),frame,0,1,1,2,
10377 And here's the result:
10383 Making a preview clickable is achieved most easily by placing it in a
10384 button. It also adds a nice border around the preview and you may not even
10385 need to place it in a frame. See the Filter Pack Simulation plug-in for an
10388 This is pretty much it as far as GTK is concerned.
10390 Filling In a Preview
10392 In order to familiarize ourselves with the basics of filling in previews,
10393 let's create the following pattern (contrived by trial and error):
10398 my_preview_rendering_function(GtkWidget *preview)
10401 #define HALF (SIZE/2)
10403 guchar *row=(guchar *) malloc(3*SIZE); /* 3 bits per dot */
10404 gint i, j; /* Coordinates */
10405 double r, alpha, x, y;
10407 if (preview==NULL) return; /* I usually add this when I want */
10408 /* to avoid silly crashes. You */
10409 /* should probably make sure that */
10410 /* everything has been nicely */
10412 for (j=0; j < ABS(cos(2*alpha)) ) { /* Are we inside the shape? */
10413 /* glib.h contains ABS(x). */
10414 row[i*3+0] = sqrt(1-r)*255; /* Define Red */
10415 row[i*3+1] = 128; /* Define Green */
10416 row[i*3+2] = 224; /* Define Blue */
10417 } /* "+0" is for alignment! */
10419 row[i*3+0] = r*255;
10420 row[i*3+1] = ABS(sin((float)i/SIZE*2*PI))*255;
10421 row[i*3+2] = ABS(sin((float)j/SIZE*2*PI))*255;
10424 gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,j,SIZE);
10425 /* Insert "row" into "preview" starting at the point with */
10426 /* coordinates (0,j) first column, j_th row extending SIZE */
10427 /* pixels to the right */
10430 free(row); /* save some space */
10431 gtk_widget_draw(preview,NULL); /* what does this do? */
10432 gdk_flush(); /* or this? */
10435 Non-GIMP users can have probably seen enough to do a lot of things already.
10436 For the GIMP users I have a few pointers to add.
10440 It is probably wise to keep a reduced version of the image around with just
10441 enough pixels to fill the preview. This is done by selecting every n'th
10442 pixel where n is the ratio of the size of the image to the size of the
10443 preview. All further operations (including filling in the previews) are then
10444 performed on the reduced number of pixels only. The following is my
10445 implementation of reducing the image. (Keep in mind that I've had only basic
10448 (UNTESTED CODE ALERT!!!)
10460 SELECTION_IN_CONTEXT,
10464 ReducedImage *Reduce_The_Image(GDrawable *drawable,
10469 /* This function reduced the image down to the the selected preview size */
10470 /* The preview size is determine by LongerSize, i.e., the greater of the */
10471 /* two dimensions. Works for RGB images only! */
10472 gint RH, RW; /* Reduced height and reduced width */
10473 gint width, height; /* Width and Height of the area being reduced */
10474 gint bytes=drawable->bpp;
10475 ReducedImage *temp=(ReducedImage *)malloc(sizeof(ReducedImage));
10477 guchar *tempRGB, *src_row, *tempmask, *src_mask_row,R,G,B;
10478 gint i, j, whichcol, whichrow, x1, x2, y1, y2;
10479 GPixelRgn srcPR, srcMask;
10480 gint NoSelectionMade=TRUE; /* Assume that we're dealing with the entire */
10483 gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
10486 /* If there's a SELECTION, we got its bounds!)
10488 if (width != drawable->width && height != drawable->height)
10489 NoSelectionMade=FALSE;
10490 /* Become aware of whether the user has made an active selection */
10491 /* This will become important later, when creating a reduced mask. */
10493 /* If we want to preview the entire image, overrule the above! */
10494 /* Of course, if no selection has been made, this does nothing! */
10495 if (Selection==ENTIRE_IMAGE) {
10497 x2=drawable->width;
10499 y2=drawable->height;
10502 /* If we want to preview a selection with some surrounding area we */
10503 /* have to expand it a little bit. Consider it a bit of a riddle. */
10504 if (Selection==SELECTION_IN_CONTEXT) {
10505 x1=MAX(0, x1-width/2.0);
10506 x2=MIN(drawable->width, x2+width/2.0);
10507 y1=MAX(0, y1-height/2.0);
10508 y2=MIN(drawable->height, y2+height/2.0);
10511 /* How we can determine the width and the height of the area being */
10516 /* The lines below determine which dimension is to be the longer */
10517 /* side. The idea borrowed from the supernova plug-in. I suspect I */
10518 /* could've thought of it myself, but the truth must be told. */
10519 /* Plagiarism stinks! */
10520 if (width>height) {
10522 RH=(float) height * (float) LongerSize/ (float) width;
10526 RW=(float)width * (float) LongerSize/ (float) height;
10529 /* The entire image is stretched into a string! */
10530 tempRGB = (guchar *) malloc(RW*RH*bytes);
10531 tempmask = (guchar *) malloc(RW*RH);
10533 gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height,
10535 gimp_pixel_rgn_init (&srcMask, mask, x1, y1, width, height,
10538 /* Grab enough to save a row of image and a row of mask. */
10539 src_row = (guchar *) malloc (width*bytes);
10540 src_mask_row = (guchar *) malloc (width);
10542 for (i=0; i < RH; i++) {
10543 whichrow=(float)i*(float)height/(float)RH;
10544 gimp_pixel_rgn_get_row (&srcPR, src_row, x1, y1+whichrow, width);
10545 gimp_pixel_rgn_get_row (&srcMask, src_mask_row, x1, y1+whichrow, width);
10547 for (j=0; j < RW; j++) {
10548 whichcol=(float)j*(float)width/(float)RW;
10550 /* No selection made = each point is completely selected! */
10551 if (NoSelectionMade)
10552 tempmask[i*RW+j]=255;
10554 tempmask[i*RW+j]=src_mask_row[whichcol];
10556 /* Add the row to the one long string which now contains the image! */
10557 tempRGB[i*RW*bytes+j*bytes+0]=src_row[whichcol*bytes+0];
10558 tempRGB[i*RW*bytes+j*bytes+1]=src_row[whichcol*bytes+1];
10559 tempRGB[i*RW*bytes+j*bytes+2]=src_row[whichcol*bytes+2];
10561 /* Hold on to the alpha as well */
10563 tempRGB[i*RW*bytes+j*bytes+3]=src_row[whichcol*bytes+3];
10570 temp->mask=tempmask;
10574 The following is a preview function which used the same ReducedImage type!
10575 Note that it uses fakes transparency (if one is present by means of
10576 fake_transparency which is defined as follows:
10578 gint fake_transparency(gint i, gint j)
10580 if ( ((i%20)- 10) * ((j%20)- 10)>0 )
10586 Now here's the preview function:
10589 my_preview_render_function(GtkWidget *preview,
10593 gint Inten, bytes=drawable->bpp;
10596 gint RW=reduced->width;
10597 gint RH=reduced->height;
10598 guchar *row=malloc(bytes*RW);;
10601 for (i=0; i < RH; i++) {
10602 for (j=0; j < RW; j++) {
10604 row[j*3+0] = reduced->rgb[i*RW*bytes + j*bytes + 0];
10605 row[j*3+1] = reduced->rgb[i*RW*bytes + j*bytes + 1];
10606 row[j*3+2] = reduced->rgb[i*RW*bytes + j*bytes + 2];
10609 for (k=0; k<3; k++) {
10610 float transp=reduced->rgb[i*RW*bytes+j*bytes+3]/255.0;
10611 row[3*j+k]=transp*a[3*j+k]+(1-transp)*fake_transparency(i,j);
10614 gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,i,RW);
10618 gtk_widget_draw(preview,NULL);
10622 Applicable Routines
10624 guint gtk_preview_get_type (void);
10626 void gtk_preview_uninit (void);
10628 GtkWidget* gtk_preview_new (GtkPreviewType type);
10629 /* Described above */
10630 void gtk_preview_size (GtkPreview *preview,
10633 /* Allows you to resize an existing preview. */
10634 /* Apparently there's a bug in GTK which makes */
10635 /* this process messy. A way to clean up a mess */
10636 /* is to manually resize the window containing */
10637 /* the preview after resizing the preview. */
10639 void gtk_preview_put (GtkPreview *preview,
10650 void gtk_preview_put_row (GtkPreview *preview,
10658 void gtk_preview_draw_row (GtkPreview *preview,
10663 /* Described in the text */
10665 void gtk_preview_set_expand (GtkPreview *preview,
10669 /* No clue for any of the below but */
10670 /* should be standard for most widgets */
10671 void gtk_preview_set_gamma (double gamma);
10672 void gtk_preview_set_color_cube (guint nred_shades,
10673 guint ngreen_shades,
10674 guint nblue_shades,
10675 guint ngray_shades);
10676 void gtk_preview_set_install_cmap (gint install_cmap);
10677 void gtk_preview_set_reserved (gint nreserved);
10678 GdkVisual* gtk_preview_get_visual (void);
10679 GdkColormap* gtk_preview_get_cmap (void);
10680 GtkPreviewInfo* gtk_preview_get_info (void);
10688 <!-- ***************************************************************** -->
10689 <sect>Setting Widget Attributes<label id="sec_setting_widget_attributes">
10690 <!-- ***************************************************************** -->
10692 This describes the functions used to operate on widgets. These can be
10693 used to set style, padding, size, etc.
10695 (Maybe I should make a whole section on accelerators.)
10698 void gtk_widget_install_accelerator( GtkWidget *widget,
10699 GtkAcceleratorTable *table,
10700 gchar *signal_name,
10702 guint8 modifiers );
10704 void gtk_widget_remove_accelerator ( GtkWidget *widget,
10705 GtkAcceleratorTable *table,
10706 gchar *signal_name);
10708 void gtk_widget_activate( GtkWidget *widget );
10710 void gtk_widget_set_name( GtkWidget *widget,
10713 gchar *gtk_widget_get_name( GtkWidget *widget );
10715 void gtk_widget_set_sensitive( GtkWidget *widget,
10718 void gtk_widget_set_style( GtkWidget *widget,
10721 GtkStyle *gtk_widget_get_style( GtkWidget *widget );
10723 GtkStyle *gtk_widget_get_default_style( void );
10725 void gtk_widget_set_uposition( GtkWidget *widget,
10729 void gtk_widget_set_usize( GtkWidget *widget,
10733 void gtk_widget_grab_focus( GtkWidget *widget );
10735 void gtk_widget_show( GtkWidget *widget );
10737 void gtk_widget_hide( GtkWidget *widget );
10740 <!-- ***************************************************************** -->
10741 <sect>Timeouts, IO and Idle Functions<label id="sec_timeouts">
10742 <!-- ***************************************************************** -->
10744 <!-- ----------------------------------------------------------------- -->
10747 You may be wondering how you make GTK do useful work when in gtk_main.
10748 Well, you have several options. Using the following function you can
10749 create a timeout function that will be called every "interval"
10753 gint gtk_timeout_add( guint32 interval,
10754 GtkFunction function,
10758 The first argument is the number of milliseconds between calls to your
10759 function. The second argument is the function you wish to have called,
10760 and the third, the data passed to this callback function. The return
10761 value is an integer "tag" which may be used to stop the timeout by
10765 void gtk_timeout_remove( gint tag );
10768 You may also stop the timeout function by returning zero or FALSE from
10769 your callback function. Obviously this means if you want your function
10770 to continue to be called, it should return a non-zero value,
10773 The declaration of your callback should look something like this:
10776 gint timeout_callback( gpointer data );
10779 <!-- ----------------------------------------------------------------- -->
10780 <sect1>Monitoring IO
10782 A nifty feature of GDK (the library that underlies GTK), is the
10783 ability to have it check for data on a file descriptor for you (as
10784 returned by open(2) or socket(2)). This is especially useful for
10785 networking applications. The function:
10788 gint gdk_input_add( gint source,
10789 GdkInputCondition condition,
10790 GdkInputFunction function,
10794 Where the first argument is the file descriptor you wish to have
10795 watched, and the second specifies what you want GDK to look for. This
10799 <item><tt/GDK_INPUT_READ/ - Call your function when there is data
10800 ready for reading on your file descriptor.
10802 <item>><tt/GDK_INPUT_WRITE/ - Call your function when the file
10803 descriptor is ready for writing.
10806 As I'm sure you've figured out already, the third argument is the
10807 function you wish to have called when the above conditions are
10808 satisfied, and the fourth is the data to pass to this function.
10810 The return value is a tag that may be used to stop GDK from monitoring
10811 this file descriptor using the following function.
10814 void gdk_input_remove( gint tag );
10817 The callback function should be declared as:
10820 void input_callback( gpointer data,
10822 GdkInputCondition condition );
10825 Where <tt/source/ and <tt/condition/ are as specified above.
10827 <!-- ----------------------------------------------------------------- -->
10828 <sect1>Idle Functions
10830 <!-- TODO: Need to check on idle priorities - TRG -->
10831 What if you have a function which you want to be called when nothing
10832 else is happening ?
10835 gint gtk_idle_add( GtkFunction function,
10839 This causes GTK to call the specified function whenever nothing else
10843 void gtk_idle_remove( gint tag );
10846 I won't explain the meaning of the arguments as they follow very much
10847 like the ones above. The function pointed to by the first argument to
10848 gtk_idle_add will be called whenever the opportunity arises. As with
10849 the others, returning FALSE will stop the idle function from being
10852 <!-- ***************************************************************** -->
10853 <sect>Advanced Event and Signal Handling<label id="sec_Adv_Events_and_Signals">
10854 <!-- ***************************************************************** -->
10856 <!-- ----------------------------------------------------------------- -->
10857 <sect1>Signal Functions
10859 <!-- ----------------------------------------------------------------- -->
10860 <sect2>Connecting and Disconnecting Signal Handlers
10864 guint gtk_signal_connect( GtkObject *object,
10866 GtkSignalFunc func,
10867 gpointer func_data );
10869 guint gtk_signal_connect_after( GtkObject *object,
10871 GtkSignalFunc func,
10872 gpointer func_data );
10874 guint gtk_signal_connect_object( GtkObject *object,
10876 GtkSignalFunc func,
10877 GtkObject *slot_object );
10879 guint gtk_signal_connect_object_after( GtkObject *object,
10881 GtkSignalFunc func,
10882 GtkObject *slot_object );
10884 guint gtk_signal_connect_full( GtkObject *object,
10886 GtkSignalFunc func,
10887 GtkCallbackMarshal marshal,
10889 GtkDestroyNotify destroy_func,
10890 gint object_signal,
10893 guint gtk_signal_connect_interp( GtkObject *object,
10895 GtkCallbackMarshal func,
10897 GtkDestroyNotify destroy_func,
10900 void gtk_signal_connect_object_while_alive( GtkObject *object,
10901 const gchar *signal,
10902 GtkSignalFunc func,
10903 GtkObject *alive_object );
10905 void gtk_signal_connect_while_alive( GtkObject *object,
10906 const gchar *signal,
10907 GtkSignalFunc func,
10908 gpointer func_data,
10909 GtkObject *alive_object );
10911 void gtk_signal_disconnect( GtkObject *object,
10912 guint handler_id );
10914 void gtk_signal_disconnect_by_func( GtkObject *object,
10915 GtkSignalFunc func,
10919 <!-- ----------------------------------------------------------------- -->
10920 <sect2>Blocking and Unblocking Signal Handlers
10923 void gtk_signal_handler_block( GtkObject *object,
10926 void gtk_signal_handler_block_by_func( GtkObject *object,
10927 GtkSignalFunc func,
10930 void gtk_signal_handler_block_by_data( GtkObject *object,
10933 void gtk_signal_handler_unblock( GtkObject *object,
10934 guint handler_id );
10936 void gtk_signal_handler_unblock_by_func( GtkObject *object,
10937 GtkSignalFunc func,
10940 void gtk_signal_handler_unblock_by_data( GtkObject *object,
10944 <!-- ----------------------------------------------------------------- -->
10945 <sect2>Emitting and Stopping Signals
10948 void gtk_signal_emit( GtkObject *object,
10952 void gtk_signal_emit_by_name( GtkObject *object,
10956 void gtk_signal_emitv( GtkObject *object,
10960 void gtk_signal_emitv_by_name( GtkObject *object,
10964 guint gtk_signal_n_emissions( GtkObject *object,
10967 guint gtk_signal_n_emissions_by_name( GtkObject *object,
10968 const gchar *name );
10970 void gtk_signal_emit_stop( GtkObject *object,
10973 void gtk_signal_emit_stop_by_name( GtkObject *object,
10974 const gchar *name );
10977 <!-- ----------------------------------------------------------------- -->
10978 <sect1>Signal Emission and Propagation
10980 Signal emission is the process whereby GTK runs all handlers for a
10981 specific object and signal.
10983 First, note that the return value from a signal emission is the return
10984 value of the <em>last</em> handler executed. Since event signals are
10985 all of type <tt/GTK_RUN_LAST/, this will be the default (GTK supplied)
10986 handler, unless you connect with gtk_signal_connect_after().
10988 The way an event (say "button_press_event") is handled, is:
10990 <item>Start with the widget where the event occured.
10992 <item>Emit the generic "event" signal. If that signal handler returns
10993 a value of TRUE, stop all processing.
10995 <item>Otherwise, emit a specific, "button_press_event" signal. If that
10996 returns TRUE, stop all processing.
10998 <item>Otherwise, go to the widget's parent, and repeat the above two
11001 <item>Continue until some signal handler returns TRUE, or until the
11002 top-level widget is reached.
11005 Some consequences of the above are:
11007 <item>Your handler's return value will have no effect if there is a
11008 default handler, unless you connect with gtk_signal_connect_after().
11010 <item>To prevent the default handler from being run, you need to
11011 connect with gtk_signal_connect() and use
11012 gtk_signal_emit_stop_by_name() - the return value only affects whether
11013 the signal is propagated, not the current emission.
11016 <!-- ***************************************************************** -->
11017 <sect>Managing Selections
11018 <!-- ***************************************************************** -->
11020 <!-- ----------------------------------------------------------------- -->
11023 One type of interprocess communication supported by X and GTK is
11024 <em>selections</em>. A selection identifies a chunk of data, for
11025 instance, a portion of text, selected by the user in some fashion, for
11026 instance, by dragging with the mouse. Only one application on a
11027 display (the <em>owner</em>) can own a particular selection at one
11028 time, so when a selection is claimed by one application, the previous
11029 owner must indicate to the user that selection has been
11030 relinquished. Other applications can request the contents of a
11031 selection in different forms, called <em>targets</em>. There can be
11032 any number of selections, but most X applications only handle one, the
11033 <em>primary selection</em>.
11035 In most cases, it isn't necessary for a GTK application to deal with
11036 selections itself. The standard widgets, such as the Entry widget,
11037 already have the capability to claim the selection when appropriate
11038 (e.g., when the user drags over text), and to retrieve the contents of
11039 the selection owned by another widget or another application (e.g.,
11040 when the user clicks the second mouse button). However, there may be
11041 cases in which you want to give other widgets the ability to supply
11042 the selection, or you wish to retrieve targets not supported by
11045 A fundamental concept needed to understand selection handling is that
11046 of the <em>atom</em>. An atom is an integer that uniquely identifies a
11047 string (on a certain display). Certain atoms are predefined by the X
11048 server, and in some cases there are constants in <tt>gtk.h</tt>
11049 corresponding to these atoms. For instance the constant
11050 <tt>GDK_PRIMARY_SELECTION</tt> corresponds to the string "PRIMARY".
11051 In other cases, you should use the functions
11052 <tt>gdk_atom_intern()</tt>, to get the atom corresponding to a string,
11053 and <tt>gdk_atom_name()</tt>, to get the name of an atom. Both
11054 selections and targets are identified by atoms.
11056 <!-- ----------------------------------------------------------------- -->
11057 <sect1> Retrieving the selection
11059 Retrieving the selection is an asynchronous process. To start the
11063 gint gtk_selection_convert( GtkWidget *widget,
11069 This <em>converts</em> the selection into the form specified by
11070 <tt/target/. If at all possible, the time field should be the time
11071 from the event that triggered the selection. This helps make sure that
11072 events occur in the order that the user requested them. However, if it
11073 is not available (for instance, if the conversion was triggered by a
11074 "clicked" signal), then you can use the constant
11075 <tt>GDK_CURRENT_TIME</tt>.
11077 When the selection owner responds to the request, a
11078 "selection_received" signal is sent to your application. The handler
11079 for this signal receives a pointer to a <tt>GtkSelectionData</tt>
11080 structure, which is defined as:
11083 struct _GtkSelectionData
11094 <tt>selection</tt> and <tt>target</tt> are the values you gave in your
11095 <tt>gtk_selection_convert()</tt> call. <tt>type</tt> is an atom that
11096 identifies the type of data returned by the selection owner. Some
11097 possible values are "STRING", a string of latin-1 characters, "ATOM",
11098 a series of atoms, "INTEGER", an integer, etc. Most targets can only
11099 return one type. <tt/format/ gives the length of the units (for
11100 instance characters) in bits. Usually, you don't care about this when
11101 receiving data. <tt>data</tt> is a pointer to the returned data, and
11102 <tt>length</tt> gives the length of the returned data, in bytes. If
11103 <tt>length</tt> is negative, then an error occurred and the selection
11104 could not be retrieved. This might happen if no application owned the
11105 selection, or if you requested a target that the application didn't
11106 support. The buffer is actually guaranteed to be one byte longer than
11107 <tt>length</tt>; the extra byte will always be zero, so it isn't
11108 necessary to make a copy of strings just to null terminate them.
11110 In the following example, we retrieve the special target "TARGETS",
11111 which is a list of all targets into which the selection can be
11115 /* example-start selection gettargets.c */
11117 #include <gtk/gtk.h>
11119 void selection_received (GtkWidget *widget,
11120 GtkSelectionData *selection_data,
11123 /* Signal handler invoked when user clicks on the "Get Targets" button */
11125 get_targets (GtkWidget *widget, gpointer data)
11127 static GdkAtom targets_atom = GDK_NONE;
11129 /* Get the atom corresponding to the string "TARGETS" */
11130 if (targets_atom == GDK_NONE)
11131 targets_atom = gdk_atom_intern ("TARGETS", FALSE);
11133 /* And request the "TARGETS" target for the primary selection */
11134 gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
11138 /* Signal handler called when the selections owner returns the data */
11140 selection_received (GtkWidget *widget, GtkSelectionData *selection_data,
11147 /* **** IMPORTANT **** Check to see if retrieval succeeded */
11148 if (selection_data->length < 0)
11150 g_print ("Selection retrieval failed\n");
11153 /* Make sure we got the data in the expected form */
11154 if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
11156 g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
11160 /* Print out the atoms we received */
11161 atoms = (GdkAtom *)selection_data->data;
11164 for (i=0; i<selection_data->length/sizeof(GdkAtom); i++)
11167 name = gdk_atom_name (atoms[i]);
11169 g_print ("%s\n",name);
11171 g_print ("(bad atom)\n");
11178 main (int argc, char *argv[])
11183 gtk_init (&argc, &argv);
11185 /* Create the toplevel window */
11187 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11188 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
11189 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
11191 gtk_signal_connect (GTK_OBJECT (window), "destroy",
11192 GTK_SIGNAL_FUNC (gtk_exit), NULL);
11194 /* Create a button the user can click to get targets */
11196 button = gtk_button_new_with_label ("Get Targets");
11197 gtk_container_add (GTK_CONTAINER (window), button);
11199 gtk_signal_connect (GTK_OBJECT(button), "clicked",
11200 GTK_SIGNAL_FUNC (get_targets), NULL);
11201 gtk_signal_connect (GTK_OBJECT(button), "selection_received",
11202 GTK_SIGNAL_FUNC (selection_received), NULL);
11204 gtk_widget_show (button);
11205 gtk_widget_show (window);
11214 <!-- ----------------------------------------------------------------- -->
11215 <sect1> Supplying the selection
11217 Supplying the selection is a bit more complicated. You must register
11218 handlers that will be called when your selection is requested. For
11219 each selection/target pair you will handle, you make a call to:
11222 void gtk_selection_add_handler( GtkWidget *widget,
11225 GtkSelectionFunction function,
11226 GtkRemoveFunction remove_func,
11230 <tt/widget/, <tt/selection/, and <tt/target/ identify the requests
11231 this handler will manage. <tt/remove_func/, if not
11232 NULL, will be called when the signal handler is removed. This is
11233 useful, for instance, for interpreted languages which need to
11234 keep track of a reference count for <tt/data/.
11236 The callback function has the signature:
11239 typedef void (*GtkSelectionFunction)( GtkWidget *widget,
11240 GtkSelectionData *selection_data,
11245 The GtkSelectionData is the same as above, but this time, we're
11246 responsible for filling in the fields <tt/type/, <tt/format/,
11247 <tt/data/, and <tt/length/. (The <tt/format/ field is actually
11248 important here - the X server uses it to figure out whether the data
11249 needs to be byte-swapped or not. Usually it will be 8 - <em/i.e./ a
11250 character - or 32 - <em/i.e./ a. integer.) This is done by calling the
11254 void gtk_selection_data_set( GtkSelectionData *selection_data,
11261 This function takes care of properly making a copy of the data so that
11262 you don't have to worry about keeping it around. (You should not fill
11263 in the fields of the GtkSelectionData structure by hand.)
11265 When prompted by the user, you claim ownership of the selection by
11269 gint gtk_selection_owner_set( GtkWidget *widget,
11274 If another application claims ownership of the selection, you will
11275 receive a "selection_clear_event".
11277 As an example of supplying the selection, the following program adds
11278 selection functionality to a toggle button. When the toggle button is
11279 depressed, the program claims the primary selection. The only target
11280 supported (aside from certain targets like "TARGETS" supplied by GTK
11281 itself), is the "STRING" target. When this target is requested, a
11282 string representation of the time is returned.
11285 /* example-start selection setselection.c */
11287 #include <gtk/gtk.h>
11290 /* Callback when the user toggles the selection */
11292 selection_toggled (GtkWidget *widget, gint *have_selection)
11294 if (GTK_TOGGLE_BUTTON(widget)->active)
11296 *have_selection = gtk_selection_owner_set (widget,
11297 GDK_SELECTION_PRIMARY,
11299 /* if claiming the selection failed, we return the button to
11301 if (!*have_selection)
11302 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), FALSE);
11306 if (*have_selection)
11308 /* Before clearing the selection by setting the owner to NULL,
11309 we check if we are the actual owner */
11310 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
11311 gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
11313 *have_selection = FALSE;
11318 /* Called when another application claims the selection */
11320 selection_clear (GtkWidget *widget, GdkEventSelection *event,
11321 gint *have_selection)
11323 *have_selection = FALSE;
11324 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), FALSE);
11329 /* Supplies the current time as the selection. */
11331 selection_handle (GtkWidget *widget,
11332 GtkSelectionData *selection_data,
11336 time_t current_time;
11338 current_time = time (NULL);
11339 timestr = asctime (localtime(&current_time));
11340 /* When we return a single string, it should not be null terminated.
11341 That will be done for us */
11343 gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
11344 8, timestr, strlen(timestr));
11348 main (int argc, char *argv[])
11352 GtkWidget *selection_button;
11354 static int have_selection = FALSE;
11356 gtk_init (&argc, &argv);
11358 /* Create the toplevel window */
11360 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11361 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
11362 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
11364 gtk_signal_connect (GTK_OBJECT (window), "destroy",
11365 GTK_SIGNAL_FUNC (gtk_exit), NULL);
11367 /* Create a toggle button to act as the selection */
11369 selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
11370 gtk_container_add (GTK_CONTAINER (window), selection_button);
11371 gtk_widget_show (selection_button);
11373 gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
11374 GTK_SIGNAL_FUNC (selection_toggled), &have_selection);
11375 gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
11376 GTK_SIGNAL_FUNC (selection_clear), &have_selection);
11378 gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
11379 GDK_SELECTION_TYPE_STRING,
11380 selection_handle, NULL);
11382 gtk_widget_show (selection_button);
11383 gtk_widget_show (window);
11393 <!-- ***************************************************************** -->
11394 <sect>GLib<label id="sec_glib">
11395 <!-- ***************************************************************** -->
11397 GLib is a lower-level library that provides many useful definitions
11398 and functions available for use when creating GDK and GTK
11399 applications. These include definitions for basic types and their
11400 limits, standard macros, type conversions, byte order, memory
11401 allocation, warnings and assertions, message logging, timers, string
11402 utilities, hook functions, a lexical scanner, dynamic loading of
11403 modules, and automatic string completion. A number of data structures
11404 (and their related operations) are also defined, including memory
11405 chunks, doubly-linked lists, singly-linked lists, hash tables, strings
11406 (which can grow dynamically), string chunks (groups of strings),
11407 arrays (which can grow in size as elements are added), balanced binary
11408 trees, N-ary trees, quarks (a two-way association of a string and a
11409 unique integer identifier), keyed data lists (lists of data elements
11410 accessible by a string or integer id), relations and tuples (tables of
11411 data which can be indexed on any number of fields), and caches.
11413 A summary of some of GLib's capabilities follows; not every function,
11414 data structure, or operation is covered here. For more complete
11415 information about the GLib routines, see the GLib documentation. One
11416 source of GLib documentation is <htmlurl url="http://www.gtk.org/"
11417 name="http://www.gtk.org/">.
11419 If you are using a language other than C, you should consult your
11420 language's binding documentation. In some cases your language may
11421 have equivalent functionality built-in, while in other cases it may
11424 <!-- ----------------------------------------------------------------- -->
11427 Definitions for the extremes of many of the standard types are:
11442 Also, the following typedefs. The ones left unspecified are dynamically set
11443 depending on the architecture. Remember to avoid counting on the size of a
11444 pointer if you want to be portable! E.g., a pointer on an Alpha is 8
11445 bytes, but 4 on Intel 80x86 family CPUs.
11454 unsigned char guchar;
11455 unsigned short gushort;
11456 unsigned long gulong;
11457 unsigned int guint;
11461 long double gldouble;
11473 <!-- ----------------------------------------------------------------- -->
11474 <sect1>Doubly Linked Lists
11476 The following functions are used to create, manage, and destroy
11477 standard doubly linked lists. Each element in the list contains a
11478 piece of data, together with pointers which link to the previous and
11479 next elements in the list. This enables easy movement in either
11480 direction through the list. The data item is of type "gpointer",
11481 which means the data can be a pointer to your real data or (through
11482 casting) a numeric value (but do not assume that int and gpointer have
11483 the same size!). These routines internally allocate list elements in
11484 blocks, which is more efficient than allocating elements individually.
11486 There is no function to specifically create a list. Instead, simply
11487 create a variable of type GList* and set its value to NULL; NULL is
11488 considered to be the empty list.
11490 To add elements to a list, use the g_list_append(), g_list_prepend(),
11491 g_list_insert(), or g_list_insert_sorted() routines. In all cases
11492 they accept a pointer to the beginning of the list, and return the
11493 (possibly changed) pointer to the beginning of the list. Thus, for
11494 all of the operations that add or remove elements, be sure to save the
11498 GList *g_list_append( GList *list,
11502 This adds a new element (with value <tt/data/) onto the end of the
11506 GList *g_list_prepend( GList *list,
11510 This adds a new element (with value <tt/data/) to the beginning of the
11514 GList *g_list_insert( GList *list,
11520 This inserts a new element (with value data) into the list at the
11521 given position. If position is 0, this is just like g_list_prepend();
11522 if position is less than 0, this is just like g_list_append().
11525 GList *g_list_remove( GList *list,
11529 This removes the element in the list with the value <tt/data/;
11530 if the element isn't there, the list is unchanged.
11533 void g_list_free( GList *list );
11536 This frees all of the memory used by a GList. If the list elements
11537 refer to dynamically-allocated memory, then they should be freed
11540 There are many other GLib functions that support doubly linked lists;
11541 see the glib documentation for more information. Here are a few of
11542 the more useful functions' signatures:
11545 GList *g_list_remove_link( GList *list,
11548 GList *g_list_reverse( GList *list );
11550 GList *g_list_nth( GList *list,
11553 GList *g_list_find( GList *list,
11556 GList *g_list_last( GList *list );
11558 GList *g_list_first( GList *list );
11560 gint g_list_length( GList *list );
11562 void g_list_foreach( GList *list,
11564 gpointer user_data );
11567 <!-- ----------------------------------------------------------------- -->
11568 <sect1>Singly Linked Lists
11570 Many of the above functions for singly linked lists are identical to the
11571 above. Here is a list of some of their operations:
11574 GSList *g_slist_append( GSList *list,
11577 GSList *g_slist_prepend( GSList *list,
11580 GSList *g_slist_insert( GSList *list,
11584 GSList *g_slist_remove( GSList *list,
11587 GSList *g_slist_remove_link( GSList *list,
11590 GSList *g_slist_reverse( GSList *list );
11592 GSList *g_slist_nth( GSList *list,
11595 GSList *g_slist_find( GSList *list,
11598 GSList *g_slist_last( GSList *list );
11600 gint g_slist_length( GSList *list );
11602 void g_slist_foreach( GSList *list,
11604 gpointer user_data );
11608 <!-- ----------------------------------------------------------------- -->
11609 <sect1>Memory Management
11612 gpointer g_malloc( gulong size );
11615 This is a replacement for malloc(). You do not need to check the return
11616 value as it is done for you in this function. If the memory allocation
11617 fails for whatever reasons, your applications will be terminated.
11620 gpointer g_malloc0( gulong size );
11623 Same as above, but zeroes the memory before returning a pointer to it.
11626 gpointer g_realloc( gpointer mem,
11630 Relocates "size" bytes of memory starting at "mem". Obviously, the
11631 memory should have been previously allocated.
11634 void g_free( gpointer mem );
11637 Frees memory. Easy one. If <tt/mem/ is NULL it simply returns.
11640 void g_mem_profile( void );
11643 Dumps a profile of used memory, but requires that you add <tt>#define
11644 MEM_PROFILE</tt> to the top of glib/gmem.c and re-make and make install.
11647 void g_mem_check( gpointer mem );
11650 Checks that a memory location is valid. Requires you add <tt>#define
11651 MEM_CHECK</tt> to the top of gmem.c and re-make and make install.
11653 <!-- ----------------------------------------------------------------- -->
11656 Timer functions can be used to time operations (e.g., to see how much
11657 time has elapsed). First, you create a new timer with g_timer_new().
11658 You can then use g_timer_start() to start timing an operation,
11659 g_timer_stop() to stop timing an operation, and g_timer_elapsed() to
11660 determine the elapsed time.
11663 GTimer *g_timer_new( void );
11665 void g_timer_destroy( GTimer *timer );
11667 void g_timer_start( GTimer *timer );
11669 void g_timer_stop( GTimer *timer );
11671 void g_timer_reset( GTimer *timer );
11673 gdouble g_timer_elapsed( GTimer *timer,
11674 gulong *microseconds );
11677 <!-- ----------------------------------------------------------------- -->
11678 <sect1>String Handling
11680 GLib defines a new type called a GString, which is similar to a
11681 standard C string but one that grows automatically. Its string data
11682 is null-terminated. What this gives you is protection from buffer
11683 overflow programming errors within your program. This is a very
11684 important feature, and hence I recommend that you make use of
11685 GStrings. GString itself has a simple public definition:
11690 gchar *str; /* Points to the string's current \0-terminated value. */
11691 gint len; /* Current length */
11695 As you might expect, there are a number of operations you can do with
11699 GString *g_string_new( gchar *init );
11702 This constructs a GString, copying the string value of <tt/init/
11703 into the GString and returning a pointer to it. NULL may be given as
11704 the argument for an initially empty GString.
11708 void g_string_free( GString *string,
11709 gint free_segment );
11712 This frees the memory for the given GString. If <tt/free_segment/ is
11713 TRUE, then this also frees its character data.
11717 GString *g_string_assign( GString *lval,
11718 const gchar *rval );
11721 This copies the characters from rval into lval, destroying the
11722 previous contents of lval. Note that lval will be lengthened as
11723 necessary to hold the string's contents, unlike the standard strcpy()
11726 The rest of these functions should be relatively obvious (the _c
11727 versions accept a character instead of a string):
11730 GString *g_string_truncate( GString *string,
11733 GString *g_string_append( GString *string,
11736 GString *g_string_append_c( GString *string,
11739 GString *g_string_prepend( GString *string,
11742 GString *g_string_prepend_c( GString *string,
11745 void g_string_sprintf( GString *string,
11749 void g_string_sprintfa ( GString *string,
11754 <!-- ----------------------------------------------------------------- -->
11755 <sect1>Utility and Error Functions
11758 gchar *g_strdup( const gchar *str );
11761 Replacement strdup function. Copies the original strings contents to
11762 newly allocated memory, and returns a pointer to it.
11765 gchar *g_strerror( gint errnum );
11768 I recommend using this for all error messages. It's much nicer, and more
11769 portable than perror() or others. The output is usually of the form:
11772 program name:function that failed:file or further description:strerror
11775 Here's an example of one such call used in our hello_world program:
11778 g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
11782 void g_error( gchar *format, ... );
11785 Prints an error message. The format is just like printf, but it
11786 prepends "** ERROR **: " to your message, and exits the program.
11787 Use only for fatal errors.
11790 void g_warning( gchar *format, ... );
11793 Same as above, but prepends "** WARNING **: ", and does not exit the
11797 void g_message( gchar *format, ... );
11800 Prints "message: " prepended to the string you pass in.
11803 void g_print( gchar *format, ... );
11806 Replacement for printf().
11808 And our last function:
11811 gchar *g_strsignal( gint signum );
11814 Prints out the name of the Unix system signal given the signal number.
11815 Useful in generic signal handling functions.
11817 All of the above are more or less just stolen from glib.h. If anyone cares
11818 to document any function, just send me an email!
11820 <!-- ***************************************************************** -->
11821 <sect>GTK's rc Files <label id="sec_gtkrc_files">
11822 <!-- ***************************************************************** -->
11824 GTK has its own way of dealing with application defaults, by using rc
11825 files. These can be used to set the colors of just about any widget, and
11826 can also be used to tile pixmaps onto the background of some widgets.
11828 <!-- ----------------------------------------------------------------- -->
11829 <sect1>Functions For rc Files
11831 When your application starts, you should include a call to:
11834 void gtk_rc_parse( char *filename );
11837 Passing in the filename of your rc file. This will cause GTK to parse
11838 this file, and use the style settings for the widget types defined
11841 If you wish to have a special set of widgets that can take on a
11842 different style from others, or any other logical division of widgets,
11846 void gtk_widget_set_name( GtkWidget *widget,
11850 Passing your newly created widget as the first argument, and the name
11851 you wish to give it as the second. This will allow you to change the
11852 attributes of this widget by name through the rc file.
11854 If we use a call something like this:
11857 button = gtk_button_new_with_label ("Special Button");
11858 gtk_widget_set_name (button, "special button");
11861 Then this button is given the name "special button" and may be addressed by
11862 name in the rc file as "special button.GtkButton". [<--- Verify ME!]
11864 The example rc file below, sets the properties of the main window, and lets
11865 all children of that main window inherit the style described by the "main
11866 button" style. The code used in the application is:
11869 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11870 gtk_widget_set_name (window, "main window");
11873 And then the style is defined in the rc file using:
11876 widget "main window.*GtkButton*" style "main_button"
11879 Which sets all the Button widgets in the "main window" to the
11880 "main_buttons" style as defined in the rc file.
11882 As you can see, this is a fairly powerful and flexible system. Use your
11883 imagination as to how best to take advantage of this.
11885 <!-- ----------------------------------------------------------------- -->
11886 <sect1>GTK's rc File Format
11888 The format of the GTK file is illustrated in the example below. This is
11889 the testgtkrc file from the GTK distribution, but I've added a
11890 few comments and things. You may wish to include this explanation in
11891 your application to allow the user to fine tune his application.
11893 There are several directives to change the attributes of a widget.
11896 <item>fg - Sets the foreground color of a widget.
11897 <item>bg - Sets the background color of a widget.
11898 <item>bg_pixmap - Sets the background of a widget to a tiled pixmap.
11899 <item>font - Sets the font to be used with the given widget.
11902 In addition to this, there are several states a widget can be in, and you
11903 can set different colors, pixmaps and fonts for each state. These states are:
11906 <item>NORMAL - The normal state of a widget, without the mouse over top of
11907 it, and not being pressed, etc.
11908 <item>PRELIGHT - When the mouse is over top of the widget, colors defined
11909 using this state will be in effect.
11910 <item>ACTIVE - When the widget is pressed or clicked it will be active, and
11911 the attributes assigned by this tag will be in effect.
11912 <item>INSENSITIVE - When a widget is set insensitive, and cannot be
11913 activated, it will take these attributes.
11914 <item>SELECTED - When an object is selected, it takes these attributes.
11917 When using the "fg" and "bg" keywords to set the colors of widgets, the
11921 fg[<STATE>] = { Red, Green, Blue }
11924 Where STATE is one of the above states (PRELIGHT, ACTIVE, etc), and the Red,
11925 Green and Blue are values in the range of 0 - 1.0, { 1.0, 1.0, 1.0 } being
11926 white. They must be in float form, or they will register as 0, so a straight
11927 "1" will not work, it must be "1.0". A straight "0" is fine because it
11928 doesn't matter if it's not recognized. Unrecognized values are set to 0.
11930 bg_pixmap is very similar to the above, except the colors are replaced by a
11933 pixmap_path is a list of paths separated by ":"'s. These paths will be
11934 searched for any pixmap you specify.
11936 The font directive is simply:
11938 font = "<font name>"
11941 The only hard part is figuring out the font string. Using xfontsel or
11942 a similar utility should help.
11944 The "widget_class" sets the style of a class of widgets. These classes are
11945 listed in the widget overview on the class hierarchy.
11947 The "widget" directive sets a specifically named set of widgets to a
11948 given style, overriding any style set for the given widget class.
11949 These widgets are registered inside the application using the
11950 gtk_widget_set_name() call. This allows you to specify the attributes of a
11951 widget on a per widget basis, rather than setting the attributes of an
11952 entire widget class. I urge you to document any of these special widgets so
11953 users may customize them.
11955 When the keyword <tt>parent</> is used as an attribute, the widget will take on
11956 the attributes of its parent in the application.
11958 When defining a style, you may assign the attributes of a previously defined
11959 style to this new one.
11962 style "main_button" = "button"
11964 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
11965 bg[PRELIGHT] = { 0.75, 0, 0 }
11969 This example takes the "button" style, and creates a new "main_button" style
11970 simply by changing the font and prelight background color of the "button"
11973 Of course, many of these attributes don't apply to all widgets. It's a
11974 simple matter of common sense really. Anything that could apply, should.
11976 <!-- ----------------------------------------------------------------- -->
11977 <sect1>Example rc file
11981 # pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
11983 pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
11985 # style <name> [= <name>]
11990 # widget <widget_set> style <style_name>
11991 # widget_class <widget_class_set> style <style_name>
11994 # Here is a list of all the possible states. Note that some do not apply to
11997 # NORMAL - The normal state of a widget, without the mouse over top of
11998 # it, and not being pressed, etc.
12000 # PRELIGHT - When the mouse is over top of the widget, colors defined
12001 # using this state will be in effect.
12003 # ACTIVE - When the widget is pressed or clicked it will be active, and
12004 # the attributes assigned by this tag will be in effect.
12006 # INSENSITIVE - When a widget is set insensitive, and cannot be
12007 # activated, it will take these attributes.
12009 # SELECTED - When an object is selected, it takes these attributes.
12011 # Given these states, we can set the attributes of the widgets in each of
12012 # these states using the following directives.
12014 # fg - Sets the foreground color of a widget.
12015 # fg - Sets the background color of a widget.
12016 # bg_pixmap - Sets the background of a widget to a tiled pixmap.
12017 # font - Sets the font to be used with the given widget.
12020 # This sets a style called "button". The name is not really important, as
12021 # it is assigned to the actual widgets at the bottom of the file.
12025 #This sets the padding around the window to the pixmap specified.
12026 #bg_pixmap[<STATE>] = "<pixmap filename>"
12027 bg_pixmap[NORMAL] = "warning.xpm"
12032 #Sets the foreground color (font color) to red when in the "NORMAL"
12035 fg[NORMAL] = { 1.0, 0, 0 }
12037 #Sets the background pixmap of this widget to that of its parent.
12038 bg_pixmap[NORMAL] = "<parent>"
12043 # This shows all the possible states for a button. The only one that
12044 # doesn't apply is the SELECTED state.
12046 fg[PRELIGHT] = { 0, 1.0, 1.0 }
12047 bg[PRELIGHT] = { 0, 0, 1.0 }
12048 bg[ACTIVE] = { 1.0, 0, 0 }
12049 fg[ACTIVE] = { 0, 1.0, 0 }
12050 bg[NORMAL] = { 1.0, 1.0, 0 }
12051 fg[NORMAL] = { .99, 0, .99 }
12052 bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
12053 fg[INSENSITIVE] = { 1.0, 0, 1.0 }
12056 # In this example, we inherit the attributes of the "button" style and then
12057 # override the font and background color when prelit to create a new
12058 # "main_button" style.
12060 style "main_button" = "button"
12062 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
12063 bg[PRELIGHT] = { 0.75, 0, 0 }
12066 style "toggle_button" = "button"
12068 fg[NORMAL] = { 1.0, 0, 0 }
12069 fg[ACTIVE] = { 1.0, 0, 0 }
12071 # This sets the background pixmap of the toggle_button to that of its
12072 # parent widget (as defined in the application).
12073 bg_pixmap[NORMAL] = "<parent>"
12078 bg_pixmap[NORMAL] = "marble.xpm"
12079 fg[NORMAL] = { 1.0, 1.0, 1.0 }
12084 font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
12087 # pixmap_path "~/.pixmaps"
12089 # These set the widget types to use the styles defined above.
12090 # The widget types are listed in the class hierarchy, but could probably be
12091 # just listed in this document for the users reference.
12093 widget_class "GtkWindow" style "window"
12094 widget_class "GtkDialog" style "window"
12095 widget_class "GtkFileSelection" style "window"
12096 widget_class "*Gtk*Scale" style "scale"
12097 widget_class "*GtkCheckButton*" style "toggle_button"
12098 widget_class "*GtkRadioButton*" style "toggle_button"
12099 widget_class "*GtkButton*" style "button"
12100 widget_class "*Ruler" style "ruler"
12101 widget_class "*GtkText" style "text"
12103 # This sets all the buttons that are children of the "main window" to
12104 # the main_button style. These must be documented to be taken advantage of.
12105 widget "main window.*GtkButton*" style "main_button"
12108 <!-- ***************************************************************** -->
12109 <sect>Writing Your Own Widgets
12110 <!-- ***************************************************************** -->
12112 <!-- ----------------------------------------------------------------- -->
12115 Although the GTK distribution comes with many types of widgets that
12116 should cover most basic needs, there may come a time when you need to
12117 create your own new widget type. Since GTK uses widget inheritance
12118 extensively, and there is already a widget that is close to what you want,
12119 it is often possible to make a useful new widget type in
12120 just a few lines of code. But before starting work on a new widget, check
12121 around first to make sure that someone has not already written
12122 it. This will prevent duplication of effort and keep the number of
12123 GTK widgets out there to a minimum, which will help keep both the code
12124 and the interface of different applications consistent. As a flip side
12125 to this, once you finish your widget, announce it to the world so
12126 other people can benefit. The best place to do this is probably the
12129 Complete sources for the example widgets are available at the place you
12130 got this tutorial, or from:
12132 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
12133 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
12136 <!-- ----------------------------------------------------------------- -->
12137 <sect1> The Anatomy Of A Widget
12139 In order to create a new widget, it is important to have an
12140 understanding of how GTK objects work. This section is just meant as a
12141 brief overview. See the reference documentation for the details.
12143 GTK widgets are implemented in an object oriented fashion. However,
12144 they are implemented in standard C. This greatly improves portability
12145 and stability over using current generation C++ compilers; however,
12146 it does mean that the widget writer has to pay attention to some of
12147 the implementation details. The information common to all instances of
12148 one class of widgets (e.g., to all Button widgets) is stored in the
12149 <em>class structure</em>. There is only one copy of this in
12150 which is stored information about the class's signals
12151 (which act like virtual functions in C). To support inheritance, the
12152 first field in the class structure must be a copy of the parent's
12153 class structure. The declaration of the class structure of GtkButtton
12157 struct _GtkButtonClass
12159 GtkContainerClass parent_class;
12161 void (* pressed) (GtkButton *button);
12162 void (* released) (GtkButton *button);
12163 void (* clicked) (GtkButton *button);
12164 void (* enter) (GtkButton *button);
12165 void (* leave) (GtkButton *button);
12169 When a button is treated as a container (for instance, when it is
12170 resized), its class structure can be cast to GtkContainerClass, and
12171 the relevant fields used to handle the signals.
12173 There is also a structure for each widget that is created on a
12174 per-instance basis. This structure has fields to store information that
12175 is different for each instance of the widget. We'll call this
12176 structure the <em>object structure</em>. For the Button class, it looks
12182 GtkContainer container;
12186 guint in_button : 1;
12187 guint button_down : 1;
12191 Note that, similar to the class structure, the first field is the
12192 object structure of the parent class, so that this structure can be
12193 cast to the parent class' object structure as needed.
12195 <!-- ----------------------------------------------------------------- -->
12196 <sect1> Creating a Composite widget
12198 <!-- ----------------------------------------------------------------- -->
12199 <sect2> Introduction
12201 One type of widget that you may be interested in creating is a
12202 widget that is merely an aggregate of other GTK widgets. This type of
12203 widget does nothing that couldn't be done without creating new
12204 widgets, but provides a convenient way of packaging user interface
12205 elements for reuse. The FileSelection and ColorSelection widgets in
12206 the standard distribution are examples of this type of widget.
12208 The example widget that we'll create in this section is the Tictactoe
12209 widget, a 3x3 array of toggle buttons which triggers a signal when all
12210 three buttons in a row, column, or on one of the diagonals are
12213 <!-- ----------------------------------------------------------------- -->
12214 <sect2> Choosing a parent class
12216 The parent class for a composite widget is typically the container
12217 class that holds all of the elements of the composite widget. For
12218 example, the parent class of the FileSelection widget is the
12219 Dialog class. Since our buttons will be arranged in a table, it
12220 might seem natural to make our parent class the Table
12221 class. Unfortunately, this turns out not to work. The creation of a
12222 widget is divided among two functions - a <tt/WIDGETNAME_new()/
12223 function that the user calls, and a <tt/WIDGETNAME_init()/ function
12224 which does the basic work of initializing the widget which is
12225 independent of the arguments passed to the <tt/_new()/
12226 function. Descendant widgets only call the <tt/_init/ function of
12227 their parent widget. But this division of labor doesn't work well for
12228 tables, which when created need to know the number of rows and
12229 columns in the table. Unless we want to duplicate most of the
12230 functionality of <tt/gtk_table_new()/ in our Tictactoe widget, we had
12231 best avoid deriving it from Table. For that reason, we derive it
12232 from VBox instead, and stick our table inside the VBox.
12234 <!-- ----------------------------------------------------------------- -->
12235 <sect2> The header file
12237 Each widget class has a header file which declares the object and
12238 class structures for that widget, along with public functions.
12239 A couple of features are worth pointing out. To prevent duplicate
12240 definitions, we wrap the entire header file in:
12243 #ifndef __TICTACTOE_H__
12244 #define __TICTACTOE_H__
12248 #endif /* __TICTACTOE_H__ */
12251 And to keep C++ programs that include the header file happy, in:
12256 #endif /* __cplusplus */
12262 #endif /* __cplusplus */
12265 Along with the functions and structures, we declare three standard
12266 macros in our header file, <tt/TICTACTOE(obj)/,
12267 <tt/TICTACTOE_CLASS(klass)/, and <tt/IS_TICTACTOE(obj)/, which cast a
12268 pointer into a pointer to the object or class structure, and check
12269 if an object is a Tictactoe widget respectively.
12271 Here is the complete header file:
12276 #ifndef __TICTACTOE_H__
12277 #define __TICTACTOE_H__
12279 #include <gdk/gdk.h>
12280 #include <gtk/gtkvbox.h>
12284 #endif /* __cplusplus */
12286 #define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
12287 #define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
12288 #define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
12291 typedef struct _Tictactoe Tictactoe;
12292 typedef struct _TictactoeClass TictactoeClass;
12298 GtkWidget *buttons[3][3];
12301 struct _TictactoeClass
12303 GtkVBoxClass parent_class;
12305 void (* tictactoe) (Tictactoe *ttt);
12308 guint tictactoe_get_type (void);
12309 GtkWidget* tictactoe_new (void);
12310 void tictactoe_clear (Tictactoe *ttt);
12314 #endif /* __cplusplus */
12316 #endif /* __TICTACTOE_H__ */
12320 <!-- ----------------------------------------------------------------- -->
12321 <sect2> The <tt/_get_type()/ function.
12323 We now continue on to the implementation of our widget. A core
12324 function for every widget is the function
12325 <tt/WIDGETNAME_get_type()/. This function, when first called, tells
12326 GTK about the widget class, and gets an ID that uniquely identifies
12327 the widget class. Upon subsequent calls, it just returns the ID.
12331 tictactoe_get_type ()
12333 static guint ttt_type = 0;
12337 GtkTypeInfo ttt_info =
12340 sizeof (Tictactoe),
12341 sizeof (TictactoeClass),
12342 (GtkClassInitFunc) tictactoe_class_init,
12343 (GtkObjectInitFunc) tictactoe_init,
12344 (GtkArgSetFunc) NULL,
12345 (GtkArgGetFunc) NULL
12348 ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
12355 The GtkTypeInfo structure has the following definition:
12358 struct _GtkTypeInfo
12363 GtkClassInitFunc class_init_func;
12364 GtkObjectInitFunc object_init_func;
12365 GtkArgSetFunc arg_set_func;
12366 GtkArgGetFunc arg_get_func;
12370 The fields of this structure are pretty self-explanatory. We'll ignore
12371 the <tt/arg_set_func/ and <tt/arg_get_func/ fields here: they have an important,
12373 unimplemented, role in allowing widget options to be conveniently set
12374 from interpreted languages. Once GTK has a correctly filled in copy of
12375 this structure, it knows how to create objects of a particular widget
12378 <!-- ----------------------------------------------------------------- -->
12379 <sect2> The <tt/_class_init()/ function
12381 The <tt/WIDGETNAME_class_init()/ function initializes the fields of
12382 the widget's class structure, and sets up any signals for the
12383 class. For our Tictactoe widget it looks like:
12392 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
12395 tictactoe_class_init (TictactoeClass *class)
12397 GtkObjectClass *object_class;
12399 object_class = (GtkObjectClass*) class;
12401 tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
12403 object_class->type,
12404 GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
12405 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
12408 gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
12410 class->tictactoe = NULL;
12414 Our widget has just one signal, the <tt/tictactoe/ signal that is
12415 invoked when a row, column, or diagonal is completely filled in. Not
12416 every composite widget needs signals, so if you are reading this for
12417 the first time, you may want to skip to the next section now, as
12418 things are going to get a bit complicated.
12423 gint gtk_signal_new( const gchar *name,
12424 GtkSignalRunType run_type,
12425 GtkType object_type,
12426 gint function_offset,
12427 GtkSignalMarshaller marshaller,
12428 GtkType return_val,
12433 Creates a new signal. The parameters are:
12436 <item> <tt/name/: The name of the signal.
12437 <item> <tt/run_type/: Whether the default handler runs before or after
12438 user handlers. Usually this will be <tt/GTK_RUN_FIRST/, or <tt/GTK_RUN_LAST/,
12439 although there are other possibilities.
12440 <item> <tt/object_type/: The ID of the object that this signal applies
12441 to. (It will also apply to that objects descendants.)
12442 <item> <tt/function_offset/: The offset within the class structure of
12443 a pointer to the default handler.
12444 <item> <tt/marshaller/: A function that is used to invoke the signal
12445 handler. For signal handlers that have no arguments other than the
12446 object that emitted the signal and user data, we can use the
12447 pre-supplied marshaller function <tt/gtk_signal_default_marshaller/.
12448 <item> <tt/return_val/: The type of the return val.
12449 <item> <tt/nparams/: The number of parameters of the signal handler
12450 (other than the two default ones mentioned above)
12451 <item> <tt/.../: The types of the parameters.
12454 When specifying types, the <tt/GtkType/ enumeration is used:
12479 /* it'd be great if the next two could be removed eventually */
12481 GTK_TYPE_C_CALLBACK,
12485 } GtkFundamentalType;
12488 <tt/gtk_signal_new()/ returns a unique integer identifier for the
12489 signal, that we store in the <tt/tictactoe_signals/ array, which we
12490 index using an enumeration. (Conventionally, the enumeration elements
12491 are the signal name, uppercased, but here there would be a conflict
12492 with the <tt/TICTACTOE()/ macro, so we called it <tt/TICTACTOE_SIGNAL/
12495 After creating our signals, we need to tell GTK to associate our
12496 signals with the Tictactoe class. We do that by calling
12497 <tt/gtk_object_class_add_signals()/. We then set the pointer which
12498 points to the default handler for the "tictactoe" signal to NULL,
12499 indicating that there is no default action.
12501 <!-- ----------------------------------------------------------------- -->
12502 <sect2> The <tt/_init()/ function.
12504 Each widget class also needs a function to initialize the object
12505 structure. Usually, this function has the fairly limited role of
12506 setting the fields of the structure to default values. For composite
12507 widgets, however, this function also creates the component widgets.
12511 tictactoe_init (Tictactoe *ttt)
12516 table = gtk_table_new (3, 3, TRUE);
12517 gtk_container_add (GTK_CONTAINER(ttt), table);
12518 gtk_widget_show (table);
12523 ttt->buttons[i][j] = gtk_toggle_button_new ();
12524 gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
12526 gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
12527 GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
12528 gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
12529 gtk_widget_show (ttt->buttons[i][j]);
12534 <!-- ----------------------------------------------------------------- -->
12535 <sect2> And the rest...
12537 There is one more function that every widget (except for base widget
12538 types like Bin that cannot be instantiated) needs to have - the
12539 function that the user calls to create an object of that type. This is
12540 conventionally called <tt/WIDGETNAME_new()/. In some
12541 widgets, though not for the Tictactoe widgets, this function takes
12542 arguments, and does some setup based on the arguments. The other two
12543 functions are specific to the Tictactoe widget.
12545 <tt/tictactoe_clear()/ is a public function that resets all the
12546 buttons in the widget to the up position. Note the use of
12547 <tt/gtk_signal_handler_block_by_data()/ to keep our signal handler for
12548 button toggles from being triggered unnecessarily.
12550 <tt/tictactoe_toggle()/ is the signal handler that is invoked when the
12551 user clicks on a button. It checks to see if there are any winning
12552 combinations that involve the toggled button, and if so, emits
12553 the "tictactoe" signal.
12559 return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
12563 tictactoe_clear (Tictactoe *ttt)
12570 gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
12571 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
12573 gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
12578 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
12582 static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
12583 { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
12584 { 0, 1, 2 }, { 0, 1, 2 } };
12585 static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
12586 { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
12587 { 0, 1, 2 }, { 2, 1, 0 } };
12589 int success, found;
12591 for (k=0; k<8; k++)
12598 success = success &&
12599 GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
12601 ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
12604 if (success && found)
12606 gtk_signal_emit (GTK_OBJECT (ttt),
12607 tictactoe_signals[TICTACTOE_SIGNAL]);
12614 And finally, an example program using our Tictactoe widget:
12617 #include <gtk/gtk.h>
12618 #include "tictactoe.h"
12620 /* Invoked when a row, column or diagonal is completed */
12622 win (GtkWidget *widget, gpointer data)
12624 g_print ("Yay!\n");
12625 tictactoe_clear (TICTACTOE (widget));
12629 main (int argc, char *argv[])
12634 gtk_init (&argc, &argv);
12636 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
12638 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
12640 gtk_signal_connect (GTK_OBJECT (window), "destroy",
12641 GTK_SIGNAL_FUNC (gtk_exit), NULL);
12643 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
12645 /* Create a new Tictactoe widget */
12646 ttt = tictactoe_new ();
12647 gtk_container_add (GTK_CONTAINER (window), ttt);
12648 gtk_widget_show (ttt);
12650 /* And attach to its "tictactoe" signal */
12651 gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
12652 GTK_SIGNAL_FUNC (win), NULL);
12654 gtk_widget_show (window);
12663 <!-- ----------------------------------------------------------------- -->
12664 <sect1> Creating a widget from scratch.
12666 <!-- ----------------------------------------------------------------- -->
12667 <sect2> Introduction
12669 In this section, we'll learn more about how widgets display themselves
12670 on the screen and interact with events. As an example of this, we'll
12671 create an analog dial widget with a pointer that the user can drag to
12674 <!-- ----------------------------------------------------------------- -->
12675 <sect2> Displaying a widget on the screen
12677 There are several steps that are involved in displaying on the screen.
12678 After the widget is created with a call to <tt/WIDGETNAME_new()/,
12679 several more functions are needed:
12682 <item> <tt/WIDGETNAME_realize()/ is responsible for creating an X
12683 window for the widget if it has one.
12684 <item> <tt/WIDGETNAME_map()/ is invoked after the user calls
12685 <tt/gtk_widget_show()/. It is responsible for making sure the widget
12686 is actually drawn on the screen (<em/mapped/). For a container class,
12687 it must also make calls to <tt/map()/> functions of any child widgets.
12688 <item> <tt/WIDGETNAME_draw()/ is invoked when <tt/gtk_widget_draw()/
12689 is called for the widget or one of its ancestors. It makes the actual
12690 calls to the drawing functions to draw the widget on the screen. For
12691 container widgets, this function must make calls to
12692 <tt/gtk_widget_draw()/ for its child widgets.
12693 <item> <tt/WIDGETNAME_expose()/ is a handler for expose events for the
12694 widget. It makes the necessary calls to the drawing functions to draw
12695 the exposed portion on the screen. For container widgets, this
12696 function must generate expose events for its child widgets which don't
12697 have their own windows. (If they have their own windows, then X will
12698 generate the necessary expose events.)
12701 You might notice that the last two functions are quite similar - each
12702 is responsible for drawing the widget on the screen. In fact many
12703 types of widgets don't really care about the difference between the
12704 two. The default <tt/draw()/ function in the widget class simply
12705 generates a synthetic expose event for the redrawn area. However, some
12706 types of widgets can save work by distinguishing between the two
12707 functions. For instance, if a widget has multiple X windows, then
12708 since expose events identify the exposed window, it can redraw only
12709 the affected window, which is not possible for calls to <tt/draw()/.
12711 Container widgets, even if they don't care about the difference for
12712 themselves, can't simply use the default <tt/draw()/ function because
12713 their child widgets might care about the difference. However,
12714 it would be wasteful to duplicate the drawing code between the two
12715 functions. The convention is that such widgets have a function called
12716 <tt/WIDGETNAME_paint()/ that does the actual work of drawing the
12717 widget, that is then called by the <tt/draw()/ and <tt/expose()/
12720 In our example approach, since the dial widget is not a container
12721 widget, and only has a single window, we can take the simplest
12722 approach and use the default <tt/draw()/ function and only implement
12723 an <tt/expose()/ function.
12725 <!-- ----------------------------------------------------------------- -->
12726 <sect2> The origins of the Dial Widget
12728 Just as all land animals are just variants on the first amphibian that
12729 crawled up out of the mud, GTK widgets tend to start off as variants
12730 of some other, previously written widget. Thus, although this section
12731 is entitled "Creating a Widget from Scratch", the Dial widget really
12732 began with the source code for the Range widget. This was picked as a
12733 starting point because it would be nice if our Dial had the same
12734 interface as the Scale widgets which are just specialized descendants
12735 of the Range widget. So, though the source code is presented below in
12736 finished form, it should not be implied that it was written, <em>ab
12737 initio</em> in this fashion. Also, if you aren't yet familiar with
12738 how scale widgets work from the application writer's point of view, it
12739 would be a good idea to look them over before continuing.
12741 <!-- ----------------------------------------------------------------- -->
12744 Quite a bit of our widget should look pretty familiar from the
12745 Tictactoe widget. First, we have a header file:
12748 /* GTK - The GIMP Toolkit
12749 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
12751 * This library is free software; you can redistribute it and/or
12752 * modify it under the terms of the GNU Library General Public
12753 * License as published by the Free Software Foundation; either
12754 * version 2 of the License, or (at your option) any later version.
12756 * This library is distributed in the hope that it will be useful,
12757 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12758 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12759 * Library General Public License for more details.
12761 * You should have received a copy of the GNU Library General Public
12762 * License along with this library; if not, write to the Free
12763 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
12766 #ifndef __GTK_DIAL_H__
12767 #define __GTK_DIAL_H__
12769 #include <gdk/gdk.h>
12770 #include <gtk/gtkadjustment.h>
12771 #include <gtk/gtkwidget.h>
12776 #endif /* __cplusplus */
12779 #define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
12780 #define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
12781 #define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
12784 typedef struct _GtkDial GtkDial;
12785 typedef struct _GtkDialClass GtkDialClass;
12791 /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
12794 /* Button currently pressed or 0 if none */
12797 /* Dimensions of dial components */
12799 gint pointer_width;
12801 /* ID of update timer, or 0 if none */
12804 /* Current angle */
12807 /* Old values from adjustment stored so we know when something changes */
12812 /* The adjustment object that stores the data for this dial */
12813 GtkAdjustment *adjustment;
12816 struct _GtkDialClass
12818 GtkWidgetClass parent_class;
12822 GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
12823 guint gtk_dial_get_type (void);
12824 GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
12825 void gtk_dial_set_update_policy (GtkDial *dial,
12826 GtkUpdateType policy);
12828 void gtk_dial_set_adjustment (GtkDial *dial,
12829 GtkAdjustment *adjustment);
12832 #endif /* __cplusplus */
12835 #endif /* __GTK_DIAL_H__ */
12838 Since there is quite a bit more going on in this widget than the last
12839 one, we have more fields in the data structure, but otherwise things
12840 are pretty similar.
12842 Next, after including header files and declaring a few constants,
12843 we have some functions to provide information about the widget
12849 #include <gtk/gtkmain.h>
12850 #include <gtk/gtksignal.h>
12852 #include "gtkdial.h"
12854 #define SCROLL_DELAY_LENGTH 300
12855 #define DIAL_DEFAULT_SIZE 100
12857 /* Forward declarations */
12859 [ omitted to save space ]
12863 static GtkWidgetClass *parent_class = NULL;
12866 gtk_dial_get_type ()
12868 static guint dial_type = 0;
12872 GtkTypeInfo dial_info =
12876 sizeof (GtkDialClass),
12877 (GtkClassInitFunc) gtk_dial_class_init,
12878 (GtkObjectInitFunc) gtk_dial_init,
12879 (GtkArgSetFunc) NULL,
12880 (GtkArgGetFunc) NULL,
12883 dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info);
12890 gtk_dial_class_init (GtkDialClass *class)
12892 GtkObjectClass *object_class;
12893 GtkWidgetClass *widget_class;
12895 object_class = (GtkObjectClass*) class;
12896 widget_class = (GtkWidgetClass*) class;
12898 parent_class = gtk_type_class (gtk_widget_get_type ());
12900 object_class->destroy = gtk_dial_destroy;
12902 widget_class->realize = gtk_dial_realize;
12903 widget_class->expose_event = gtk_dial_expose;
12904 widget_class->size_request = gtk_dial_size_request;
12905 widget_class->size_allocate = gtk_dial_size_allocate;
12906 widget_class->button_press_event = gtk_dial_button_press;
12907 widget_class->button_release_event = gtk_dial_button_release;
12908 widget_class->motion_notify_event = gtk_dial_motion_notify;
12912 gtk_dial_init (GtkDial *dial)
12915 dial->policy = GTK_UPDATE_CONTINUOUS;
12918 dial->pointer_width = 0;
12920 dial->old_value = 0.0;
12921 dial->old_lower = 0.0;
12922 dial->old_upper = 0.0;
12923 dial->adjustment = NULL;
12927 gtk_dial_new (GtkAdjustment *adjustment)
12931 dial = gtk_type_new (gtk_dial_get_type ());
12934 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
12936 gtk_dial_set_adjustment (dial, adjustment);
12938 return GTK_WIDGET (dial);
12942 gtk_dial_destroy (GtkObject *object)
12946 g_return_if_fail (object != NULL);
12947 g_return_if_fail (GTK_IS_DIAL (object));
12949 dial = GTK_DIAL (object);
12951 if (dial->adjustment)
12952 gtk_object_unref (GTK_OBJECT (dial->adjustment));
12954 if (GTK_OBJECT_CLASS (parent_class)->destroy)
12955 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
12959 Note that this <tt/init()/ function does less than for the Tictactoe
12960 widget, since this is not a composite widget, and the <tt/new()/
12961 function does more, since it now has an argument. Also, note that when
12962 we store a pointer to the Adjustment object, we increment its
12963 reference count, (and correspondingly decrement it when we no longer
12964 use it) so that GTK can keep track of when it can be safely destroyed.
12967 Also, there are a few function to manipulate the widget's options:
12971 gtk_dial_get_adjustment (GtkDial *dial)
12973 g_return_val_if_fail (dial != NULL, NULL);
12974 g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
12976 return dial->adjustment;
12980 gtk_dial_set_update_policy (GtkDial *dial,
12981 GtkUpdateType policy)
12983 g_return_if_fail (dial != NULL);
12984 g_return_if_fail (GTK_IS_DIAL (dial));
12986 dial->policy = policy;
12990 gtk_dial_set_adjustment (GtkDial *dial,
12991 GtkAdjustment *adjustment)
12993 g_return_if_fail (dial != NULL);
12994 g_return_if_fail (GTK_IS_DIAL (dial));
12996 if (dial->adjustment)
12998 gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
12999 gtk_object_unref (GTK_OBJECT (dial->adjustment));
13002 dial->adjustment = adjustment;
13003 gtk_object_ref (GTK_OBJECT (dial->adjustment));
13005 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
13006 (GtkSignalFunc) gtk_dial_adjustment_changed,
13008 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
13009 (GtkSignalFunc) gtk_dial_adjustment_value_changed,
13012 dial->old_value = adjustment->value;
13013 dial->old_lower = adjustment->lower;
13014 dial->old_upper = adjustment->upper;
13016 gtk_dial_update (dial);
13020 <sect2> <tt/gtk_dial_realize()/
13023 Now we come to some new types of functions. First, we have a function
13024 that does the work of creating the X window. Notice that a mask is
13025 passed to the function <tt/gdk_window_new()/ which specifies which fields of
13026 the GdkWindowAttr structure actually have data in them (the remaining
13027 fields will be given default values). Also worth noting is the way the
13028 event mask of the widget is created. We call
13029 <tt/gtk_widget_get_events()/ to retrieve the event mask that the user
13030 has specified for this widget (with <tt/gtk_widget_set_events()/), and
13031 add the events that we are interested in ourselves.
13034 After creating the window, we set its style and background, and put a
13035 pointer to the widget in the user data field of the GdkWindow. This
13036 last step allows GTK to dispatch events for this window to the correct
13041 gtk_dial_realize (GtkWidget *widget)
13044 GdkWindowAttr attributes;
13045 gint attributes_mask;
13047 g_return_if_fail (widget != NULL);
13048 g_return_if_fail (GTK_IS_DIAL (widget));
13050 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
13051 dial = GTK_DIAL (widget);
13053 attributes.x = widget->allocation.x;
13054 attributes.y = widget->allocation.y;
13055 attributes.width = widget->allocation.width;
13056 attributes.height = widget->allocation.height;
13057 attributes.wclass = GDK_INPUT_OUTPUT;
13058 attributes.window_type = GDK_WINDOW_CHILD;
13059 attributes.event_mask = gtk_widget_get_events (widget) |
13060 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
13061 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
13062 GDK_POINTER_MOTION_HINT_MASK;
13063 attributes.visual = gtk_widget_get_visual (widget);
13064 attributes.colormap = gtk_widget_get_colormap (widget);
13066 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
13067 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
13069 widget->style = gtk_style_attach (widget->style, widget->window);
13071 gdk_window_set_user_data (widget->window, widget);
13073 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
13077 <sect2> Size negotiation
13080 Before the first time that the window containing a widget is
13081 displayed, and whenever the layout of the window changes, GTK asks
13082 each child widget for its desired size. This request is handled by the
13083 function <tt/gtk_dial_size_request()/. Since our widget isn't a
13084 container widget, and has no real constraints on its size, we just
13085 return a reasonable default value.
13089 gtk_dial_size_request (GtkWidget *widget,
13090 GtkRequisition *requisition)
13092 requisition->width = DIAL_DEFAULT_SIZE;
13093 requisition->height = DIAL_DEFAULT_SIZE;
13098 After all the widgets have requested an ideal size, the layout of the
13099 window is computed and each child widget is notified of its actual
13100 size. Usually, this will be at least as large as the requested size,
13101 but if for instance the user has resized the window, it may
13102 occasionally be smaller than the requested size. The size notification
13103 is handled by the function <tt/gtk_dial_size_allocate()/. Notice that
13104 as well as computing the sizes of some component pieces for future
13105 use, this routine also does the grunt work of moving the widget's X
13106 window into the new position and size.
13110 gtk_dial_size_allocate (GtkWidget *widget,
13111 GtkAllocation *allocation)
13115 g_return_if_fail (widget != NULL);
13116 g_return_if_fail (GTK_IS_DIAL (widget));
13117 g_return_if_fail (allocation != NULL);
13119 widget->allocation = *allocation;
13120 if (GTK_WIDGET_REALIZED (widget))
13122 dial = GTK_DIAL (widget);
13124 gdk_window_move_resize (widget->window,
13125 allocation->x, allocation->y,
13126 allocation->width, allocation->height);
13128 dial->radius = MAX(allocation->width,allocation->height) * 0.45;
13129 dial->pointer_width = dial->radius / 5;
13134 <!-- ----------------------------------------------------------------- -->
13135 <sect2> <tt/gtk_dial_expose()/
13138 As mentioned above, all the drawing of this widget is done in the
13139 handler for expose events. There's not much to remark on here except
13140 the use of the function <tt/gtk_draw_polygon/ to draw the pointer with
13141 three dimensional shading according to the colors stored in the
13146 gtk_dial_expose (GtkWidget *widget,
13147 GdkEventExpose *event)
13150 GdkPoint points[3];
13157 g_return_val_if_fail (widget != NULL, FALSE);
13158 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13159 g_return_val_if_fail (event != NULL, FALSE);
13161 if (event->count > 0)
13164 dial = GTK_DIAL (widget);
13166 gdk_window_clear_area (widget->window,
13168 widget->allocation.width,
13169 widget->allocation.height);
13171 xc = widget->allocation.width/2;
13172 yc = widget->allocation.height/2;
13176 for (i=0; i<25; i++)
13178 theta = (i*M_PI/18. - M_PI/6.);
13182 tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
13184 gdk_draw_line (widget->window,
13185 widget->style->fg_gc[widget->state],
13186 xc + c*(dial->radius - tick_length),
13187 yc - s*(dial->radius - tick_length),
13188 xc + c*dial->radius,
13189 yc - s*dial->radius);
13194 s = sin(dial->angle);
13195 c = cos(dial->angle);
13198 points[0].x = xc + s*dial->pointer_width/2;
13199 points[0].y = yc + c*dial->pointer_width/2;
13200 points[1].x = xc + c*dial->radius;
13201 points[1].y = yc - s*dial->radius;
13202 points[2].x = xc - s*dial->pointer_width/2;
13203 points[2].y = yc - c*dial->pointer_width/2;
13205 gtk_draw_polygon (widget->style,
13216 <!-- ----------------------------------------------------------------- -->
13217 <sect2> Event handling
13219 The rest of the widget's code handles various types of events, and
13220 isn't too different from what would be found in many GTK
13221 applications. Two types of events can occur - either the user can
13222 click on the widget with the mouse and drag to move the pointer, or
13223 the value of the Adjustment object can change due to some external
13226 When the user clicks on the widget, we check to see if the click was
13227 appropriately near the pointer, and if so, store the button that the
13228 user clicked with in the <tt/button/ field of the widget
13229 structure, and grab all mouse events with a call to
13230 <tt/gtk_grab_add()/. Subsequent motion of the mouse causes the
13231 value of the control to be recomputed (by the function
13232 <tt/gtk_dial_update_mouse/). Depending on the policy that has been
13233 set, "value_changed" events are either generated instantly
13234 (<tt/GTK_UPDATE_CONTINUOUS/), after a delay in a timer added with
13235 <tt/gtk_timeout_add()/ (<tt/GTK_UPDATE_DELAYED/), or only when the
13236 button is released (<tt/GTK_UPDATE_DISCONTINUOUS/).
13240 gtk_dial_button_press (GtkWidget *widget,
13241 GdkEventButton *event)
13247 double d_perpendicular;
13249 g_return_val_if_fail (widget != NULL, FALSE);
13250 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13251 g_return_val_if_fail (event != NULL, FALSE);
13253 dial = GTK_DIAL (widget);
13255 /* Determine if button press was within pointer region - we
13256 do this by computing the parallel and perpendicular distance of
13257 the point where the mouse was pressed from the line passing through
13260 dx = event->x - widget->allocation.width / 2;
13261 dy = widget->allocation.height / 2 - event->y;
13263 s = sin(dial->angle);
13264 c = cos(dial->angle);
13266 d_parallel = s*dy + c*dx;
13267 d_perpendicular = fabs(s*dx - c*dy);
13269 if (!dial->button &&
13270 (d_perpendicular < dial->pointer_width/2) &&
13271 (d_parallel > - dial->pointer_width))
13273 gtk_grab_add (widget);
13275 dial->button = event->button;
13277 gtk_dial_update_mouse (dial, event->x, event->y);
13284 gtk_dial_button_release (GtkWidget *widget,
13285 GdkEventButton *event)
13289 g_return_val_if_fail (widget != NULL, FALSE);
13290 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13291 g_return_val_if_fail (event != NULL, FALSE);
13293 dial = GTK_DIAL (widget);
13295 if (dial->button == event->button)
13297 gtk_grab_remove (widget);
13301 if (dial->policy == GTK_UPDATE_DELAYED)
13302 gtk_timeout_remove (dial->timer);
13304 if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
13305 (dial->old_value != dial->adjustment->value))
13306 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13313 gtk_dial_motion_notify (GtkWidget *widget,
13314 GdkEventMotion *event)
13317 GdkModifierType mods;
13320 g_return_val_if_fail (widget != NULL, FALSE);
13321 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13322 g_return_val_if_fail (event != NULL, FALSE);
13324 dial = GTK_DIAL (widget);
13326 if (dial->button != 0)
13331 if (event->is_hint || (event->window != widget->window))
13332 gdk_window_get_pointer (widget->window, &x, &y, &mods);
13334 switch (dial->button)
13337 mask = GDK_BUTTON1_MASK;
13340 mask = GDK_BUTTON2_MASK;
13343 mask = GDK_BUTTON3_MASK;
13351 gtk_dial_update_mouse (dial, x,y);
13358 gtk_dial_timer (GtkDial *dial)
13360 g_return_val_if_fail (dial != NULL, FALSE);
13361 g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
13363 if (dial->policy == GTK_UPDATE_DELAYED)
13364 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13370 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
13375 g_return_if_fail (dial != NULL);
13376 g_return_if_fail (GTK_IS_DIAL (dial));
13378 xc = GTK_WIDGET(dial)->allocation.width / 2;
13379 yc = GTK_WIDGET(dial)->allocation.height / 2;
13381 old_value = dial->adjustment->value;
13382 dial->angle = atan2(yc-y, x-xc);
13384 if (dial->angle < -M_PI/2.)
13385 dial->angle += 2*M_PI;
13387 if (dial->angle < -M_PI/6)
13388 dial->angle = -M_PI/6;
13390 if (dial->angle > 7.*M_PI/6.)
13391 dial->angle = 7.*M_PI/6.;
13393 dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
13394 (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
13396 if (dial->adjustment->value != old_value)
13398 if (dial->policy == GTK_UPDATE_CONTINUOUS)
13400 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13404 gtk_widget_draw (GTK_WIDGET(dial), NULL);
13406 if (dial->policy == GTK_UPDATE_DELAYED)
13409 gtk_timeout_remove (dial->timer);
13411 dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
13412 (GtkFunction) gtk_dial_timer,
13420 Changes to the Adjustment by external means are communicated to our
13421 widget by the "changed" and "value_changed" signals. The handlers
13422 for these functions call <tt/gtk_dial_update()/ to validate the
13423 arguments, compute the new pointer angle, and redraw the widget (by
13424 calling <tt/gtk_widget_draw()/).
13428 gtk_dial_update (GtkDial *dial)
13432 g_return_if_fail (dial != NULL);
13433 g_return_if_fail (GTK_IS_DIAL (dial));
13435 new_value = dial->adjustment->value;
13437 if (new_value < dial->adjustment->lower)
13438 new_value = dial->adjustment->lower;
13440 if (new_value > dial->adjustment->upper)
13441 new_value = dial->adjustment->upper;
13443 if (new_value != dial->adjustment->value)
13445 dial->adjustment->value = new_value;
13446 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13449 dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
13450 (dial->adjustment->upper - dial->adjustment->lower);
13452 gtk_widget_draw (GTK_WIDGET(dial), NULL);
13456 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
13461 g_return_if_fail (adjustment != NULL);
13462 g_return_if_fail (data != NULL);
13464 dial = GTK_DIAL (data);
13466 if ((dial->old_value != adjustment->value) ||
13467 (dial->old_lower != adjustment->lower) ||
13468 (dial->old_upper != adjustment->upper))
13470 gtk_dial_update (dial);
13472 dial->old_value = adjustment->value;
13473 dial->old_lower = adjustment->lower;
13474 dial->old_upper = adjustment->upper;
13479 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
13484 g_return_if_fail (adjustment != NULL);
13485 g_return_if_fail (data != NULL);
13487 dial = GTK_DIAL (data);
13489 if (dial->old_value != adjustment->value)
13491 gtk_dial_update (dial);
13493 dial->old_value = adjustment->value;
13498 <!-- ----------------------------------------------------------------- -->
13499 <sect2> Possible Enhancements
13501 The Dial widget as we've described it so far runs about 670 lines of
13502 code. Although that might sound like a fair bit, we've really
13503 accomplished quite a bit with that much code, especially since much of
13504 that length is headers and boilerplate. However, there are quite a few
13505 more enhancements that could be made to this widget:
13508 <item> If you try this widget out, you'll find that there is some
13509 flashing as the pointer is dragged around. This is because the entire
13510 widget is erased every time the pointer is moved before being
13511 redrawn. Often, the best way to handle this problem is to draw to an
13512 offscreen pixmap, then copy the final results onto the screen in one
13513 step. (The ProgressBar widget draws itself in this fashion.)
13515 <item> The user should be able to use the up and down arrow keys to
13516 increase and decrease the value.
13518 <item> It would be nice if the widget had buttons to increase and
13519 decrease the value in small or large steps. Although it would be
13520 possible to use embedded Button widgets for this, we would also like
13521 the buttons to auto-repeat when held down, as the arrows on a
13522 scrollbar do. Most of the code to implement this type of behavior can
13523 be found in the Range widget.
13525 <item> The Dial widget could be made into a container widget with a
13526 single child widget positioned at the bottom between the buttons
13527 mentioned above. The user could then add their choice of a label or
13528 entry widget to display the current value of the dial.
13532 <!-- ----------------------------------------------------------------- -->
13533 <sect1> Learning More
13536 Only a small part of the many details involved in creating widgets
13537 could be described above. If you want to write your own widgets, the
13538 best source of examples is the GTK source itself. Ask yourself some
13539 questions about the widget you want to write: IS it a Container
13540 widget? Does it have its own window? Is it a modification of an
13541 existing widget? Then find a similar widget, and start making changes.
13544 <!-- ***************************************************************** -->
13545 <sect>Scribble, A Simple Example Drawing Program
13546 <!-- ***************************************************************** -->
13548 <!-- ----------------------------------------------------------------- -->
13551 In this section, we will build a simple drawing program. In the
13552 process, we will examine how to handle mouse events, how to draw in a
13553 window, and how to do drawing better by using a backing pixmap. After
13554 creating the simple drawing program, we will extend it by adding
13555 support for XInput devices, such as drawing tablets. GTK provides
13556 support routines which makes getting extended information, such as
13557 pressure and tilt, from such devices quite easy.
13559 <!-- ----------------------------------------------------------------- -->
13560 <sect1> Event Handling
13562 The GTK signals we have already discussed are for high-level actions,
13563 such as a menu item being selected. However, sometimes it is useful to
13564 learn about lower-level occurrences, such as the mouse being moved, or
13565 a key being pressed. There are also GTK signals corresponding to these
13566 low-level <em>events</em>. The handlers for these signals have an
13567 extra parameter which is a pointer to a structure containing
13568 information about the event. For instance, motion event handlers are
13569 passed a pointer to a GdkEventMotion structure which looks (in part)
13573 struct _GdkEventMotion
13586 <tt/type/ will be set to the event type, in this case
13587 <tt/GDK_MOTION_NOTIFY/, window is the window in which the event
13588 occurred. <tt/x/ and <tt/y/ give the coordinates of the event.
13589 <tt/state/ specifies the modifier state when the event
13590 occurred (that is, it specifies which modifier keys and mouse buttons
13591 were pressed). It is the bitwise OR of some of the following:
13609 As for other signals, to determine what happens when an event occurs
13610 we call <tt>gtk_signal_connect()</tt>. But we also need let GTK
13611 know which events we want to be notified about. To do this, we call
13615 void gtk_widget_set_events (GtkWidget *widget,
13619 The second field specifies the events we are interested in. It
13620 is the bitwise OR of constants that specify different types
13621 of events. For future reference the event types are:
13625 GDK_POINTER_MOTION_MASK
13626 GDK_POINTER_MOTION_HINT_MASK
13627 GDK_BUTTON_MOTION_MASK
13628 GDK_BUTTON1_MOTION_MASK
13629 GDK_BUTTON2_MOTION_MASK
13630 GDK_BUTTON3_MOTION_MASK
13631 GDK_BUTTON_PRESS_MASK
13632 GDK_BUTTON_RELEASE_MASK
13634 GDK_KEY_RELEASE_MASK
13635 GDK_ENTER_NOTIFY_MASK
13636 GDK_LEAVE_NOTIFY_MASK
13637 GDK_FOCUS_CHANGE_MASK
13639 GDK_PROPERTY_CHANGE_MASK
13640 GDK_PROXIMITY_IN_MASK
13641 GDK_PROXIMITY_OUT_MASK
13644 There are a few subtle points that have to be observed when calling
13645 <tt/gtk_widget_set_events()/. First, it must be called before the X window
13646 for a GTK widget is created. In practical terms, this means you
13647 should call it immediately after creating the widget. Second, the
13648 widget must have an associated X window. For efficiency, many widget
13649 types do not have their own window, but draw in their parent's window.
13672 To capture events for these widgets, you need to use an EventBox
13673 widget. See the section on the <ref id="sec_EventBox"
13674 name="EventBox"> widget for details.
13676 For our drawing program, we want to know when the mouse button is
13677 pressed and when the mouse is moved, so we specify
13678 <tt/GDK_POINTER_MOTION_MASK/ and <tt/GDK_BUTTON_PRESS_MASK/. We also
13679 want to know when we need to redraw our window, so we specify
13680 <tt/GDK_EXPOSURE_MASK/. Although we want to be notified via a
13681 Configure event when our window size changes, we don't have to specify
13682 the corresponding <tt/GDK_STRUCTURE_MASK/ flag, because it is
13683 automatically specified for all windows.
13685 It turns out, however, that there is a problem with just specifying
13686 <tt/GDK_POINTER_MOTION_MASK/. This will cause the server to add a new
13687 motion event to the event queue every time the user moves the mouse.
13688 Imagine that it takes us 0.1 seconds to handle a motion event, but the
13689 X server queues a new motion event every 0.05 seconds. We will soon
13690 get way behind the users drawing. If the user draws for 5 seconds,
13691 it will take us another 5 seconds to catch up after they release
13692 the mouse button! What we would like is to only get one motion
13693 event for each event we process. The way to do this is to
13694 specify <tt/GDK_POINTER_MOTION_HINT_MASK/.
13696 When we specify <tt/GDK_POINTER_MOTION_HINT_MASK/, the server sends
13697 us a motion event the first time the pointer moves after entering
13698 our window, or after a button press or release event. Subsequent
13699 motion events will be suppressed until we explicitly ask for
13700 the position of the pointer using the function:
13703 GdkWindow* gdk_window_get_pointer (GdkWindow *window,
13706 GdkModifierType *mask);
13709 (There is another function, <tt>gtk_widget_get_pointer()</tt> which
13710 has a simpler interface, but turns out not to be very useful, since
13711 it only retrieves the position of the mouse, not whether the buttons
13714 The code to set the events for our window then looks like:
13717 gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
13718 (GtkSignalFunc) expose_event, NULL);
13719 gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
13720 (GtkSignalFunc) configure_event, NULL);
13721 gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
13722 (GtkSignalFunc) motion_notify_event, NULL);
13723 gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
13724 (GtkSignalFunc) button_press_event, NULL);
13726 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
13727 | GDK_LEAVE_NOTIFY_MASK
13728 | GDK_BUTTON_PRESS_MASK
13729 | GDK_POINTER_MOTION_MASK
13730 | GDK_POINTER_MOTION_HINT_MASK);
13733 We'll save the "expose_event" and "configure_event" handlers for
13734 later. The "motion_notify_event" and "button_press_event" handlers
13739 button_press_event (GtkWidget *widget, GdkEventButton *event)
13741 if (event->button == 1 && pixmap != NULL)
13742 draw_brush (widget, event->x, event->y);
13748 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
13751 GdkModifierType state;
13753 if (event->is_hint)
13754 gdk_window_get_pointer (event->window, &x, &y, &state);
13759 state = event->state;
13762 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
13763 draw_brush (widget, x, y);
13769 <!-- ----------------------------------------------------------------- -->
13770 <sect1> The DrawingArea Widget, And Drawing
13772 We now turn to the process of drawing on the screen. The
13773 widget we use for this is the DrawingArea widget. A drawing area
13774 widget is essentially an X window and nothing more. It is a blank
13775 canvas in which we can draw whatever we like. A drawing area
13776 is created using the call:
13779 GtkWidget* gtk_drawing_area_new (void);
13782 A default size for the widget can be specified by calling:
13785 void gtk_drawing_area_size (GtkDrawingArea *darea,
13790 This default size can be overridden, as is true for all widgets,
13791 by calling <tt>gtk_widget_set_usize()</tt>, and that, in turn, can
13792 be overridden if the user manually resizes the the window containing
13795 It should be noted that when we create a DrawingArea widget, we are
13796 <em>completely</em> responsible for drawing the contents. If our
13797 window is obscured then uncovered, we get an exposure event and must
13798 redraw what was previously hidden.
13800 Having to remember everything that was drawn on the screen so we
13801 can properly redraw it can, to say the least, be a nuisance. In
13802 addition, it can be visually distracting if portions of the
13803 window are cleared, then redrawn step by step. The solution to
13804 this problem is to use an offscreen <em>backing pixmap</em>.
13805 Instead of drawing directly to the screen, we draw to an image
13806 stored in server memory but not displayed, then when the image
13807 changes or new portions of the image are displayed, we copy the
13808 relevant portions onto the screen.
13810 To create an offscreen pixmap, we call the function:
13813 GdkPixmap* gdk_pixmap_new (GdkWindow *window,
13819 The <tt>window</tt> parameter specifies a GDK window that this pixmap
13820 takes some of its properties from. <tt>width</tt> and <tt>height</tt>
13821 specify the size of the pixmap. <tt>depth</tt> specifies the <em>color
13822 depth</em>, that is the number of bits per pixel, for the new window.
13823 If the depth is specified as <tt>-1</tt>, it will match the depth
13824 of <tt>window</tt>.
13826 We create the pixmap in our "configure_event" handler. This event
13827 is generated whenever the window changes size, including when it
13828 is originally created.
13831 /* Backing pixmap for drawing area */
13832 static GdkPixmap *pixmap = NULL;
13834 /* Create a new backing pixmap of the appropriate size */
13836 configure_event (GtkWidget *widget, GdkEventConfigure *event)
13839 gdk_pixmap_unref(pixmap);
13841 pixmap = gdk_pixmap_new(widget->window,
13842 widget->allocation.width,
13843 widget->allocation.height,
13845 gdk_draw_rectangle (pixmap,
13846 widget->style->white_gc,
13849 widget->allocation.width,
13850 widget->allocation.height);
13856 The call to <tt>gdk_draw_rectangle()</tt> clears the pixmap
13857 initially to white. We'll say more about that in a moment.
13859 Our exposure event handler then simply copies the relevant portion
13860 of the pixmap onto the screen (we determine the area we need
13861 to redraw by using the event->area field of the exposure event):
13864 /* Redraw the screen from the backing pixmap */
13866 expose_event (GtkWidget *widget, GdkEventExpose *event)
13868 gdk_draw_pixmap(widget->window,
13869 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
13871 event->area.x, event->area.y,
13872 event->area.x, event->area.y,
13873 event->area.width, event->area.height);
13879 We've now seen how to keep the screen up to date with our pixmap, but
13880 how do we actually draw interesting stuff on our pixmap? There are a
13881 large number of calls in GTK's GDK library for drawing on
13882 <em>drawables</em>. A drawable is simply something that can be drawn
13883 upon. It can be a window, a pixmap, or a bitmap (a black and white
13884 image). We've already seen two such calls above,
13885 <tt>gdk_draw_rectangle()</tt> and <tt>gdk_draw_pixmap()</tt>. The
13890 gdk_draw_rectangle ()
13892 gdk_draw_polygon ()
13899 gdk_draw_segments ()
13902 See the reference documentation or the header file
13903 <tt><gdk/gdk.h></tt> for further details on these functions.
13904 These functions all share the same first two arguments. The first
13905 argument is the drawable to draw upon, the second argument is a
13906 <em>graphics context</em> (GC).
13908 A graphics context encapsulates information about things such as
13909 foreground and background color and line width. GDK has a full set of
13910 functions for creating and modifying graphics contexts, but to keep
13911 things simple we'll just use predefined graphics contexts. Each widget
13912 has an associated style. (Which can be modified in a gtkrc file, see
13913 the section GTK's rc file.) This, among other things, stores a number
13914 of graphics contexts. Some examples of accessing these graphics
13918 widget->style->white_gc
13919 widget->style->black_gc
13920 widget->style->fg_gc[GTK_STATE_NORMAL]
13921 widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
13924 The fields <tt>fg_gc</tt>, <tt>bg_gc</tt>, <tt>dark_gc</tt>, and
13925 <tt>light_gc</tt> are indexed by a parameter of type
13926 <tt>GtkStateType</tt> which can take on the values:
13931 GTK_STATE_PRELIGHT,
13932 GTK_STATE_SELECTED,
13933 GTK_STATE_INSENSITIVE
13936 For instance, for <tt/GTK_STATE_SELECTED/ the default foreground
13937 color is white and the default background color, dark blue.
13939 Our function <tt>draw_brush()</tt>, which does the actual drawing
13940 on the screen, is then:
13943 /* Draw a rectangle on the screen */
13945 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
13947 GdkRectangle update_rect;
13949 update_rect.x = x - 5;
13950 update_rect.y = y - 5;
13951 update_rect.width = 10;
13952 update_rect.height = 10;
13953 gdk_draw_rectangle (pixmap,
13954 widget->style->black_gc,
13956 update_rect.x, update_rect.y,
13957 update_rect.width, update_rect.height);
13958 gtk_widget_draw (widget, &update_rect);
13962 After we draw the rectangle representing the brush onto the pixmap,
13963 we call the function:
13966 void gtk_widget_draw (GtkWidget *widget,
13967 GdkRectangle *area);
13970 which notifies X that the area given by the <tt>area</tt> parameter
13971 needs to be updated. X will eventually generate an expose event
13972 (possibly combining the areas passed in several calls to
13973 <tt>gtk_widget_draw()</tt>) which will cause our expose event handler
13974 to copy the relevant portions to the screen.
13976 We have now covered the entire drawing program except for a few
13977 mundane details like creating the main window. The complete
13978 source code is available from the location from which you got
13979 this tutorial, or from:
13981 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
13982 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
13985 <!-- ----------------------------------------------------------------- -->
13986 <sect1> Adding XInput support
13988 It is now possible to buy quite inexpensive input devices such
13989 as drawing tablets, which allow drawing with a much greater
13990 ease of artistic expression than does a mouse. The simplest way
13991 to use such devices is simply as a replacement for the mouse,
13992 but that misses out many of the advantages of these devices,
13996 <item> Pressure sensitivity
13997 <item> Tilt reporting
13998 <item> Sub-pixel positioning
13999 <item> Multiple inputs (for example, a stylus with a point and eraser)
14002 For information about the XInput extension, see the <htmlurl
14003 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
14004 name="XInput-HOWTO">.
14006 If we examine the full definition of, for example, the GdkEventMotion
14007 structure, we see that it has fields to support extended device
14011 struct _GdkEventMotion
14023 GdkInputSource source;
14028 <tt/pressure/ gives the pressure as a floating point number between
14029 0 and 1. <tt/xtilt/ and <tt/ytilt/ can take on values between
14030 -1 and 1, corresponding to the degree of tilt in each direction.
14031 <tt/source/ and <tt/deviceid/ specify the device for which the
14032 event occurred in two different ways. <tt/source/ gives some simple
14033 information about the type of device. It can take the enumeration
14043 <tt/deviceid/ specifies a unique numeric ID for the device. This can
14044 be used to find out further information about the device using the
14045 <tt/gdk_input_list_devices()/ call (see below). The special value
14046 <tt/GDK_CORE_POINTER/ is used for the core pointer device. (Usually
14049 <sect2> Enabling extended device information
14051 To let GTK know about our interest in the extended device information,
14052 we merely have to add a single line to our program:
14055 gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
14058 By giving the value <tt/GDK_EXTENSION_EVENTS_CURSOR/ we say that
14059 we are interested in extension events, but only if we don't have
14060 to draw our own cursor. See the section <ref
14061 id="sec_Further_Sophistications" name="Further Sophistications"> below
14062 for more information about drawing the cursor. We could also
14063 give the values <tt/GDK_EXTENSION_EVENTS_ALL/ if we were willing
14064 to draw our own cursor, or <tt/GDK_EXTENSION_EVENTS_NONE/ to revert
14065 back to the default condition.
14067 This is not completely the end of the story however. By default,
14068 no extension devices are enabled. We need a mechanism to allow
14069 users to enable and configure their extension devices. GTK provides
14070 the InputDialog widget to automate this process. The following
14071 procedure manages an InputDialog widget. It creates the dialog if
14072 it isn't present, and raises it to the top otherwise.
14076 input_dialog_destroy (GtkWidget *w, gpointer data)
14078 *((GtkWidget **)data) = NULL;
14082 create_input_dialog ()
14084 static GtkWidget *inputd = NULL;
14088 inputd = gtk_input_dialog_new();
14090 gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
14091 (GtkSignalFunc)input_dialog_destroy, &inputd);
14092 gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
14094 (GtkSignalFunc)gtk_widget_hide,
14095 GTK_OBJECT(inputd));
14096 gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
14098 gtk_widget_show (inputd);
14102 if (!GTK_WIDGET_MAPPED(inputd))
14103 gtk_widget_show(inputd);
14105 gdk_window_raise(inputd->window);
14110 (You might want to take note of the way we handle this dialog. By
14111 connecting to the "destroy" signal, we make sure that we don't keep a
14112 pointer to dialog around after it is destroyed - that could lead to a
14115 The InputDialog has two buttons "Close" and "Save", which by default
14116 have no actions assigned to them. In the above function we make
14117 "Close" hide the dialog, hide the "Save" button, since we don't
14118 implement saving of XInput options in this program.
14120 <sect2> Using extended device information
14122 Once we've enabled the device, we can just use the extended
14123 device information in the extra fields of the event structures.
14124 In fact, it is always safe to use this information since these
14125 fields will have reasonable default values even when extended
14126 events are not enabled.
14128 Once change we do have to make is to call
14129 <tt/gdk_input_window_get_pointer()/ instead of
14130 <tt/gdk_window_get_pointer/. This is necessary because
14131 <tt/gdk_window_get_pointer/ doesn't return the extended device
14135 void gdk_input_window_get_pointer( GdkWindow *window,
14142 GdkModifierType *mask);
14145 When calling this function, we need to specify the device ID as
14146 well as the window. Usually, we'll get the device ID from the
14147 <tt/deviceid/ field of an event structure. Again, this function
14148 will return reasonable values when extension events are not
14149 enabled. (In this case, <tt/event->deviceid/ will have the value
14150 <tt/GDK_CORE_POINTER/).
14152 So the basic structure of our button-press and motion event handlers
14153 doesn't change much - we just need to add code to deal with the
14154 extended information.
14158 button_press_event (GtkWidget *widget, GdkEventButton *event)
14160 print_button_press (event->deviceid);
14162 if (event->button == 1 && pixmap != NULL)
14163 draw_brush (widget, event->source, event->x, event->y, event->pressure);
14169 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
14173 GdkModifierType state;
14175 if (event->is_hint)
14176 gdk_input_window_get_pointer (event->window, event->deviceid,
14177 &x, &y, &pressure, NULL, NULL, &state);
14182 pressure = event->pressure;
14183 state = event->state;
14186 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
14187 draw_brush (widget, event->source, x, y, pressure);
14193 We also need to do something with the new information. Our new
14194 <tt/draw_brush()/ function draws with a different color for
14195 each <tt/event->source/ and changes the brush size depending
14199 /* Draw a rectangle on the screen, size depending on pressure,
14200 and color on the type of device */
14202 draw_brush (GtkWidget *widget, GdkInputSource source,
14203 gdouble x, gdouble y, gdouble pressure)
14206 GdkRectangle update_rect;
14210 case GDK_SOURCE_MOUSE:
14211 gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
14213 case GDK_SOURCE_PEN:
14214 gc = widget->style->black_gc;
14216 case GDK_SOURCE_ERASER:
14217 gc = widget->style->white_gc;
14220 gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
14223 update_rect.x = x - 10 * pressure;
14224 update_rect.y = y - 10 * pressure;
14225 update_rect.width = 20 * pressure;
14226 update_rect.height = 20 * pressure;
14227 gdk_draw_rectangle (pixmap, gc, TRUE,
14228 update_rect.x, update_rect.y,
14229 update_rect.width, update_rect.height);
14230 gtk_widget_draw (widget, &update_rect);
14234 <sect2> Finding out more about a device
14236 As an example of how to find out more about a device, our program
14237 will print the name of the device that generates each button
14238 press. To find out the name of a device, we call the function:
14241 GList *gdk_input_list_devices (void);
14244 which returns a GList (a linked list type from the GLib library)
14245 of GdkDeviceInfo structures. The GdkDeviceInfo structure is defined
14249 struct _GdkDeviceInfo
14253 GdkInputSource source;
14259 GdkDeviceKey *keys;
14263 Most of these fields are configuration information that you can ignore
14264 unless you are implementing XInput configuration saving. The fieldwe
14265 are interested in here is <tt/name/ which is simply the name that X
14266 assigns to the device. The other field that isn't configuration
14267 information is <tt/has_cursor/. If <tt/has_cursor/ is false, then we
14268 we need to draw our own cursor. But since we've specified
14269 <tt/GDK_EXTENSION_EVENTS_CURSOR/, we don't have to worry about this.
14271 Our <tt/print_button_press()/ function simply iterates through
14272 the returned list until it finds a match, then prints out
14273 the name of the device.
14277 print_button_press (guint32 deviceid)
14281 /* gdk_input_list_devices returns an internal list, so we shouldn't
14282 free it afterwards */
14283 tmp_list = gdk_input_list_devices();
14287 GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
14289 if (info->deviceid == deviceid)
14291 printf("Button press on device '%s'\n", info->name);
14295 tmp_list = tmp_list->next;
14300 That completes the changes to "XInputize" our program. As with
14301 the first version, the complete source is available at the location
14302 from which you got this tutorial, or from:
14304 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
14305 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
14308 <sect2> Further sophistications <label id="sec_Further_Sophistications">
14310 Although our program now supports XInput quite well, it lacks some
14311 features we would want in a full-featured application. First, the user
14312 probably doesn't want to have to configure their device each time they
14313 run the program, so we should allow them to save the device
14314 configuration. This is done by iterating through the return of
14315 <tt/gdk_input_list_devices()/ and writing out the configuration to a
14318 To restore the state next time the program is run, GDK provides
14319 functions to change device configuration:
14322 gdk_input_set_extension_events()
14323 gdk_input_set_source()
14324 gdk_input_set_mode()
14325 gdk_input_set_axes()
14326 gdk_input_set_key()
14329 (The list returned from <tt/gdk_input_list_devices()/ should not be
14330 modified directly.) An example of doing this can be found in the
14331 drawing program gsumi. (Available from <htmlurl
14332 url="http://www.msc.cornell.edu/~otaylor/gsumi/"
14333 name="http://www.msc.cornell.edu/~otaylor/gsumi/">) Eventually, it
14334 would be nice to have a standard way of doing this for all
14335 applications. This probably belongs at a slightly higher level than
14336 GTK, perhaps in the GNOME library.
14338 Another major omission that we have mentioned above is the lack of
14339 cursor drawing. Platforms other than XFree86 currently do not allow
14340 simultaneously using a device as both the core pointer and directly by
14341 an application. See the <url
14342 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
14343 name="XInput-HOWTO"> for more information about this. This means that
14344 applications that want to support the widest audience need to draw
14347 An application that draws its own cursor needs to do two things:
14348 determine if the current device needs a cursor drawn or not, and
14349 determine if the current device is in proximity. (If the current
14350 device is a drawing tablet, it's a nice touch to make the cursor
14351 disappear when the stylus is lifted from the tablet. When the
14352 device is touching the stylus, that is called "in proximity.")
14353 The first is done by searching the device list, as we did
14354 to find out the device name. The second is achieved by selecting
14355 "proximity_out" events. An example of drawing one's own cursor is
14356 found in the "testinput" program found in the GTK distribution.
14358 <!-- ***************************************************************** -->
14359 <sect>Tips For Writing GTK Applications
14360 <!-- ***************************************************************** -->
14362 This section is simply a gathering of wisdom, general style guidelines
14363 and hints to creating good GTK applications. Currently this section
14364 is very short, but I hope it will get longer in future editions of
14367 Use GNU autoconf and automake! They are your friends :) Automake
14368 examines C files, determines how they depend on each other, and
14369 generates a Makefile so the files can be compiled in the correct
14370 order. Autoconf permits automatic configuration of software
14371 installation, handling a large number of system quirks to increase
14372 portability. I am planning to make a quick intro on them here.
14374 When writing C code, use only C comments (beginning with "/*" and
14375 ending with "*/"), and don't use C++-style comments ("//"). Although
14376 many C compilers understand C++ comments, others don't, and the ANSI C
14377 standard does not require that C++-style comments be processed as
14380 <!-- ***************************************************************** -->
14381 <sect>Contributing <label id="sec_Contributing">
14382 <!-- ***************************************************************** -->
14384 This document, like so much other great software out there, was
14385 created for free by volunteers. If you are at all knowledgeable about
14386 any aspect of GTK that does not already have documentation, please
14387 consider contributing to this document.
14389 If you do decide to contribute, please mail your text to Tony Gale,
14390 <tt><htmlurl url="mailto:gale@gtk.org"
14391 name="gale@gtk.org"></tt>. Also, be aware that the entirety of this
14392 document is free, and any addition by you provide must also be
14393 free. That is, people may use any portion of your examples in their
14394 programs, and copies of this document may be distributed at will, etc.
14398 <!-- ***************************************************************** -->
14400 <!-- ***************************************************************** -->
14402 We would like to thank the following for their contributions to this text.
14405 <item>Bawer Dagdeviren, <tt><htmlurl url="mailto:chamele0n@geocities.com"
14406 name="chamele0n@geocities.com"></tt> for the menus tutorial.
14408 <item>Raph Levien, <tt><htmlurl url="mailto:raph@acm.org"
14409 name="raph@acm.org"></tt>
14410 for hello world ala GTK, widget packing, and general all around wisdom.
14411 He's also generously donated a home for this tutorial.
14413 <item>Peter Mattis, <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
14414 name="petm@xcf.berkeley.edu"></tt> for the simplest GTK program..
14415 and the ability to make it :)
14417 <item>Werner Koch <tt><htmlurl url="mailto:werner.koch@guug.de"
14418 name="werner.koch@guug.de"></tt> for converting the original plain text to
14419 SGML, and the widget class hierarchy.
14421 <item>Mark Crichton <tt><htmlurl
14422 url="mailto:crichton@expert.cc.purdue.edu"
14423 name="crichton@expert.cc.purdue.edu"></tt> for the menu factory code,
14424 and the table packing tutorial.
14426 <item>Owen Taylor <tt><htmlurl url="mailto:owt1@cornell.edu"
14427 name="owt1@cornell.edu"></tt> for the EventBox widget section (and the
14428 patch to the distro). He's also responsible for the selections code
14429 and tutorial, as well as the sections on writing your own GTK widgets,
14430 and the example application. Thanks a lot Owen for all you help!
14432 <item>Mark VanderBoom <tt><htmlurl url="mailto:mvboom42@calvin.edu"
14433 name="mvboom42@calvin.edu"></tt> for his wonderful work on the
14434 Notebook, Progress Bar, Dialogs, and File selection widgets. Thanks a
14435 lot Mark! You've been a great help.
14437 <item>Tim Janik <tt><htmlurl url="mailto:timj@gtk.org"
14438 name="timj@psynet.net"></tt> for his great job on the Lists
14439 Widget. His excellent work on automatically extracting the widget tree
14440 and signal information from GTK. Thanks Tim :)
14442 <item>Rajat Datta <tt><htmlurl url="mailto:rajat@ix.netcom.com"
14443 name="rajat@ix.netcom.com"</tt> for the excellent job on the Pixmap
14446 <item>Michael K. Johnson <tt><htmlurl url="mailto:johnsonm@redhat.com"
14447 name="johnsonm@redhat.com"></tt> for info and code for popup menus.
14449 <item>David Huggins-Daines <tt><htmlurl
14450 url="mailto:bn711@freenet.carleton.ca"
14451 name="bn711@freenet.carleton.ca"></tt> for the Range Widgets and Tree
14454 <item>Stefan Mars <tt><htmlurl url="mailto:mars@lysator.liu.se"
14455 name="mars@lysator.liu.se"></tt> for the CList section.
14457 <item>David A. Wheeler <tt><htmlurl url="mailto:dwheeler@ida.org"
14458 name="dwheeler@ida.org"></tt> for portions of the text on GLib
14459 and various tutorial fixups and improvements.
14460 The GLib text was in turn based on material developed by Damon Chaplin
14461 <tt><htmlurl url="mailto:DAChaplin@msn.com" name="DAChaplin@msn.com"></tt>
14463 <item>David King for style checking the entire document.
14466 And to all of you who commented on and helped refine this document.
14470 <!-- ***************************************************************** -->
14471 <sect> Tutorial Copyright and Permissions Notice
14472 <!-- ***************************************************************** -->
14475 The GTK Tutorial is Copyright (C) 1997 Ian Main.
14477 Copyright (C) 1998-1999 Tony Gale.
14479 Permission is granted to make and distribute verbatim copies of this
14480 manual provided the copyright notice and this permission notice are
14481 preserved on all copies.
14483 Permission is granted to copy and distribute modified versions of
14484 this document under the conditions for verbatim copying, provided that
14485 this copyright notice is included exactly as in the original,
14486 and that the entire resulting derived work is distributed under
14487 the terms of a permission notice identical to this one.
14488 <P>Permission is granted to copy and distribute translations of this
14489 document into another language, under the above conditions for modified
14492 If you are intending to incorporate this document into a published
14493 work, please contact the maintainer, and we will make an effort
14494 to ensure that you have the most up to date information available.
14496 There is no guarantee that this document lives up to its intended
14497 purpose. This is simply provided as a free resource. As such,
14498 the authors and maintainers of the information provided within can
14499 not make any guarantee that the information is even accurate.
14501 <!-- ***************************************************************** -->
14503 <!-- ***************************************************************** -->
14505 <!-- ***************************************************************** -->
14506 <sect> GTK Signals <label id="sec_GTK_Signals">
14507 <!-- ***************************************************************** -->
14509 As GTK is an object oriented widget set, it has a hierarchy of
14510 inheritance. This inheritance mechanism applies for
14511 signals. Therefore, you should refer to the widget hierarchy tree when
14512 using the signals listed in this section.
14514 <!-- ----------------------------------------------------------------- -->
14516 <!-- ----------------------------------------------------------------- -->
14519 void GtkObject::destroy (GtkObject *,
14523 <!-- ----------------------------------------------------------------- -->
14525 <!-- ----------------------------------------------------------------- -->
14529 void GtkWidget::show (GtkWidget *,
14531 void GtkWidget::hide (GtkWidget *,
14533 void GtkWidget::map (GtkWidget *,
14535 void GtkWidget::unmap (GtkWidget *,
14537 void GtkWidget::realize (GtkWidget *,
14539 void GtkWidget::unrealize (GtkWidget *,
14541 void GtkWidget::draw (GtkWidget *,
14544 void GtkWidget::draw-focus (GtkWidget *,
14546 void GtkWidget::draw-default (GtkWidget *,
14548 void GtkWidget::size-request (GtkWidget *,
14551 void GtkWidget::size-allocate (GtkWidget *,
14554 void GtkWidget::state-changed (GtkWidget *,
14557 void GtkWidget::parent-set (GtkWidget *,
14560 void GtkWidget::style-set (GtkWidget *,
14563 void GtkWidget::add-accelerator (GtkWidget *,
14570 void GtkWidget::remove-accelerator (GtkWidget *,
14575 gboolean GtkWidget::event (GtkWidget *,
14578 gboolean GtkWidget::button-press-event (GtkWidget *,
14581 gboolean GtkWidget::button-release-event (GtkWidget *,
14584 gboolean GtkWidget::motion-notify-event (GtkWidget *,
14587 gboolean GtkWidget::delete-event (GtkWidget *,
14590 gboolean GtkWidget::destroy-event (GtkWidget *,
14593 gboolean GtkWidget::expose-event (GtkWidget *,
14596 gboolean GtkWidget::key-press-event (GtkWidget *,
14599 gboolean GtkWidget::key-release-event (GtkWidget *,
14602 gboolean GtkWidget::enter-notify-event (GtkWidget *,
14605 gboolean GtkWidget::leave-notify-event (GtkWidget *,
14608 gboolean GtkWidget::configure-event (GtkWidget *,
14611 gboolean GtkWidget::focus-in-event (GtkWidget *,
14614 gboolean GtkWidget::focus-out-event (GtkWidget *,
14617 gboolean GtkWidget::map-event (GtkWidget *,
14620 gboolean GtkWidget::unmap-event (GtkWidget *,
14623 gboolean GtkWidget::property-notify-event (GtkWidget *,
14626 gboolean GtkWidget::selection-clear-event (GtkWidget *,
14629 gboolean GtkWidget::selection-request-event (GtkWidget *,
14632 gboolean GtkWidget::selection-notify-event (GtkWidget *,
14635 void GtkWidget::selection-get (GtkWidget *,
14636 GtkSelectionData *,
14639 void GtkWidget::selection-received (GtkWidget *,
14640 GtkSelectionData *,
14643 gboolean GtkWidget::proximity-in-event (GtkWidget *,
14646 gboolean GtkWidget::proximity-out-event (GtkWidget *,
14649 void GtkWidget::drag-begin (GtkWidget *,
14652 void GtkWidget::drag-end (GtkWidget *,
14655 void GtkWidget::drag-data-delete (GtkWidget *,
14658 void GtkWidget::drag-leave (GtkWidget *,
14662 gboolean GtkWidget::drag-motion (GtkWidget *,
14668 gboolean GtkWidget::drag-drop (GtkWidget *,
14674 void GtkWidget::drag-data-get (GtkWidget *,
14676 GtkSelectionData *,
14680 void GtkWidget::drag-data-received (GtkWidget *,
14684 GtkSelectionData *,
14688 gboolean GtkWidget::client-event (GtkWidget *,
14691 gboolean GtkWidget::no-expose-event (GtkWidget *,
14694 gboolean GtkWidget::visibility-notify-event (GtkWidget *,
14697 void GtkWidget::debug-msg (GtkWidget *,
14702 <!-- ----------------------------------------------------------------- -->
14704 <!-- ----------------------------------------------------------------- -->
14707 void GtkData::disconnect (GtkData *,
14711 <!-- ----------------------------------------------------------------- -->
14712 <sect1>GtkContainer
14713 <!-- ----------------------------------------------------------------- -->
14716 void GtkContainer::add (GtkContainer *,
14719 void GtkContainer::remove (GtkContainer *,
14722 void GtkContainer::check-resize (GtkContainer *,
14724 GtkDirectionType GtkContainer::focus (GtkContainer *,
14727 void GtkContainer::set-focus-child (GtkContainer *,
14732 <!-- ----------------------------------------------------------------- -->
14734 <!-- ----------------------------------------------------------------- -->
14737 void GtkCalendar::month-changed (GtkCalendar *,
14739 void GtkCalendar::day-selected (GtkCalendar *,
14741 void GtkCalendar::day-selected-double-click (GtkCalendar *,
14743 void GtkCalendar::prev-month (GtkCalendar *,
14745 void GtkCalendar::next-month (GtkCalendar *,
14747 void GtkCalendar::prev-year (GtkCalendar *,
14749 void GtkCalendar::next-year (GtkCalendar *,
14753 <!-- ----------------------------------------------------------------- -->
14755 <!-- ----------------------------------------------------------------- -->
14758 void GtkEditable::changed (GtkEditable *,
14760 void GtkEditable::insert-text (GtkEditable *,
14765 void GtkEditable::delete-text (GtkEditable *,
14769 void GtkEditable::activate (GtkEditable *,
14771 void GtkEditable::set-editable (GtkEditable *,
14774 void GtkEditable::move-cursor (GtkEditable *,
14778 void GtkEditable::move-word (GtkEditable *,
14781 void GtkEditable::move-page (GtkEditable *,
14785 void GtkEditable::move-to-row (GtkEditable *,
14788 void GtkEditable::move-to-column (GtkEditable *,
14791 void GtkEditable::kill-char (GtkEditable *,
14794 void GtkEditable::kill-word (GtkEditable *,
14797 void GtkEditable::kill-line (GtkEditable *,
14800 void GtkEditable::cut-clipboard (GtkEditable *,
14802 void GtkEditable::copy-clipboard (GtkEditable *,
14804 void GtkEditable::paste-clipboard (GtkEditable *,
14808 <!-- ----------------------------------------------------------------- -->
14809 <sect1>GtkTipsQuery
14810 <!-- ----------------------------------------------------------------- -->
14813 void GtkTipsQuery::start-query (GtkTipsQuery *,
14815 void GtkTipsQuery::stop-query (GtkTipsQuery *,
14817 void GtkTipsQuery::widget-entered (GtkTipsQuery *,
14822 gboolean GtkTipsQuery::widget-selected (GtkTipsQuery *,
14830 <!-- ----------------------------------------------------------------- -->
14832 <!-- ----------------------------------------------------------------- -->
14835 void GtkCList::select-row (GtkCList *,
14840 void GtkCList::unselect-row (GtkCList *,
14845 void GtkCList::row-move (GtkCList *,
14849 void GtkCList::click-column (GtkCList *,
14852 void GtkCList::resize-column (GtkCList *,
14856 void GtkCList::toggle-focus-row (GtkCList *,
14858 void GtkCList::select-all (GtkCList *,
14860 void GtkCList::unselect-all (GtkCList *,
14862 void GtkCList::undo-selection (GtkCList *,
14864 void GtkCList::start-selection (GtkCList *,
14866 void GtkCList::end-selection (GtkCList *,
14868 void GtkCList::toggle-add-mode (GtkCList *,
14870 void GtkCList::extend-selection (GtkCList *,
14875 void GtkCList::scroll-vertical (GtkCList *,
14879 void GtkCList::scroll-horizontal (GtkCList *,
14883 void GtkCList::abort-column-resize (GtkCList *,
14887 <!-- ----------------------------------------------------------------- -->
14889 <!-- ----------------------------------------------------------------- -->
14892 void GtkNotebook::switch-page (GtkNotebook *,
14899 <!-- ----------------------------------------------------------------- -->
14901 <!-- ----------------------------------------------------------------- -->
14904 void GtkList::selection-changed (GtkList *,
14906 void GtkList::select-child (GtkList *,
14909 void GtkList::unselect-child (GtkList *,
14914 <!-- ----------------------------------------------------------------- -->
14915 <sect1>GtkMenuShell
14916 <!-- ----------------------------------------------------------------- -->
14919 void GtkMenuShell::deactivate (GtkMenuShell *,
14921 void GtkMenuShell::selection-done (GtkMenuShell *,
14923 void GtkMenuShell::move-current (GtkMenuShell *,
14924 GtkMenuDirectionType,
14926 void GtkMenuShell::activate-current (GtkMenuShell *,
14929 void GtkMenuShell::cancel (GtkMenuShell *,
14933 <!-- ----------------------------------------------------------------- -->
14935 <!-- ----------------------------------------------------------------- -->
14938 void GtkToolbar::orientation-changed (GtkToolbar *,
14941 void GtkToolbar::style-changed (GtkToolbar *,
14946 <!-- ----------------------------------------------------------------- -->
14948 <!-- ----------------------------------------------------------------- -->
14951 void GtkTree::selection-changed (GtkTree *,
14953 void GtkTree::select-child (GtkTree *,
14956 void GtkTree::unselect-child (GtkTree *,
14961 <!-- ----------------------------------------------------------------- -->
14963 <!-- ----------------------------------------------------------------- -->
14966 void GtkButton::pressed (GtkButton *,
14968 void GtkButton::released (GtkButton *,
14970 void GtkButton::clicked (GtkButton *,
14972 void GtkButton::enter (GtkButton *,
14974 void GtkButton::leave (GtkButton *,
14978 <!-- ----------------------------------------------------------------- -->
14980 <!-- ----------------------------------------------------------------- -->
14983 void GtkItem::select (GtkItem *,
14985 void GtkItem::deselect (GtkItem *,
14987 void GtkItem::toggle (GtkItem *,
14991 <!-- ----------------------------------------------------------------- -->
14993 <!-- ----------------------------------------------------------------- -->
14996 void GtkWindow::set-focus (GtkWindow *,
15001 <!-- ----------------------------------------------------------------- -->
15002 <sect1>GtkHandleBox
15003 <!-- ----------------------------------------------------------------- -->
15006 void GtkHandleBox::child-attached (GtkHandleBox *,
15009 void GtkHandleBox::child-detached (GtkHandleBox *,
15014 <!-- ----------------------------------------------------------------- -->
15015 <sect1>GtkToggleButton
15016 <!-- ----------------------------------------------------------------- -->
15019 void GtkToggleButton::toggled (GtkToggleButton *,
15024 <!-- ----------------------------------------------------------------- -->
15026 <!-- ----------------------------------------------------------------- -->
15029 void GtkMenuItem::activate (GtkMenuItem *,
15031 void GtkMenuItem::activate-item (GtkMenuItem *,
15035 <!-- ----------------------------------------------------------------- -->
15037 <!-- ----------------------------------------------------------------- -->
15040 void GtkListItem::toggle-focus-row (GtkListItem *,
15042 void GtkListItem::select-all (GtkListItem *,
15044 void GtkListItem::unselect-all (GtkListItem *,
15046 void GtkListItem::undo-selection (GtkListItem *,
15048 void GtkListItem::start-selection (GtkListItem *,
15050 void GtkListItem::end-selection (GtkListItem *,
15052 void GtkListItem::toggle-add-mode (GtkListItem *,
15054 void GtkListItem::extend-selection (GtkListItem *,
15059 void GtkListItem::scroll-vertical (GtkListItem *,
15063 void GtkListItem::scroll-horizontal (GtkListItem *,
15069 <!-- ----------------------------------------------------------------- -->
15071 <!-- ----------------------------------------------------------------- -->
15074 void GtkTreeItem::collapse (GtkTreeItem *,
15076 void GtkTreeItem::expand (GtkTreeItem *,
15080 <!-- ----------------------------------------------------------------- -->
15081 <sect1>GtkCheckMenuItem
15082 <!-- ----------------------------------------------------------------- -->
15085 void GtkCheckMenuItem::toggled (GtkCheckMenuItem *,
15089 <!-- ----------------------------------------------------------------- -->
15090 <sect1>GtkInputDialog
15091 <!-- ----------------------------------------------------------------- -->
15094 void GtkInputDialog::enable-device (GtkInputDialog *,
15097 void GtkInputDialog::disable-device (GtkInputDialog *,
15102 <!-- ----------------------------------------------------------------- -->
15103 <sect1>GtkColorSelection
15104 <!-- ----------------------------------------------------------------- -->
15107 void GtkColorSelection::color-changed (GtkColorSelection *,
15111 <!-- ----------------------------------------------------------------- -->
15112 <sect1>GtkStatusBar
15113 <!-- ----------------------------------------------------------------- -->
15116 void GtkStatusbar::text-pushed (GtkStatusbar *,
15120 void GtkStatusbar::text-popped (GtkStatusbar *,
15126 <!-- ----------------------------------------------------------------- -->
15128 <!-- ----------------------------------------------------------------- -->
15131 void GtkCTree::tree-select-row (GtkCTree *,
15135 void GtkCTree::tree-unselect-row (GtkCTree *,
15139 void GtkCTree::tree-expand (GtkCTree *,
15142 void GtkCTree::tree-collapse (GtkCTree *,
15145 void GtkCTree::tree-move (GtkCTree *,
15150 void GtkCTree::change-focus-row-expansion (GtkCTree *,
15151 GtkCTreeExpansionType,
15155 <!-- ----------------------------------------------------------------- -->
15157 <!-- ----------------------------------------------------------------- -->
15160 void GtkCurve::curve-type-changed (GtkCurve *,
15164 <!-- ----------------------------------------------------------------- -->
15165 <sect1>GtkAdjustment
15166 <!-- ----------------------------------------------------------------- -->
15169 void GtkAdjustment::changed (GtkAdjustment *,
15171 void GtkAdjustment::value-changed (GtkAdjustment *,
15175 <!-- ***************************************************************** -->
15176 <sect> GDK Event Types<label id="sec_GDK_Event_Types">
15177 <!-- ***************************************************************** -->
15179 The following data types are passed into event handlers by GTK+. For
15180 each data type listed, the signals that use this data type are listed.
15185 <item>drag_end_event
15188 <item> GdkEventType
15193 <item>destroy_event
15196 <item>no_expose_event
15199 <item> GdkEventExpose
15204 <item> GdkEventNoExpose
15206 <item> GdkEventVisibility
15208 <item> GdkEventMotion
15210 <item>motion_notify_event
15213 <item> GdkEventButton
15215 <item>button_press_event
15216 <item>button_release_event
15221 <item>key_press_event
15222 <item>key_release_event
15225 <item> GdkEventCrossing
15227 <item>enter_notify_event
15228 <item>leave_notify_event
15231 <item> GdkEventFocus
15233 <item>focus_in_event
15234 <item>focus_out_event
15237 <item> GdkEventConfigure
15239 <item>configure_event
15242 <item> GdkEventProperty
15244 <item>property_notify_event
15247 <item> GdkEventSelection
15249 <item>selection_clear_event
15250 <item>selection_request_event
15251 <item>selection_notify_event
15254 <item> GdkEventProximity
15256 <item>proximity_in_event
15257 <item>proximity_out_event
15260 <item> GdkEventDragBegin
15262 <item>drag_begin_event
15265 <item> GdkEventDragRequest
15267 <item>drag_request_event
15270 <item> GdkEventDropEnter
15272 <item>drop_enter_event
15275 <item> GdkEventDropLeave
15277 <item>drop_leave_event
15280 <item> GdkEventDropDataAvailable
15282 <item>drop_data_available_event
15285 <item> GdkEventClient
15290 <item> GdkEventOther
15296 The data type <tt/GdkEventType/ is a special data type that is used by
15297 all the other data types as an indicator of the data type being passed
15298 to the signal handler. As you will see below, each of the event data
15299 structures has a member of this type. It is defined as an enumeration
15309 GDK_MOTION_NOTIFY = 3,
15310 GDK_BUTTON_PRESS = 4,
15311 GDK_2BUTTON_PRESS = 5,
15312 GDK_3BUTTON_PRESS = 6,
15313 GDK_BUTTON_RELEASE = 7,
15315 GDK_KEY_RELEASE = 9,
15316 GDK_ENTER_NOTIFY = 10,
15317 GDK_LEAVE_NOTIFY = 11,
15318 GDK_FOCUS_CHANGE = 12,
15319 GDK_CONFIGURE = 13,
15322 GDK_PROPERTY_NOTIFY = 16,
15323 GDK_SELECTION_CLEAR = 17,
15324 GDK_SELECTION_REQUEST = 18,
15325 GDK_SELECTION_NOTIFY = 19,
15326 GDK_PROXIMITY_IN = 20,
15327 GDK_PROXIMITY_OUT = 21,
15328 GDK_DRAG_BEGIN = 22,
15329 GDK_DRAG_REQUEST = 23,
15330 GDK_DROP_ENTER = 24,
15331 GDK_DROP_LEAVE = 25,
15332 GDK_DROP_DATA_AVAIL = 26,
15333 GDK_CLIENT_EVENT = 27,
15334 GDK_VISIBILITY_NOTIFY = 28,
15335 GDK_NO_EXPOSE = 29,
15336 GDK_OTHER_EVENT = 9999 /* Deprecated, use filters instead */
15340 The other event type that is different from the others is
15341 <tt/GdkEvent/ itself. This is a union of all the other
15342 data types, which allows it to be cast to a specific
15343 event data type within a signal handler.
15345 <!-- Just a big list for now, needs expanding upon - TRG -->
15346 So, the event data types are defined as follows:
15349 struct _GdkEventAny
15356 struct _GdkEventExpose
15362 gint count; /* If non-zero, how many more events follow. */
15365 struct _GdkEventNoExpose
15370 /* XXX: does anyone need the X major_code or minor_code fields? */
15373 struct _GdkEventVisibility
15378 GdkVisibilityState state;
15381 struct _GdkEventMotion
15394 GdkInputSource source;
15396 gdouble x_root, y_root;
15399 struct _GdkEventButton
15412 GdkInputSource source;
15414 gdouble x_root, y_root;
15417 struct _GdkEventKey
15429 struct _GdkEventCrossing
15434 GdkWindow *subwindow;
15435 GdkNotifyType detail;
15438 struct _GdkEventFocus
15446 struct _GdkEventConfigure
15456 struct _GdkEventProperty
15466 struct _GdkEventSelection
15478 /* This event type will be used pretty rarely. It only is important
15479 for XInput aware programs that are drawing their own cursor */
15481 struct _GdkEventProximity
15487 GdkInputSource source;
15491 struct _GdkEventDragRequest
15499 guint protocol_version:4;
15501 guint willaccept:1;
15502 guint delete_data:1; /* Do *not* delete if link is sent, only
15509 guint8 isdrop; /* This gdk event can be generated by a couple of
15510 X events - this lets the app know whether the
15511 drop really occurred or we just set the data */
15513 GdkPoint drop_coords;
15518 struct _GdkEventDragBegin
15525 guint protocol_version:4;
15532 struct _GdkEventDropEnter
15540 guint protocol_version:4;
15542 guint extended_typelist:1;
15549 struct _GdkEventDropLeave
15557 guint protocol_version:4;
15564 struct _GdkEventDropDataAvailable
15572 guint protocol_version:4;
15578 gchar *data_type; /* MIME type */
15579 gulong data_numbytes;
15585 struct _GdkEventClient
15590 GdkAtom message_type;
15591 gushort data_format;
15599 struct _GdkEventOther
15608 <!-- ***************************************************************** -->
15609 <sect> Code Examples
15610 <!-- ***************************************************************** -->
15612 Below are the code examples that are used in the above text
15613 which are not included in complete form elsewhere.
15615 <!-- ----------------------------------------------------------------- -->
15617 <!-- ----------------------------------------------------------------- -->
15621 /* example-start tictactoe tictactoe.h */
15623 /* GTK - The GIMP Toolkit
15624 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15626 * This library is free software; you can redistribute it and/or
15627 * modify it under the terms of the GNU Library General Public
15628 * License as published by the Free Software Foundation; either
15629 * version 2 of the License, or (at your option) any later version.
15631 * This library is distributed in the hope that it will be useful,
15632 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15633 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15634 * Library General Public License for more details.
15636 * You should have received a copy of the GNU Library General Public
15637 * License along with this library; if not, write to the
15638 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15639 * Boston, MA 02111-1307, USA.
15641 #ifndef __TICTACTOE_H__
15642 #define __TICTACTOE_H__
15645 #include <gdk/gdk.h>
15646 #include <gtk/gtkvbox.h>
15651 #endif /* __cplusplus */
15653 #define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
15654 #define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
15655 #define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
15658 typedef struct _Tictactoe Tictactoe;
15659 typedef struct _TictactoeClass TictactoeClass;
15665 GtkWidget *buttons[3][3];
15668 struct _TictactoeClass
15670 GtkVBoxClass parent_class;
15672 void (* tictactoe) (Tictactoe *ttt);
15675 guint tictactoe_get_type (void);
15676 GtkWidget* tictactoe_new (void);
15677 void tictactoe_clear (Tictactoe *ttt);
15681 #endif /* __cplusplus */
15683 #endif /* __TICTACTOE_H__ */
15688 <!-- ----------------------------------------------------------------- -->
15692 /* example-start tictactoe tictactoe.c */
15694 /* GTK - The GIMP Toolkit
15695 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15697 * This library is free software; you can redistribute it and/or
15698 * modify it under the terms of the GNU Library General Public
15699 * License as published by the Free Software Foundation; either
15700 * version 2 of the License, or (at your option) any later version.
15702 * This library is distributed in the hope that it will be useful,
15703 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15704 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15705 * Library General Public License for more details.
15707 * You should have received a copy of the GNU Library General Public
15708 * License along with this library; if not, write to the
15709 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15710 * Boston, MA 02111-1307, USA.
15712 #include "gtk/gtksignal.h"
15713 #include "gtk/gtktable.h"
15714 #include "gtk/gtktogglebutton.h"
15715 #include "tictactoe.h"
15722 static void tictactoe_class_init (TictactoeClass *klass);
15723 static void tictactoe_init (Tictactoe *ttt);
15724 static void tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt);
15726 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
15729 tictactoe_get_type ()
15731 static guint ttt_type = 0;
15735 GtkTypeInfo ttt_info =
15738 sizeof (Tictactoe),
15739 sizeof (TictactoeClass),
15740 (GtkClassInitFunc) tictactoe_class_init,
15741 (GtkObjectInitFunc) tictactoe_init,
15742 (GtkArgSetFunc) NULL,
15743 (GtkArgGetFunc) NULL
15746 ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
15753 tictactoe_class_init (TictactoeClass *class)
15755 GtkObjectClass *object_class;
15757 object_class = (GtkObjectClass*) class;
15759 tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
15761 object_class->type,
15762 GTK_SIGNAL_OFFSET (TictactoeClass,
15764 gtk_signal_default_marshaller,
15768 gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
15770 class->tictactoe = NULL;
15774 tictactoe_init (Tictactoe *ttt)
15779 table = gtk_table_new (3, 3, TRUE);
15780 gtk_container_add (GTK_CONTAINER(ttt), table);
15781 gtk_widget_show (table);
15786 ttt->buttons[i][j] = gtk_toggle_button_new ();
15787 gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
15789 gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
15790 GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
15791 gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
15792 gtk_widget_show (ttt->buttons[i][j]);
15799 return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
15803 tictactoe_clear (Tictactoe *ttt)
15810 gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
15811 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
15813 gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
15818 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
15822 static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
15823 { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
15824 { 0, 1, 2 }, { 0, 1, 2 } };
15825 static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
15826 { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
15827 { 0, 1, 2 }, { 2, 1, 0 } };
15829 int success, found;
15831 for (k=0; k<8; k++)
15838 success = success &&
15839 GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
15841 ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
15844 if (success && found)
15846 gtk_signal_emit (GTK_OBJECT (ttt),
15847 tictactoe_signals[TICTACTOE_SIGNAL]);
15856 <!-- ----------------------------------------------------------------- -->
15860 /* example-start tictactoe ttt_test.c */
15862 #include <gtk/gtk.h>
15863 #include "tictactoe.h"
15866 win (GtkWidget *widget, gpointer data)
15868 g_print ("Yay!\n");
15869 tictactoe_clear (TICTACTOE (widget));
15873 main (int argc, char *argv[])
15878 gtk_init (&argc, &argv);
15880 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
15882 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
15884 gtk_signal_connect (GTK_OBJECT (window), "destroy",
15885 GTK_SIGNAL_FUNC (gtk_exit), NULL);
15887 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
15889 ttt = tictactoe_new ();
15891 gtk_container_add (GTK_CONTAINER (window), ttt);
15892 gtk_widget_show (ttt);
15894 gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
15895 GTK_SIGNAL_FUNC (win), NULL);
15897 gtk_widget_show (window);
15907 <!-- ----------------------------------------------------------------- -->
15910 <!-- ----------------------------------------------------------------- -->
15914 /* example-start gtkdial gtkdial.h */
15916 /* GTK - The GIMP Toolkit
15917 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15919 * This library is free software; you can redistribute it and/or
15920 * modify it under the terms of the GNU Library General Public
15921 * License as published by the Free Software Foundation; either
15922 * version 2 of the License, or (at your option) any later version.
15924 * This library is distributed in the hope that it will be useful,
15925 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15926 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15927 * Library General Public License for more details.
15929 * You should have received a copy of the GNU Library General Public
15930 * License along with this library; if not, write to the
15931 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15932 * Boston, MA 02111-1307, USA.
15934 #ifndef __GTK_DIAL_H__
15935 #define __GTK_DIAL_H__
15938 #include <gdk/gdk.h>
15939 #include <gtk/gtkadjustment.h>
15940 #include <gtk/gtkwidget.h>
15945 #endif /* __cplusplus */
15948 #define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
15949 #define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
15950 #define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
15953 typedef struct _GtkDial GtkDial;
15954 typedef struct _GtkDialClass GtkDialClass;
15960 /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
15963 /* Button currently pressed or 0 if none */
15966 /* Dimensions of dial components */
15968 gint pointer_width;
15970 /* ID of update timer, or 0 if none */
15973 /* Current angle */
15976 /* Old values from adjustment stored so we know when something changes */
15981 /* The adjustment object that stores the data for this dial */
15982 GtkAdjustment *adjustment;
15985 struct _GtkDialClass
15987 GtkWidgetClass parent_class;
15991 GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
15992 guint gtk_dial_get_type (void);
15993 GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
15994 void gtk_dial_set_update_policy (GtkDial *dial,
15995 GtkUpdateType policy);
15997 void gtk_dial_set_adjustment (GtkDial *dial,
15998 GtkAdjustment *adjustment);
16001 #endif /* __cplusplus */
16004 #endif /* __GTK_DIAL_H__ */
16008 <!-- ----------------------------------------------------------------- -->
16012 /* example-start gtkdial gtkdial.c */
16014 /* GTK - The GIMP Toolkit
16015 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
16017 * This library is free software; you can redistribute it and/or
16018 * modify it under the terms of the GNU Library General Public
16019 * License as published by the Free Software Foundation; either
16020 * version 2 of the License, or (at your option) any later version.
16022 * This library is distributed in the hope that it will be useful,
16023 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16025 * Library General Public License for more details.
16027 * You should have received a copy of the GNU Library General Public
16028 * License along with this library; if not, write to the
16029 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16030 * Boston, MA 02111-1307, USA.
16034 #include <gtk/gtkmain.h>
16035 #include <gtk/gtksignal.h>
16037 #include "gtkdial.h"
16039 #define SCROLL_DELAY_LENGTH 300
16040 #define DIAL_DEFAULT_SIZE 100
16042 /* Forward declarations */
16044 static void gtk_dial_class_init (GtkDialClass *klass);
16045 static void gtk_dial_init (GtkDial *dial);
16046 static void gtk_dial_destroy (GtkObject *object);
16047 static void gtk_dial_realize (GtkWidget *widget);
16048 static void gtk_dial_size_request (GtkWidget *widget,
16049 GtkRequisition *requisition);
16050 static void gtk_dial_size_allocate (GtkWidget *widget,
16051 GtkAllocation *allocation);
16052 static gint gtk_dial_expose (GtkWidget *widget,
16053 GdkEventExpose *event);
16054 static gint gtk_dial_button_press (GtkWidget *widget,
16055 GdkEventButton *event);
16056 static gint gtk_dial_button_release (GtkWidget *widget,
16057 GdkEventButton *event);
16058 static gint gtk_dial_motion_notify (GtkWidget *widget,
16059 GdkEventMotion *event);
16060 static gint gtk_dial_timer (GtkDial *dial);
16062 static void gtk_dial_update_mouse (GtkDial *dial, gint x, gint y);
16063 static void gtk_dial_update (GtkDial *dial);
16064 static void gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
16066 static void gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
16071 static GtkWidgetClass *parent_class = NULL;
16074 gtk_dial_get_type ()
16076 static guint dial_type = 0;
16080 GtkTypeInfo dial_info =
16084 sizeof (GtkDialClass),
16085 (GtkClassInitFunc) gtk_dial_class_init,
16086 (GtkObjectInitFunc) gtk_dial_init,
16087 (GtkArgSetFunc) NULL,
16088 (GtkArgGetFunc) NULL,
16091 dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info);
16098 gtk_dial_class_init (GtkDialClass *class)
16100 GtkObjectClass *object_class;
16101 GtkWidgetClass *widget_class;
16103 object_class = (GtkObjectClass*) class;
16104 widget_class = (GtkWidgetClass*) class;
16106 parent_class = gtk_type_class (gtk_widget_get_type ());
16108 object_class->destroy = gtk_dial_destroy;
16110 widget_class->realize = gtk_dial_realize;
16111 widget_class->expose_event = gtk_dial_expose;
16112 widget_class->size_request = gtk_dial_size_request;
16113 widget_class->size_allocate = gtk_dial_size_allocate;
16114 widget_class->button_press_event = gtk_dial_button_press;
16115 widget_class->button_release_event = gtk_dial_button_release;
16116 widget_class->motion_notify_event = gtk_dial_motion_notify;
16120 gtk_dial_init (GtkDial *dial)
16123 dial->policy = GTK_UPDATE_CONTINUOUS;
16126 dial->pointer_width = 0;
16128 dial->old_value = 0.0;
16129 dial->old_lower = 0.0;
16130 dial->old_upper = 0.0;
16131 dial->adjustment = NULL;
16135 gtk_dial_new (GtkAdjustment *adjustment)
16139 dial = gtk_type_new (gtk_dial_get_type ());
16142 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0,
16145 gtk_dial_set_adjustment (dial, adjustment);
16147 return GTK_WIDGET (dial);
16151 gtk_dial_destroy (GtkObject *object)
16155 g_return_if_fail (object != NULL);
16156 g_return_if_fail (GTK_IS_DIAL (object));
16158 dial = GTK_DIAL (object);
16160 if (dial->adjustment)
16161 gtk_object_unref (GTK_OBJECT (dial->adjustment));
16163 if (GTK_OBJECT_CLASS (parent_class)->destroy)
16164 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
16168 gtk_dial_get_adjustment (GtkDial *dial)
16170 g_return_val_if_fail (dial != NULL, NULL);
16171 g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
16173 return dial->adjustment;
16177 gtk_dial_set_update_policy (GtkDial *dial,
16178 GtkUpdateType policy)
16180 g_return_if_fail (dial != NULL);
16181 g_return_if_fail (GTK_IS_DIAL (dial));
16183 dial->policy = policy;
16187 gtk_dial_set_adjustment (GtkDial *dial,
16188 GtkAdjustment *adjustment)
16190 g_return_if_fail (dial != NULL);
16191 g_return_if_fail (GTK_IS_DIAL (dial));
16193 if (dial->adjustment)
16195 gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment),
16197 gtk_object_unref (GTK_OBJECT (dial->adjustment));
16200 dial->adjustment = adjustment;
16201 gtk_object_ref (GTK_OBJECT (dial->adjustment));
16203 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
16204 (GtkSignalFunc) gtk_dial_adjustment_changed,
16206 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
16207 (GtkSignalFunc) gtk_dial_adjustment_value_changed,
16210 dial->old_value = adjustment->value;
16211 dial->old_lower = adjustment->lower;
16212 dial->old_upper = adjustment->upper;
16214 gtk_dial_update (dial);
16218 gtk_dial_realize (GtkWidget *widget)
16221 GdkWindowAttr attributes;
16222 gint attributes_mask;
16224 g_return_if_fail (widget != NULL);
16225 g_return_if_fail (GTK_IS_DIAL (widget));
16227 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
16228 dial = GTK_DIAL (widget);
16230 attributes.x = widget->allocation.x;
16231 attributes.y = widget->allocation.y;
16232 attributes.width = widget->allocation.width;
16233 attributes.height = widget->allocation.height;
16234 attributes.wclass = GDK_INPUT_OUTPUT;
16235 attributes.window_type = GDK_WINDOW_CHILD;
16236 attributes.event_mask = gtk_widget_get_events (widget) |
16237 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
16238 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
16239 GDK_POINTER_MOTION_HINT_MASK;
16240 attributes.visual = gtk_widget_get_visual (widget);
16241 attributes.colormap = gtk_widget_get_colormap (widget);
16243 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
16244 widget->window = gdk_window_new (widget->parent->window,
16248 widget->style = gtk_style_attach (widget->style, widget->window);
16250 gdk_window_set_user_data (widget->window, widget);
16252 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
16256 gtk_dial_size_request (GtkWidget *widget,
16257 GtkRequisition *requisition)
16259 requisition->width = DIAL_DEFAULT_SIZE;
16260 requisition->height = DIAL_DEFAULT_SIZE;
16264 gtk_dial_size_allocate (GtkWidget *widget,
16265 GtkAllocation *allocation)
16269 g_return_if_fail (widget != NULL);
16270 g_return_if_fail (GTK_IS_DIAL (widget));
16271 g_return_if_fail (allocation != NULL);
16273 widget->allocation = *allocation;
16274 dial = GTK_DIAL (widget);
16276 if (GTK_WIDGET_REALIZED (widget))
16279 gdk_window_move_resize (widget->window,
16280 allocation->x, allocation->y,
16281 allocation->width, allocation->height);
16284 dial->radius = MIN(allocation->width,allocation->height) * 0.45;
16285 dial->pointer_width = dial->radius / 5;
16289 gtk_dial_expose (GtkWidget *widget,
16290 GdkEventExpose *event)
16293 GdkPoint points[3];
16300 g_return_val_if_fail (widget != NULL, FALSE);
16301 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16302 g_return_val_if_fail (event != NULL, FALSE);
16304 if (event->count > 0)
16307 dial = GTK_DIAL (widget);
16309 gdk_window_clear_area (widget->window,
16311 widget->allocation.width,
16312 widget->allocation.height);
16314 xc = widget->allocation.width/2;
16315 yc = widget->allocation.height/2;
16319 for (i=0; i<25; i++)
16321 theta = (i*M_PI/18. - M_PI/6.);
16325 tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
16327 gdk_draw_line (widget->window,
16328 widget->style->fg_gc[widget->state],
16329 xc + c*(dial->radius - tick_length),
16330 yc - s*(dial->radius - tick_length),
16331 xc + c*dial->radius,
16332 yc - s*dial->radius);
16337 s = sin(dial->angle);
16338 c = cos(dial->angle);
16341 points[0].x = xc + s*dial->pointer_width/2;
16342 points[0].y = yc + c*dial->pointer_width/2;
16343 points[1].x = xc + c*dial->radius;
16344 points[1].y = yc - s*dial->radius;
16345 points[2].x = xc - s*dial->pointer_width/2;
16346 points[2].y = yc - c*dial->pointer_width/2;
16348 gtk_draw_polygon (widget->style,
16359 gtk_dial_button_press (GtkWidget *widget,
16360 GdkEventButton *event)
16366 double d_perpendicular;
16368 g_return_val_if_fail (widget != NULL, FALSE);
16369 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16370 g_return_val_if_fail (event != NULL, FALSE);
16372 dial = GTK_DIAL (widget);
16374 /* Determine if button press was within pointer region - we
16375 do this by computing the parallel and perpendicular distance of
16376 the point where the mouse was pressed from the line passing through
16379 dx = event->x - widget->allocation.width / 2;
16380 dy = widget->allocation.height / 2 - event->y;
16382 s = sin(dial->angle);
16383 c = cos(dial->angle);
16385 d_parallel = s*dy + c*dx;
16386 d_perpendicular = fabs(s*dx - c*dy);
16388 if (!dial->button &&
16389 (d_perpendicular < dial->pointer_width/2) &&
16390 (d_parallel > - dial->pointer_width))
16392 gtk_grab_add (widget);
16394 dial->button = event->button;
16396 gtk_dial_update_mouse (dial, event->x, event->y);
16403 gtk_dial_button_release (GtkWidget *widget,
16404 GdkEventButton *event)
16408 g_return_val_if_fail (widget != NULL, FALSE);
16409 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16410 g_return_val_if_fail (event != NULL, FALSE);
16412 dial = GTK_DIAL (widget);
16414 if (dial->button == event->button)
16416 gtk_grab_remove (widget);
16420 if (dial->policy == GTK_UPDATE_DELAYED)
16421 gtk_timeout_remove (dial->timer);
16423 if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
16424 (dial->old_value != dial->adjustment->value))
16425 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment),
16433 gtk_dial_motion_notify (GtkWidget *widget,
16434 GdkEventMotion *event)
16437 GdkModifierType mods;
16440 g_return_val_if_fail (widget != NULL, FALSE);
16441 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16442 g_return_val_if_fail (event != NULL, FALSE);
16444 dial = GTK_DIAL (widget);
16446 if (dial->button != 0)
16451 if (event->is_hint || (event->window != widget->window))
16452 gdk_window_get_pointer (widget->window, &x, &y, &mods);
16454 switch (dial->button)
16457 mask = GDK_BUTTON1_MASK;
16460 mask = GDK_BUTTON2_MASK;
16463 mask = GDK_BUTTON3_MASK;
16470 if (mods & mask)
16471 gtk_dial_update_mouse (dial, x,y);
16478 gtk_dial_timer (GtkDial *dial)
16480 g_return_val_if_fail (dial != NULL, FALSE);
16481 g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
16483 if (dial->policy == GTK_UPDATE_DELAYED)
16484 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment),
16491 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
16496 g_return_if_fail (dial != NULL);
16497 g_return_if_fail (GTK_IS_DIAL (dial));
16499 xc = GTK_WIDGET(dial)->allocation.width / 2;
16500 yc = GTK_WIDGET(dial)->allocation.height / 2;
16502 old_value = dial->adjustment->value;
16503 dial->angle = atan2(yc-y, x-xc);
16505 if (dial->angle < -M_PI/2.)
16506 dial->angle += 2*M_PI;
16508 if (dial->angle < -M_PI/6)
16509 dial->angle = -M_PI/6;
16511 if (dial->angle > 7.*M_PI/6.)
16512 dial->angle = 7.*M_PI/6.;
16514 dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
16515 (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
16517 if (dial->adjustment->value != old_value)
16519 if (dial->policy == GTK_UPDATE_CONTINUOUS)
16521 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment),
16526 gtk_widget_draw (GTK_WIDGET(dial), NULL);
16528 if (dial->policy == GTK_UPDATE_DELAYED)
16531 gtk_timeout_remove (dial->timer);
16533 dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
16534 (GtkFunction) gtk_dial_timer,
16542 gtk_dial_update (GtkDial *dial)
16546 g_return_if_fail (dial != NULL);
16547 g_return_if_fail (GTK_IS_DIAL (dial));
16549 new_value = dial->adjustment->value;
16551 if (new_value < dial->adjustment->lower)
16552 new_value = dial->adjustment->lower;
16554 if (new_value > dial->adjustment->upper)
16555 new_value = dial->adjustment->upper;
16557 if (new_value != dial->adjustment->value)
16559 dial->adjustment->value = new_value;
16560 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
16563 dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) *
16565 (dial->adjustment->upper - dial->adjustment->lower);
16567 gtk_widget_draw (GTK_WIDGET(dial), NULL);
16571 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
16576 g_return_if_fail (adjustment != NULL);
16577 g_return_if_fail (data != NULL);
16579 dial = GTK_DIAL (data);
16581 if ((dial->old_value != adjustment->value) ||
16582 (dial->old_lower != adjustment->lower) ||
16583 (dial->old_upper != adjustment->upper))
16585 gtk_dial_update (dial);
16587 dial->old_value = adjustment->value;
16588 dial->old_lower = adjustment->lower;
16589 dial->old_upper = adjustment->upper;
16594 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
16599 g_return_if_fail (adjustment != NULL);
16600 g_return_if_fail (data != NULL);
16602 dial = GTK_DIAL (data);
16604 if (dial->old_value != adjustment->value)
16606 gtk_dial_update (dial);
16608 dial->old_value = adjustment->value;
16614 <!-- ----------------------------------------------------------------- -->
16618 /* example-start scribble-simple scribble-simple.c */
16620 /* GTK - The GIMP Toolkit
16621 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
16623 * This library is free software; you can redistribute it and/or
16624 * modify it under the terms of the GNU Library General Public
16625 * License as published by the Free Software Foundation; either
16626 * version 2 of the License, or (at your option) any later version.
16628 * This library is distributed in the hope that it will be useful,
16629 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16630 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16631 * Library General Public License for more details.
16633 * You should have received a copy of the GNU Library General Public
16634 * License along with this library; if not, write to the
16635 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16636 * Boston, MA 02111-1307, USA.
16639 #include <gtk/gtk.h>
16641 /* Backing pixmap for drawing area */
16642 static GdkPixmap *pixmap = NULL;
16644 /* Create a new backing pixmap of the appropriate size */
16646 configure_event (GtkWidget *widget, GdkEventConfigure *event)
16649 gdk_pixmap_unref(pixmap);
16651 pixmap = gdk_pixmap_new(widget->window,
16652 widget->allocation.width,
16653 widget->allocation.height,
16655 gdk_draw_rectangle (pixmap,
16656 widget->style->white_gc,
16659 widget->allocation.width,
16660 widget->allocation.height);
16665 /* Redraw the screen from the backing pixmap */
16667 expose_event (GtkWidget *widget, GdkEventExpose *event)
16669 gdk_draw_pixmap(widget->window,
16670 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
16672 event->area.x, event->area.y,
16673 event->area.x, event->area.y,
16674 event->area.width, event->area.height);
16679 /* Draw a rectangle on the screen */
16681 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
16683 GdkRectangle update_rect;
16685 update_rect.x = x - 5;
16686 update_rect.y = y - 5;
16687 update_rect.width = 10;
16688 update_rect.height = 10;
16689 gdk_draw_rectangle (pixmap,
16690 widget->style->black_gc,
16692 update_rect.x, update_rect.y,
16693 update_rect.width, update_rect.height);
16694 gtk_widget_draw (widget, &update_rect);
16698 button_press_event (GtkWidget *widget, GdkEventButton *event)
16700 if (event->button == 1 && pixmap != NULL)
16701 draw_brush (widget, event->x, event->y);
16707 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
16710 GdkModifierType state;
16712 if (event->is_hint)
16713 gdk_window_get_pointer (event->window, &x, &y, &state);
16718 state = event->state;
16721 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
16722 draw_brush (widget, x, y);
16734 main (int argc, char *argv[])
16737 GtkWidget *drawing_area;
16742 gtk_init (&argc, &argv);
16744 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
16745 gtk_widget_set_name (window, "Test Input");
16747 vbox = gtk_vbox_new (FALSE, 0);
16748 gtk_container_add (GTK_CONTAINER (window), vbox);
16749 gtk_widget_show (vbox);
16751 gtk_signal_connect (GTK_OBJECT (window), "destroy",
16752 GTK_SIGNAL_FUNC (quit), NULL);
16754 /* Create the drawing area */
16756 drawing_area = gtk_drawing_area_new ();
16757 gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200);
16758 gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
16760 gtk_widget_show (drawing_area);
16762 /* Signals used to handle backing pixmap */
16764 gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
16765 (GtkSignalFunc) expose_event, NULL);
16766 gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
16767 (GtkSignalFunc) configure_event, NULL);
16769 /* Event signals */
16771 gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
16772 (GtkSignalFunc) motion_notify_event, NULL);
16773 gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
16774 (GtkSignalFunc) button_press_event, NULL);
16776 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
16777 | GDK_LEAVE_NOTIFY_MASK
16778 | GDK_BUTTON_PRESS_MASK
16779 | GDK_POINTER_MOTION_MASK
16780 | GDK_POINTER_MOTION_HINT_MASK);
16782 /* .. And a quit button */
16783 button = gtk_button_new_with_label ("Quit");
16784 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
16786 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
16787 GTK_SIGNAL_FUNC (gtk_widget_destroy),
16788 GTK_OBJECT (window));
16789 gtk_widget_show (button);
16791 gtk_widget_show (window);
16800 <!-- ***************************************************************** -->
16802 <!-- ***************************************************************** -->
16804 NOTE: The List widget has been superseded by the CList widget. It is
16805 detailed here just for completeness.
16807 The List widget is designed to act as a vertical container for
16808 widgets that should be of the type ListItem.
16810 A List widget has its own window to receive events and its own
16811 background color which is usually white. As it is directly derived
16812 from a Container it can be treated as such by using the
16813 GTK_CONTAINER(List) macro, see the Container widget for more on
16814 this. One should already be familiar with the usage of a GList and
16815 its related functions g_list_*() to be able to use the List widget
16818 There is one field inside the structure definition of the List
16819 widget that will be of greater interest to us, this is:
16826 guint selection_mode;
16831 The selection field of a List points to a linked list of all items
16832 that are currently selected, or NULL if the selection is empty. So to
16833 learn about the current selection we read the GTK_LIST()->selection
16834 field, but do not modify it since the internal fields are maintained
16835 by the gtk_list_*() functions.
16837 The selection_mode of the List determines the selection facilities
16838 of a List and therefore the contents of the GTK_LIST()->selection
16839 field. The selection_mode may be one of the following:
16842 <item> <tt/GTK_SELECTION_SINGLE/ - The selection is either NULL
16843 or contains a GList pointer
16844 for a single selected item.
16846 <item> <tt/GTK_SELECTION_BROWSE/ - The selection is NULL if the list
16847 contains no widgets or insensitive
16848 ones only, otherwise it contains
16849 a GList pointer for one GList
16850 structure, and therefore exactly
16853 <item> <tt/GTK_SELECTION_MULTIPLE/ - The selection is NULL if no list
16854 items are selected or a GList pointer
16855 for the first selected item. That
16856 in turn points to a GList structure
16857 for the second selected item and so
16860 <item> <tt/GTK_SELECTION_EXTENDED/ - The selection is always NULL.
16863 The default is <tt/GTK_SELECTION_MULTIPLE/.
16865 <!-- ----------------------------------------------------------------- -->
16869 void selection_changed( GtkList *list );
16872 This signal will be invoked whenever the selection field of a List
16873 has changed. This happens when a child of thekList got selected or
16877 void select_child( GtkList *list,
16881 This signal is invoked when a child of the List is about to get
16882 selected. This happens mainly on calls to gtk_list_select_item(),
16883 gtk_list_select_child(), button presses and sometimes indirectly
16884 triggered on some else occasions where children get added to or
16885 removed from the List.
16888 void unselect_child( GtkList *list,
16889 GtkWidget *child );
16892 This signal is invoked when a child of the List is about to get
16893 deselected. This happens mainly on calls to gtk_list_unselect_item(),
16894 gtk_list_unselect_child(), button presses and sometimes indirectly
16895 triggered on some else occasions where children get added to or
16896 removed from the List.
16898 <!-- ----------------------------------------------------------------- -->
16902 guint gtk_list_get_type( void );
16905 Returns the "GtkList" type identifier.
16908 GtkWidget *gtk_list_new( void );
16911 Create a new List object. The new widget is returned as a pointer
16912 to a GtkWidget object. NULL is returned on failure.
16915 void gtk_list_insert_items( GtkList *list,
16920 Insert list items into the list, starting at <tt/position/.
16921 <tt/items/ is a doubly linked list where each nodes data pointer is
16922 expected to point to a newly created ListItem. The GList nodes of
16923 <tt/items/ are taken over by the list.
16926 void gtk_list_append_items( GtkList *list,
16930 Insert list items just like gtk_list_insert_items() at the end of the
16931 list. The GList nodes of <tt/items/ are taken over by the list.
16934 void gtk_list_prepend_items( GtkList *list,
16938 Insert list items just like gtk_list_insert_items() at the very
16939 beginning of the list. The GList nodes of <tt/items/ are taken over by
16943 void gtk_list_remove_items( GtkList *list,
16947 Remove list items from the list. <tt/items/ is a doubly linked list
16948 where each nodes data pointer is expected to point to a direct child
16949 of list. It is the callers responsibility to make a call to
16950 g_list_free(items) afterwards. Also the caller has to destroy the list
16954 void gtk_list_clear_items( GtkList *list,
16959 Remove and destroy list items from the list. A widget is affected if
16960 its current position within the list is in the range specified by
16961 <tt/start/ and <tt/end/.
16964 void gtk_list_select_item( GtkList *list,
16968 Invoke the select_child signal for a list item specified through its
16969 current position within the list.
16972 void gtk_list_unselect_item( GtkList *list,
16976 Invoke the unselect_child signal for a list item specified through its
16977 current position within the list.
16980 void gtk_list_select_child( GtkList *list,
16984 Invoke the select_child signal for the specified child.
16987 void gtk_list_unselect_child( GtkList *list,
16991 Invoke the unselect_child signal for the specified child.
16994 gint gtk_list_child_position( GtkList *list,
16998 Return the position of <tt/child/ within the list. "-1" is returned on
17002 void gtk_list_set_selection_mode( GtkList *list,
17003 GtkSelectionMode mode );
17006 Set the selection mode MODE which can be of GTK_SELECTION_SINGLE,
17007 GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE or
17008 GTK_SELECTION_EXTENDED.
17011 GtkList *GTK_LIST( gpointer obj );
17014 Cast a generic pointer to "GtkList *".
17017 GtkListClass *GTK_LIST_CLASS( gpointer class);
17020 Cast a generic pointer to "GtkListClass *".
17023 gint GTK_IS_LIST( gpointer obj);
17026 Determine if a generic pointer refers to a "GtkList" object.
17028 <!-- ----------------------------------------------------------------- -->
17031 Following is an example program that will print out the changes of the
17032 selection of a List, and lets you "arrest" list items into a prison
17033 by selecting them with the rightmost mouse button.
17036 /* example-start list list.c */
17038 /* Include the GTK header files
17039 * Include stdio.h, we need that for the printf() function
17041 #include <gtk/gtk.h>
17044 /* This is our data identification string to store
17045 * data in list items
17047 const gchar *list_item_data_key="list_item_data";
17050 /* prototypes for signal handler that we are going to connect
17051 * to the List widget
17053 static void sigh_print_selection( GtkWidget *gtklist,
17054 gpointer func_data);
17056 static void sigh_button_event( GtkWidget *gtklist,
17057 GdkEventButton *event,
17058 GtkWidget *frame );
17061 /* Main function to set up the user interface */
17063 gint main (int argc,
17066 GtkWidget *separator;
17069 GtkWidget *scrolled_window;
17071 GtkWidget *gtklist;
17073 GtkWidget *list_item;
17079 /* Initialize GTK (and subsequently GDK) */
17081 gtk_init(&argc, &argv);
17084 /* Create a window to put all the widgets in
17085 * connect gtk_main_quit() to the "destroy" event of
17086 * the window to handle window manager close-window-events
17088 window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
17089 gtk_window_set_title(GTK_WINDOW(window), "GtkList Example");
17090 gtk_signal_connect(GTK_OBJECT(window),
17092 GTK_SIGNAL_FUNC(gtk_main_quit),
17096 /* Inside the window we need a box to arrange the widgets
17098 vbox=gtk_vbox_new(FALSE, 5);
17099 gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
17100 gtk_container_add(GTK_CONTAINER(window), vbox);
17101 gtk_widget_show(vbox);
17103 /* This is the scrolled window to put the List widget inside */
17104 scrolled_window=gtk_scrolled_window_new(NULL, NULL);
17105 gtk_widget_set_usize(scrolled_window, 250, 150);
17106 gtk_container_add(GTK_CONTAINER(vbox), scrolled_window);
17107 gtk_widget_show(scrolled_window);
17109 /* Create thekList widget.
17110 * Connect the sigh_print_selection() signal handler
17111 * function to the "selection_changed" signal of the List
17112 * to print out the selected items each time the selection
17114 gtklist=gtk_list_new();
17115 gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(scrolled_window),
17117 gtk_widget_show(gtklist);
17118 gtk_signal_connect(GTK_OBJECT(gtklist),
17119 "selection_changed",
17120 GTK_SIGNAL_FUNC(sigh_print_selection),
17123 /* We create a "Prison" to put a list item in ;) */
17124 frame=gtk_frame_new("Prison");
17125 gtk_widget_set_usize(frame, 200, 50);
17126 gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
17127 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
17128 gtk_container_add(GTK_CONTAINER(vbox), frame);
17129 gtk_widget_show(frame);
17131 /* Connect the sigh_button_event() signal handler to the List
17132 * which will handle the "arresting" of list items
17134 gtk_signal_connect(GTK_OBJECT(gtklist),
17135 "button_release_event",
17136 GTK_SIGNAL_FUNC(sigh_button_event),
17139 /* Create a separator */
17140 separator=gtk_hseparator_new();
17141 gtk_container_add(GTK_CONTAINER(vbox), separator);
17142 gtk_widget_show(separator);
17144 /* Finally create a button and connect its "clicked" signal
17145 * to the destruction of the window */
17146 button=gtk_button_new_with_label("Close");
17147 gtk_container_add(GTK_CONTAINER(vbox), button);
17148 gtk_widget_show(button);
17149 gtk_signal_connect_object(GTK_OBJECT(button),
17151 GTK_SIGNAL_FUNC(gtk_widget_destroy),
17152 GTK_OBJECT(window));
17155 /* Now we create 5 list items, each having its own
17156 * label and add them to the List using gtk_container_add()
17157 * Also we query the text string from the label and
17158 * associate it with the list_item_data_key for each list item
17160 for (i=0; i<5; i++) {
17164 sprintf(buffer, "ListItemContainer with Label #%d", i);
17165 label=gtk_label_new(buffer);
17166 list_item=gtk_list_item_new();
17167 gtk_container_add(GTK_CONTAINER(list_item), label);
17168 gtk_widget_show(label);
17169 gtk_container_add(GTK_CONTAINER(gtklist), list_item);
17170 gtk_widget_show(list_item);
17171 gtk_label_get(GTK_LABEL(label), &string);
17172 gtk_object_set_data(GTK_OBJECT(list_item),
17173 list_item_data_key,
17176 /* Here, we are creating another 5 labels, this time
17177 * we use gtk_list_item_new_with_label() for the creation
17178 * we can't query the text string from the label because
17179 * we don't have the labels pointer and therefore
17180 * we just associate the list_item_data_key of each
17181 * list item with the same text string.
17182 * For adding of the list items we put them all into a doubly
17183 * linked list (GList), and then add them by a single call to
17184 * gtk_list_append_items().
17185 * Because we use g_list_prepend() to put the items into the
17186 * doubly linked list, their order will be descending (instead
17187 * of ascending when using g_list_append())
17190 for (; i<10; i++) {
17191 sprintf(buffer, "List Item with Label %d", i);
17192 list_item=gtk_list_item_new_with_label(buffer);
17193 dlist=g_list_prepend(dlist, list_item);
17194 gtk_widget_show(list_item);
17195 gtk_object_set_data(GTK_OBJECT(list_item),
17196 list_item_data_key,
17197 "ListItem with integrated Label");
17199 gtk_list_append_items(GTK_LIST(gtklist), dlist);
17201 /* Finally we want to see the window, don't we? ;) */
17202 gtk_widget_show(window);
17204 /* Fire up the main event loop of gtk */
17207 /* We get here after gtk_main_quit() has been called which
17208 * happens if the main window gets destroyed
17213 /* This is the signal handler that got connected to button
17214 * press/release events of the List
17216 void sigh_button_event( GtkWidget *gtklist,
17217 GdkEventButton *event,
17220 /* We only do something if the third (rightmost mouse button
17223 if (event->type==GDK_BUTTON_RELEASE &&
17224 event->button==3) {
17225 GList *dlist, *free_list;
17226 GtkWidget *new_prisoner;
17228 /* Fetch the currently selected list item which
17229 * will be our next prisoner ;)
17231 dlist=GTK_LIST(gtklist)->selection;
17233 new_prisoner=GTK_WIDGET(dlist->data);
17237 /* Look for already imprisoned list items, we
17238 * will put them back into the list.
17239 * Remember to free the doubly linked list that
17240 * gtk_container_children() returns
17242 dlist=gtk_container_children(GTK_CONTAINER(frame));
17245 GtkWidget *list_item;
17247 list_item=dlist->data;
17249 gtk_widget_reparent(list_item, gtklist);
17253 g_list_free(free_list);
17255 /* If we have a new prisoner, remove him from the
17256 * List and put him into the frame "Prison".
17257 * We need to unselect the item first.
17259 if (new_prisoner) {
17260 GList static_dlist;
17262 static_dlist.data=new_prisoner;
17263 static_dlist.next=NULL;
17264 static_dlist.prev=NULL;
17266 gtk_list_unselect_child(GTK_LIST(gtklist),
17268 gtk_widget_reparent(new_prisoner, frame);
17273 /* This is the signal handler that gets called if List
17274 * emits the "selection_changed" signal
17276 void sigh_print_selection( GtkWidget *gtklist,
17277 gpointer func_data)
17281 /* Fetch the doubly linked list of selected items
17282 * of the List, remember to treat this as read-only!
17284 dlist=GTK_LIST(gtklist)->selection;
17286 /* If there are no selected items there is nothing more
17287 * to do than just telling the user so
17290 g_print("Selection cleared\n");
17293 /* Ok, we got a selection and so we print it
17295 g_print("The selection is a ");
17297 /* Get the list item from the doubly linked list
17298 * and then query the data associated with list_item_data_key.
17299 * We then just print it */
17301 GtkObject *list_item;
17302 gchar *item_data_string;
17304 list_item=GTK_OBJECT(dlist->data);
17305 item_data_string=gtk_object_get_data(list_item,
17306 list_item_data_key);
17307 g_print("%s ", item_data_string);
17316 <!-- ----------------------------------------------------------------- -->
17317 <sect1> List Item Widget
17319 The ListItem widget is designed to act as a container holding up to
17320 one child, providing functions for selection/deselection just like the
17321 List widget requires them for its children.
17323 A ListItem has its own window to receive events and has its own
17324 background color which is usually white.
17326 As it is directly derived from an Item it can be treated as such by
17327 using the GTK_ITEM(ListItem) macro, see the Item widget for more on
17328 this. Usually a ListItem just holds a label to identify, e.g., a
17329 filename within a List -- therefore the convenience function
17330 gtk_list_item_new_with_label() is provided. The same effect can be
17331 achieved by creating a Label on its own, setting its alignment to
17332 xalign=0 and yalign=0.5 with a subsequent container addition to the
17335 As one is not forced to add a GtkLabel to a GtkListItem, you could
17336 also add a GtkVBox or a GtkArrow etc. to the GtkListItem.
17338 <!-- ----------------------------------------------------------------- -->
17341 AkListItem does not create new signals on its own, but inherits
17342 the signals of a Item.
17344 <!-- ----------------------------------------------------------------- -->
17348 guint gtk_list_item_get_type( void );
17351 Returns the "GtkListItem" type identifier.
17354 GtkWidget *gtk_list_item_new( void );
17357 Create a new ListItem object. The new widget is returned as a
17358 pointer to a GtkWidget object. NULL is returned on failure.
17361 GtkWidget *gtk_list_item_new_with_label( gchar *label );
17364 Create a new ListItem object, having a single GtkLabel as the sole
17365 child. The new widget is returned as a pointer to a GtkWidget
17366 object. NULL is returned on failure.
17369 void gtk_list_item_select( GtkListItem *list_item );
17372 This function is basically a wrapper around a call to gtk_item_select
17373 (GTK_ITEM (list_item)) which will emit the select signal. *Note
17374 GtkItem::, for more info.
17377 void gtk_list_item_deselect( GtkListItem *list_item );
17380 This function is basically a wrapper around a call to
17381 gtk_item_deselect (GTK_ITEM (list_item)) which will emit the deselect
17382 signal. *Note GtkItem::, for more info.
17385 GtkListItem *GTK_LIST_ITEM( gpointer obj );
17388 Cast a generic pointer to "GtkListItem *".
17391 GtkListItemClass *GTK_LIST_ITEM_CLASS( gpointer class );
17394 Cast a generic pointer to GtkListItemClass*. *Note Standard Macros::,
17398 gint GTK_IS_LIST_ITEM( gpointer obj );
17401 Determine if a generic pointer refers to a `GtkListItem' object.
17402 *Note Standard Macros::, for more info.
17404 <!-- ----------------------------------------------------------------- -->
17407 Please see the List example on this, which covers the usage of a