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>February 7th, 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 X windows). The primary authors of GTK are:
44 <item> Peter Mattis <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
45 name="petm@xcf.berkeley.edu"></tt>
46 <item> Spencer Kimball <tt><htmlurl url="mailto:spencer@xcf.berkeley.edu"
47 name="spencer@xcf.berkeley.edu"></tt>
48 <item> Josh MacDonald <tt><htmlurl url="mailto:jmacd@xcf.berkeley.edu"
49 name="jmacd@xcf.berkeley.edu"></tt>
52 GTK is essentially an object oriented application programmers
53 interface (API). Although written completely in C, it is implemented
54 using the idea of classes and callback functions (pointers to
57 There is also a third component called glib which contains a few
58 replacements for some standard calls, as well as some additional
59 functions for handling linked lists etc. The replacement functions are
60 used to increase GTK's portability, as some of the functions
61 implemented here are not available or are nonstandard on other unixes
62 such as g_strerror(). Some also contain enhancements to the libc
63 versions, such as g_malloc that has enhanced debugging utilities.
65 This tutorial describes the C interface to GTK. There are GTK
66 bindings for many other languages including C++, Guile, Perl, Python,
67 TOM, Ada95, Objective C, Free Pascal, and Eiffel. If you intend to
68 use another language's bindings to GTK, look at that binding's
69 documentation first. In some cases that documentation may describe
70 some important conventions (which you should know first) and then
71 refer you back to this tutorial. There are also some cross-platform
72 APIs (such as wxWindows and V) which use GTK as one of their target
73 platforms; again, consult their documentation first.
75 If you're developing your GTK application in C++, a few extra notes
76 are in order. There's a C++ binding to GTK called GTK--, which
77 provides a more C++-like interface to GTK; you should probably look
78 into this instead. If you don't like that approach for whatever
79 reason, there are two alternatives for using GTK. First, you can use
80 only the C subset of C++ when interfacing with GTK and then use the C
81 interface as described in this tutorial. Second, you can use GTK and
82 C++ together by declaring all callbacks as static functions in C++
83 classes, and again calling GTK using its C interface. If you choose
84 this last approach, you can include as the callback's data value a
85 pointer to the object to be manipulated (the so-called "this" value).
86 Selecting between these options is simply a matter of preference,
87 since in all three approaches you get C++ and GTK. None of these
88 approaches requires the use of a specialized preprocessor, so no
89 matter what you choose you can use standard C++ with GTK.
91 This tutorial is an attempt to document as much as possible of GTK,
92 but it is by no means complete. This tutorial assumes a good
93 understanding of C, and how to create C programs. It would be a great
94 benefit for the reader to have previous X programming experience, but
95 it shouldn't be necessary. If you are learning GTK as your first
96 widget set, please comment on how you found this tutorial, and what
97 you had trouble with. Note that there is also a C++ API for GTK
98 (GTK--) in the works, so if you prefer to use C++, you should look
99 into this instead. There are also Objective C, ADA, Guile and other
100 language bindings available, but I don't follow these.
102 This document is a 'work in progress'. Please look for updates on
103 http://www.gtk.org/ <htmlurl url="http://www.gtk.org/"
104 name="http://www.gtk.org/">.
106 I would very much like to hear of any problems you have learning GTK
107 from this document, and would appreciate input as to how it may be
108 improved. Please see the section on <ref id="sec_Contributing"
109 name="Contributing"> for further information.
111 <!-- ***************************************************************** -->
112 <sect>Getting Started
113 <!-- ***************************************************************** -->
116 The first thing to do of course, is download the GTK source and
117 install it. You can always get the latest version from ftp.gtk.org in
118 /pub/gtk. You can also view other sources of GTK information on
119 http://www.gtk.org/ <htmlurl url="http://www.gtk.org/"
120 name="http://www.gtk.org/">. GTK uses GNU autoconf for configuration.
121 Once untar'd, type ./configure --help to see a list of options.
123 Th GTK source distribution also contains the complete source to all of
124 the examples used in this tutorial, along with Makefiles to aid
127 To begin our introduction to GTK, we'll start with the simplest
128 program possible. This program will create a 200x200 pixel window and
129 has no way of exiting except to be killed using the shell.
132 /* example-start base base.c */
141 gtk_init (&argc, &argv);
143 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
144 gtk_widget_show (window);
153 You can compile the above program with gcc using:
155 gcc base.c -o base `gtk-config --cflags --libs`
158 The meaning of the unusual compilation options is explained below.
160 All programs will of course include gtk/gtk.h which declares the
161 variables, functions, structures etc. that will be used in your GTK
167 gtk_init (&argc, &argv);
170 calls the function gtk_init(gint *argc, gchar ***argv) which will be
171 called in all GTK applications. This sets up a few things for us such
172 as the default visual and color map and then proceeds to call
173 gdk_init(gint *argc, gchar ***argv). This function initializes the
174 library for use, sets up default signal handlers, and checks the
175 arguments passed to your application on the command line, looking for
176 one of the following:
179 <item> <tt/--gtk-module/
180 <item> <tt/--g-fatal-warnings/
181 <item> <tt/--gtk-debug/
182 <item> <tt/--gtk-no-debug/
183 <item> <tt/--gdk-debug/
184 <item> <tt/--gdk-no-debug/
185 <item> <tt/--display/
187 <item> <tt/--no-xshm/
192 It removes these from the argument list, leaving anything it does not
193 recognize for your application to parse or ignore. This creates a set
194 of standard arguments accepted by all GTK applications.
196 The next two lines of code create and display a window.
199 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
200 gtk_widget_show (window);
203 The GTK_WINDOW_TOPLEVEL argument specifies that we want the window to
204 undergo window manager decoration and placement. Rather than create a
205 window of 0x0 size, a window without children is set to 200x200 by
206 default so you can still manipulate it.
208 The gtk_widget_show() function lets GTK know that we are done setting
209 the attributes of this widget, and that it can display it.
211 The last line enters the GTK main processing loop.
217 gtk_main() is another call you will see in every GTK application.
218 When control reaches this point, GTK will sleep waiting for X events
219 (such as button or key presses), timeouts, or file IO notifications to
220 occur. In our simple example however, events are ignored.
222 <!-- ----------------------------------------------------------------- -->
223 <sect1>Hello World in GTK
225 Now for a program with a widget (a button). It's the classic
226 hello world a la GTK.
229 /* example-start helloworld helloworld.c */
233 /* This is a callback function. The data arguments are ignored
234 * in this example. More on callbacks below. */
235 void hello( GtkWidget *widget,
238 g_print ("Hello World\n");
241 gint delete_event( GtkWidget *widget,
245 /* If you return FALSE in the "delete_event" signal handler,
246 * GTK will emit the "destroy" signal. Returning TRUE means
247 * you don't want the window to be destroyed.
248 * This is useful for popping up 'are you sure you want to quit?'
251 g_print ("delete event occurred\n");
253 /* Change TRUE to FALSE and the main window will be destroyed with
254 * a "delete_event". */
259 /* Another callback */
260 void destroy( GtkWidget *widget,
269 /* GtkWidget is the storage type for widgets */
273 /* This is called in all GTK applications. Arguments are parsed
274 * from the command line and are returned to the application. */
275 gtk_init(&argc, &argv);
277 /* create a new window */
278 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
280 /* When the window is given the "delete_event" signal (this is given
281 * by the window manager, usually by the 'close' option, or on the
282 * titlebar), we ask it to call the delete_event () function
283 * as defined above. The data passed to the callback
284 * function is NULL and is ignored in the callback function. */
285 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
286 GTK_SIGNAL_FUNC (delete_event), NULL);
288 /* Here we connect the "destroy" event to a signal handler.
289 * This event occurs when we call gtk_widget_destroy() on the window,
290 * or if we return 'FALSE' in the "delete_event" callback. */
291 gtk_signal_connect (GTK_OBJECT (window), "destroy",
292 GTK_SIGNAL_FUNC (destroy), NULL);
294 /* Sets the border width of the window. */
295 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
297 /* Creates a new button with the label "Hello World". */
298 button = gtk_button_new_with_label ("Hello World");
300 /* When the button receives the "clicked" signal, it will call the
301 * function hello() passing it NULL as its argument. The hello()
302 * function is defined above. */
303 gtk_signal_connect (GTK_OBJECT (button), "clicked",
304 GTK_SIGNAL_FUNC (hello), NULL);
306 /* This will cause the window to be destroyed by calling
307 * gtk_widget_destroy(window) when "clicked". Again, the destroy
308 * signal could come from here, or the window manager. */
309 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
310 GTK_SIGNAL_FUNC (gtk_widget_destroy),
311 GTK_OBJECT (window));
313 /* This packs the button into the window (a gtk container). */
314 gtk_container_add (GTK_CONTAINER (window), button);
316 /* The final step is to display this newly created widget. */
317 gtk_widget_show (button);
320 gtk_widget_show (window);
322 /* All GTK applications must have a gtk_main(). Control ends here
323 * and waits for an event to occur (like a key press or
332 <!-- ----------------------------------------------------------------- -->
333 <sect1>Compiling Hello World
338 gcc -Wall -g helloworld.c -o helloworld `gtk-config --cflags` \
342 This uses the program <tt>gtk-config</>, which comes with gtk. This
343 program 'knows' what compiler switches are needed to compile programs
344 that use gtk. <tt>gtk-config --cflags</> will output a list of include
345 directories for the compiler to look in, and <tt>gtk-config --libs</>
346 will output the list of libraries for the compiler to link with and
347 the directories to find them in. In the aboce example they could have
348 been combined into a single instance, such as
349 `gtk-config --cflags --libs`.
351 Note that the type of single quote used in the compile command above
354 The libraries that are usually linked in are:
356 <item>The GTK library (-lgtk), the widget library, based on top of GDK.
357 <item>The GDK library (-lgdk), the Xlib wrapper.
358 <item>The gmodule library (-lgmodule), which is used to load run time
360 <item>The glib library (-lglib), containing miscellaneous functions, only
361 g_print() is used in this particular example. GTK is built on top
362 of glib so you will always require this library. See the section on
363 <ref id="sec_glib" name="glib"> for details.
364 <item>The Xlib library (-lX11) which is used by GDK.
365 <item>The Xext library (-lXext). This contains code for shared memory
366 pixmaps and other X extensions.
367 <item>The math library (-lm). This is used by GTK for various purposes.
370 <!-- ----------------------------------------------------------------- -->
371 <sect1>Theory of Signals and Callbacks
373 Before we look in detail at <em>helloworld</em>, we'll discuss signals
374 and callbacks. GTK is an event driven toolkit, which means it will
375 sleep in gtk_main until an event occurs and control is passed to the
376 appropriate function.
378 This passing of control is done using the idea of "signals". When an
379 event occurs, such as the press of a mouse button, the appropriate
380 signal will be "emitted" by the widget that was pressed. This is how
381 GTK does most of its useful work. There are a set of signals that all
382 widgets inherit, such as "destroy", and there are signals that are
383 widget specific, such as "toggled" on a toggle button.
385 To make a button perform an action, we set up a signal handler to
386 catch these signals and call the appropriate function. This is done by
387 using a function such as:
390 gint gtk_signal_connect( GtkObject *object,
393 gpointer func_data );
396 Where the first argument is the widget which will be emitting the
397 signal, and the second, the name of the signal you wish to catch. The
398 third is the function you wish to be called when it is caught, and the
399 fourth, the data you wish to have passed to this function.
401 The function specified in the third argument is called a "callback
402 function", and should generally be of the form:
405 void callback_func( GtkWidget *widget,
406 gpointer callback_data );
409 Where the first argument will be a pointer to the widget that emitted
410 the signal, and the second, a pointer to the data given as the last
411 argument to the gtk_signal_connect() function as shown above.
413 Note that the above form for a signal callback function declaration is
414 only a general guide, as some widget specific signals generate
415 different calling parameters. For example, the GtkCList "select_row"
416 signal provides both row and column parameters.
418 Another call used in the <em>helloworld</em> example, is:
421 gint gtk_signal_connect_object( GtkObject *object,
424 GtkObject *slot_object );
427 gtk_signal_connect_object() is the same as gtk_signal_connect() except
428 that the callback function only uses one argument, a pointer to a GTK
429 object. So when using this function to connect signals, the callback
430 should be of the form:
433 void callback_func( GtkObject *object );
436 Where the object is usually a widget. We usually don't setup callbacks
437 for gtk_signal_connect_object however. They are usually used to call a
438 GTK function that accepts a single widget or object as an argument, as
439 is the case in our <em>helloworld</em> example.
441 The purpose of having two functions to connect signals is simply to
442 allow the callbacks to have a different number of arguments. Many
443 functions in the GTK library accept only a single GtkWidget pointer as
444 an argument, so you want to use the gtk_signal_connect_object() for
445 these, whereas for your functions, you may need to have additional
446 data supplied to the callbacks.
448 <!-- ----------------------------------------------------------------- -->
451 In addition to the signal mechanism described above, there are a set
452 of <em>events</em> that reflect the X event mechanism. Callbacks may
453 also be attached to these events. These events are:
457 <item> button_press_event
458 <item> button_release_event
459 <item> motion_notify_event
463 <item> key_press_event
464 <item> key_release_event
465 <item> enter_notify_event
466 <item> leave_notify_event
467 <item> configure_event
468 <item> focus_in_event
469 <item> focus_out_event
472 <item> property_notify_event
473 <item> selection_clear_event
474 <item> selection_request_event
475 <item> selection_notify_event
476 <item> proximity_in_event
477 <item> proximity_out_event
478 <item> drag_begin_event
479 <item> drag_request_event
480 <item> drag_end_event
481 <item> drop_enter_event
482 <item> drop_leave_event
483 <item> drop_data_available_event
487 In order to connect a callback function to one of these events, you
488 use the function gtk_signal_connect, as described above, using one of
489 the above event names as the <tt/name/ parameter. The callback
490 function for events has a slightly different form than that for
494 void callback_func( GtkWidget *widget,
496 gpointer callback_data );
499 GdkEvent is a C <tt/union/ structure whose type will depend upon which
500 of the above events has occurred. In order for us to tell which event
501 has been issued each of the possible alternatives has a <tt/type/
502 parameter which reflects the event being issued. The other components
503 of the event structure will depend upon the type of the
504 event. Possible values for the type are:
526 GDK_SELECTION_REQUEST
536 GDK_VISIBILITY_NOTIFY
538 GDK_OTHER_EVENT /* Deprecated, use filters instead */
541 So, to connect a callback function to one of these events we would use
545 gtk_signal_connect( GTK_OBJECT(button), "button_press_event",
546 GTK_SIGNAL_FUNC(button_press_callback),
550 This assumes that <tt/button/ is a GtkButton widget. Now, when the
551 mouse is over the button and a mouse button is pressed, the function
552 <tt/button_press_callback/ will be called. This function may be
556 static gint button_press_event (GtkWidget *widget,
557 GdkEventButton *event,
561 Note that we can declare the second argument as type
562 <tt/GdkEventButton/ as we know what type of event will occur for this
563 function to be called.
565 The value returned from this function indicates whether the event
566 should be propagated further by the GTK event handling
567 mechanism. Returning TRUE indicates that the event has been handled,
568 and that it should not propagate further. Returning FALSE continues
569 the normal event handling. See the section on
570 <ref id="sec_Adv_Events_and_Signals"
571 name="Advanced Event and Signal Handling"> for more details on this
574 For details on the GdkEvent data types, see the appendix entitled
575 <ref id="sec_GDK_Event_Types" name="GDK Event Types">.
577 <!-- ----------------------------------------------------------------- -->
578 <sect1>Stepping Through Hello World
580 Now that we know the theory behind this, lets clarify by walking through
581 the example <em>helloworld</em> program.
583 Here is the callback function that will be called when the button is
584 "clicked". We ignore both the widget and the data in this example, but
585 it is not hard to do things with them. The next example will use the
586 data argument to tell us which button was pressed.
589 void hello( GtkWidget *widget,
592 g_print ("Hello World\n");
596 The next callback is a bit special. The "delete_event" occurs when the
597 window manager sends this event to the application. We have a choice
598 here as to what to do about these events. We can ignore them, make
599 some sort of response, or simply quit the application.
601 The value you return in this callback lets GTK know what action to
602 take. By returning TRUE, we let it know that we don't want to have
603 the "destroy" signal emitted, keeping our application running. By
604 returning FALSE, we ask that "destroy" is emitted, which in turn will
605 call our "destroy" signal handler.
608 gint delete_event( GtkWidget *widget,
612 g_print ("delete event occurred\n");
618 Here is another callback function which causes the program to quit by
619 calling gtk_main_quit(). This function tells GTK that it is to exit
620 from gtk_main when control is returned to it.
623 void destroy( GtkWidget *widget,
630 I assume you know about the main() function... yes, as with other
631 applications, all GTK applications will also have one of these.
639 This next part, declares a pointer to a structure of type
640 GtkWidget. These are used below to create a window and a button.
647 Here is our gtk_init again. As before, this initializes the toolkit,
648 and parses the arguments found on the command line. Any argument it
649 recognizes from the command line, it removes from the list, and
650 modifies argc and argv to make it look like they never existed,
651 allowing your application to parse the remaining arguments.
654 gtk_init (&argc, &argv);
657 Create a new window. This is fairly straight forward. Memory is
658 allocated for the GtkWidget *window structure so it now points to a
659 valid structure. It sets up a new window, but it is not displayed
660 until we call gtk_widget_show(window) near the end of our program.
663 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
666 Here is an example of connecting a signal handler to an object, in
667 this case, the window. Here, the "destroy" signal is caught. This is
668 emitted when we use the window manager to kill the window (and we
669 return FALSE in the "delete_event" handler), or when we use the
670 gtk_widget_destroy() call passing in the window widget as the object
671 to destroy. By setting this up, we handle both cases with a single
672 call. Here, it just calls the destroy() function defined above with a
673 NULL argument, which quits GTK for us.
675 The GTK_OBJECT and GTK_SIGNAL_FUNC are macros that perform type
676 casting and checking for us, as well as aid the readability of the
680 gtk_signal_connect (GTK_OBJECT (window), "destroy",
681 GTK_SIGNAL_FUNC (destroy), NULL);
684 This next function is used to set an attribute of a container object.
685 This just sets the window so it has a blank area along the inside of
686 it 10 pixels wide where no widgets will go. There are other similar
687 functions which we will look at in the section on
688 <ref id="sec_setting_widget_attributes" name="Setting Widget Attributes">
690 And again, GTK_CONTAINER is a macro to perform type casting.
693 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
696 This call creates a new button. It allocates space for a new GtkWidget
697 structure in memory, initializes it, and makes the button pointer
698 point to it. It will have the label "Hello World" on it when
702 button = gtk_button_new_with_label ("Hello World");
705 Here, we take this button, and make it do something useful. We attach
706 a signal handler to it so when it emits the "clicked" signal, our
707 hello() function is called. The data is ignored, so we simply pass in
708 NULL to the hello() callback function. Obviously, the "clicked" signal
709 is emitted when we click the button with our mouse pointer.
712 gtk_signal_connect (GTK_OBJECT (button), "clicked",
713 GTK_SIGNAL_FUNC (hello), NULL);
716 We are also going to use this button to exit our program. This will
717 illustrate how the "destroy" signal may come from either the window
718 manager, or our program. When the button is "clicked", same as above,
719 it calls the first hello() callback function, and then this one in the
720 order they are set up. You may have as many callback functions as you
721 need, and all will be executed in the order you connected
722 them. Because the gtk_widget_destroy() function accepts only a
723 GtkWidget *widget as an argument, we use the
724 gtk_signal_connect_object() function here instead of straight
725 gtk_signal_connect().
728 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
729 GTK_SIGNAL_FUNC (gtk_widget_destroy),
730 GTK_OBJECT (window));
733 This is a packing call, which will be explained in depth later on. But
734 it is fairly easy to understand. It simply tells GTK that the button
735 is to be placed in the window where it will be displayed. Note that a
736 GTK container can only contain one widget. There are other widgets,
737 that are described later, which are designed to layout multiple
738 widgets in various ways.
741 gtk_container_add (GTK_CONTAINER (window), button);
744 Now we have everything set up the way we want it to be. With all the
745 signal handlers in place, and the button placed in the window where it
746 should be, we ask GTK to "show" the widgets on the screen. The window
747 widget is shown last so the whole window will pop up at once rather
748 than seeing the window pop up, and then the button form inside of
749 it. Although with such a simple example, you'd never notice.
752 gtk_widget_show (button);
754 gtk_widget_show (window);
757 And of course, we call gtk_main() which waits for events to come from
758 the X server and will call on the widgets to emit signals when these
765 And the final return. Control returns here after gtk_quit() is called.
771 Now, when we click the mouse button on a GTK button, the widget emits
772 a "clicked" signal. In order for us to use this information, our
773 program sets up a signal handler to catch that signal, which
774 dispatches the function of our choice. In our example, when the button
775 we created is "clicked", the hello() function is called with a NULL
776 argument, and then the next handler for this signal is called. This
777 calls the gtk_widget_destroy() function, passing it the window widget
778 as its argument, destroying the window widget. This causes the window
779 to emit the "destroy" signal, which is caught, and calls our destroy()
780 callback function, which simply exits GTK.
782 Another course of events, is to use the window manager to kill the
783 window. This will cause the "delete_event" to be emitted. This will
784 call our "delete_event" handler. If we return TRUE here, the window
785 will be left as is and nothing will happen. Returning FALSE will cause
786 GTK to emit the "destroy" signal which of course, calls the "destroy"
787 callback, exiting GTK.
789 Note that these signals are not the same as the Unix system signals,
790 and are not implemented using them, although the terminology is almost
793 <!-- ***************************************************************** -->
795 <!-- ***************************************************************** -->
797 <!-- ----------------------------------------------------------------- -->
800 There are a few things you probably noticed in the previous examples
801 that need explaining. The gint, gchar etc. that you see are typedefs
802 to int and char respectively. This is done to get around that nasty
803 dependency on the size of simple data 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 straight forward and intuitive. They are
808 all defined in glib/glib.h (which gets included from gtk.h).
810 You'll also notice the ability to use GtkWidget when the function
811 calls for a GtkObject. 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, this 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() - GTK_WINDOW_DIALOG. This interacts with the window
967 manager a little differently and should be used for transient windows.
969 <!-- ***************************************************************** -->
970 <sect>Packing Widgets
971 <!-- ***************************************************************** -->
973 When creating an application, you'll want to put more than one widget
974 inside a window. Our first <em>helloworld</em> example only used one
975 widget so we could simply use a gtk_container_add call to "pack" the
976 widget into the window. But when you want to put more than one widget
977 into a window, how do you control where that widget is positioned?
978 This is where packing comes in.
980 <!-- ----------------------------------------------------------------- -->
981 <sect1>Theory of Packing Boxes
983 Most packing is done by creating boxes as in the example above. These
984 are invisible widget containers that we can pack our widgets into
985 which come in two forms, a horizontal box, and a vertical box. When
986 packing widgets into a horizontal box, the objects are inserted
987 horizontally from left to right or right to left depending on the call
988 used. In a vertical box, widgets are packed from top to bottom or vice
989 versa. You may use any combination of boxes inside or beside other
990 boxes to create the desired effect.
992 To create a new horizontal box, we use a call to gtk_hbox_new(), and
993 for vertical boxes, gtk_vbox_new().The gtk_box_pack_start() and
994 gtk_box_pack_end() functions are used to place objects inside of these
995 containers. The gtk_box_pack_start() function will start at the top
996 and work its way down in a vbox, and pack left to right in an hbox.
997 gtk_box_pack_end() will do the opposite, packing from bottom to top in
998 a vbox, and right to left in an hbox. Using these functions allow us
999 to right justify or left justify our widgets and may be mixed in any
1000 way to achieve the desired effect. We will use gtk_box_pack_start() in
1001 most of our examples. An object may be another container or a
1002 widget. In fact, many widgets are actually containers themselves,
1003 including the button, but we usually only use a label inside a button.
1005 By using these calls, GTK knows where you want to place your widgets
1006 so it can do automatic resizing and other nifty things. There's also a
1007 number of options as to how your widgets should be packed. As you can
1008 imagine, this method gives us a quite a bit of flexibility when
1009 placing and creating widgets.
1011 <!-- ----------------------------------------------------------------- -->
1012 <sect1>Details of Boxes
1014 Because of this flexibility, packing boxes in GTK can be confusing at
1015 first. There are a lot of options, and it's not immediately obvious how
1016 they all fit together. In the end however, there are basically five
1021 <IMG SRC="gtk_tut_packbox1.gif" VSPACE="15" HSPACE="10" WIDTH="528"
1022 HEIGHT="235" ALT="Box Packing Example Image">
1026 Each line contains one horizontal box (hbox) with several buttons. The
1027 call to gtk_box_pack is shorthand for the call to pack each of the
1028 buttons into the hbox. Each of the buttons is packed into the hbox the
1029 same way (i.e. same arguments to the gtk_box_pack_start() function).
1031 This is the declaration of the gtk_box_pack_start function.
1034 void gtk_box_pack_start( GtkBox *box,
1041 The first argument is the box you are packing the object into, the
1042 second is the object. The objects will all be buttons for now, so
1043 we'll be packing buttons into boxes.
1045 The expand argument to gtk_box_pack_start() and gtk_box_pack_end()
1046 controls whether the widgets are laid out in the box to fill in all
1047 the extra space in the box so the box is expanded to fill the area
1048 alloted to it (TRUE). Or the box is shrunk to just fit the widgets
1049 (FALSE). Setting expand to FALSE will allow you to do right and left
1050 justification of your widgets. Otherwise, they will all expand to fit
1051 into the box, and the same effect could be achieved by using only one
1052 of gtk_box_pack_start or gtk_box_pack_end.
1054 The fill argument to the gtk_box_pack functions control whether the
1055 extra space is allocated to the objects themselves (TRUE), or as extra
1056 padding in the box around these objects (FALSE). It only has an effect
1057 if the expand argument is also TRUE.
1059 When creating a new box, the function looks like this:
1062 GtkWidget *gtk_hbox_new (gint homogeneous,
1066 The homogeneous argument to gtk_hbox_new (and the same for
1067 gtk_vbox_new) controls whether each object in the box has the same
1068 size (i.e. the same width in an hbox, or the same height in a
1069 vbox). If it is set, the expand argument to the gtk_box_pack routines
1070 is always turned on.
1072 What's the difference between spacing (set when the box is created)
1073 and padding (set when elements are packed)? Spacing is added between
1074 objects, and padding is added on either side of an object. The
1075 following figure should make it clearer:
1079 <IMG ALIGN="center" SRC="gtk_tut_packbox2.gif" WIDTH="509"
1080 HEIGHT="213" VSPACE="15" HSPACE="10"
1081 ALT="Box Packing Example Image">
1085 Here is the code used to create the above images. I've commented it
1086 fairly heavily so hopefully you won't have any problems following
1087 it. Compile it yourself and play with it.
1089 <!-- ----------------------------------------------------------------- -->
1090 <sect1>Packing Demonstration Program
1093 /* example-start packbox packbox.c */
1096 #include "gtk/gtk.h"
1098 void delete_event( GtkWidget *widget,
1105 /* Make a new hbox filled with button-labels. Arguments for the
1106 * variables we're interested are passed in to this function.
1107 * We do not show the box, but do show everything inside. */
1108 GtkWidget *make_box( gint homogeneous,
1118 /* Create a new hbox with the appropriate homogeneous
1119 * and spacing settings */
1120 box = gtk_hbox_new (homogeneous, spacing);
1122 /* Create a series of buttons with the appropriate settings */
1123 button = gtk_button_new_with_label ("gtk_box_pack");
1124 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1125 gtk_widget_show (button);
1127 button = gtk_button_new_with_label ("(box,");
1128 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1129 gtk_widget_show (button);
1131 button = gtk_button_new_with_label ("button,");
1132 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1133 gtk_widget_show (button);
1135 /* Create a button with the label depending on the value of
1138 button = gtk_button_new_with_label ("TRUE,");
1140 button = gtk_button_new_with_label ("FALSE,");
1142 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1143 gtk_widget_show (button);
1145 /* This is the same as the button creation for "expand"
1146 * above, but uses the shorthand form. */
1147 button = gtk_button_new_with_label (fill ? "TRUE," : "FALSE,");
1148 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1149 gtk_widget_show (button);
1151 sprintf (padstr, "%d);", padding);
1153 button = gtk_button_new_with_label (padstr);
1154 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1155 gtk_widget_show (button);
1167 GtkWidget *separator;
1172 /* Our init, don't forget this! :) */
1173 gtk_init (&argc, &argv);
1176 fprintf (stderr, "usage: packbox num, where num is 1, 2, or 3.\n");
1177 /* This just does cleanup in GTK and exits with an exit status of 1. */
1181 which = atoi (argv[1]);
1183 /* Create our window */
1184 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1186 /* You should always remember to connect the destroy signal to the
1187 * main window. This is very important for proper intuitive
1189 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
1190 GTK_SIGNAL_FUNC (delete_event), NULL);
1191 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
1193 /* We create a vertical box (vbox) to pack the horizontal boxes into.
1194 * This allows us to stack the horizontal boxes filled with buttons one
1195 * on top of the other in this vbox. */
1196 box1 = gtk_vbox_new (FALSE, 0);
1198 /* which example to show. These correspond to the pictures above. */
1201 /* create a new label. */
1202 label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1204 /* Align the label to the left side. We'll discuss this function and
1205 * others in the section on Widget Attributes. */
1206 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1208 /* Pack the label into the vertical box (vbox box1). Remember that
1209 * widgets added to a vbox will be packed one on top of the other in
1211 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1213 /* Show the label */
1214 gtk_widget_show (label);
1216 /* Call our make box function - homogeneous = FALSE, spacing = 0,
1217 * expand = FALSE, fill = FALSE, padding = 0 */
1218 box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1219 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1220 gtk_widget_show (box2);
1222 /* Call our make box function - homogeneous = FALSE, spacing = 0,
1223 * expand = FALSE, fill = FALSE, padding = 0 */
1224 box2 = make_box (FALSE, 0, TRUE, FALSE, 0);
1225 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1226 gtk_widget_show (box2);
1228 /* Args are: homogeneous, spacing, expand, fill, padding */
1229 box2 = make_box (FALSE, 0, TRUE, TRUE, 0);
1230 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1231 gtk_widget_show (box2);
1233 /* Creates a separator, we'll learn more about these later,
1234 * but they are quite simple. */
1235 separator = gtk_hseparator_new ();
1237 /* Cack the separator into the vbox. Remember each of these
1238 * widgets are being packed into a vbox, so they'll be stacked
1240 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1241 gtk_widget_show (separator);
1243 /* Create another new label, and show it. */
1244 label = gtk_label_new ("gtk_hbox_new (TRUE, 0);");
1245 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1246 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1247 gtk_widget_show (label);
1249 /* Args are: homogeneous, spacing, expand, fill, padding */
1250 box2 = make_box (TRUE, 0, TRUE, FALSE, 0);
1251 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1252 gtk_widget_show (box2);
1254 /* Args are: homogeneous, spacing, expand, fill, padding */
1255 box2 = make_box (TRUE, 0, TRUE, TRUE, 0);
1256 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1257 gtk_widget_show (box2);
1259 /* Another new separator. */
1260 separator = gtk_hseparator_new ();
1261 /* The last 3 arguments to gtk_box_pack_start are:
1262 * expand, fill, padding. */
1263 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1264 gtk_widget_show (separator);
1270 /* Create a new label, remember box1 is a vbox as created
1271 * near the beginning of main() */
1272 label = gtk_label_new ("gtk_hbox_new (FALSE, 10);");
1273 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1274 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1275 gtk_widget_show (label);
1277 /* Args are: homogeneous, spacing, expand, fill, padding */
1278 box2 = make_box (FALSE, 10, TRUE, FALSE, 0);
1279 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1280 gtk_widget_show (box2);
1282 /* Args are: homogeneous, spacing, expand, fill, padding */
1283 box2 = make_box (FALSE, 10, TRUE, TRUE, 0);
1284 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1285 gtk_widget_show (box2);
1287 separator = gtk_hseparator_new ();
1288 /* The last 3 arguments to gtk_box_pack_start are:
1289 * expand, fill, padding. */
1290 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1291 gtk_widget_show (separator);
1293 label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1294 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1295 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1296 gtk_widget_show (label);
1298 /* Args are: homogeneous, spacing, expand, fill, padding */
1299 box2 = make_box (FALSE, 0, TRUE, FALSE, 10);
1300 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1301 gtk_widget_show (box2);
1303 /* Args are: homogeneous, spacing, expand, fill, padding */
1304 box2 = make_box (FALSE, 0, TRUE, TRUE, 10);
1305 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1306 gtk_widget_show (box2);
1308 separator = gtk_hseparator_new ();
1309 /* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */
1310 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1311 gtk_widget_show (separator);
1316 /* This demonstrates the ability to use gtk_box_pack_end() to
1317 * right justify widgets. First, we create a new box as before. */
1318 box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1320 /* Create the label that will be put at the end. */
1321 label = gtk_label_new ("end");
1322 /* Pack it using gtk_box_pack_end(), so it is put on the right
1323 * side of the hbox created in the make_box() call. */
1324 gtk_box_pack_end (GTK_BOX (box2), label, FALSE, FALSE, 0);
1325 /* Show the label. */
1326 gtk_widget_show (label);
1328 /* Pack box2 into box1 (the vbox remember ? :) */
1329 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1330 gtk_widget_show (box2);
1332 /* A separator for the bottom. */
1333 separator = gtk_hseparator_new ();
1334 /* This explicitly sets the separator to 400 pixels wide by 5 pixels
1335 * high. This is so the hbox we created will also be 400 pixels wide,
1336 * and the "end" label will be separated from the other labels in the
1337 * hbox. Otherwise, all the widgets in the hbox would be packed as
1338 * close together as possible. */
1339 gtk_widget_set_usize (separator, 400, 5);
1340 /* pack the separator into the vbox (box1) created near the start
1342 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1343 gtk_widget_show (separator);
1346 /* Create another new hbox.. remember we can use as many as we need! */
1347 quitbox = gtk_hbox_new (FALSE, 0);
1349 /* Our quit button. */
1350 button = gtk_button_new_with_label ("Quit");
1352 /* Setup the signal to destroy the window. Remember that this will send
1353 * the "destroy" signal to the window which will be caught by our signal
1354 * handler as defined above. */
1355 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
1356 GTK_SIGNAL_FUNC (gtk_main_quit),
1357 GTK_OBJECT (window));
1358 /* Pack the button into the quitbox.
1359 * The last 3 arguments to gtk_box_pack_start are:
1360 * expand, fill, padding. */
1361 gtk_box_pack_start (GTK_BOX (quitbox), button, TRUE, FALSE, 0);
1362 /* pack the quitbox into the vbox (box1) */
1363 gtk_box_pack_start (GTK_BOX (box1), quitbox, FALSE, FALSE, 0);
1365 /* Pack the vbox (box1) which now contains all our widgets, into the
1367 gtk_container_add (GTK_CONTAINER (window), box1);
1369 /* And show everything left */
1370 gtk_widget_show (button);
1371 gtk_widget_show (quitbox);
1373 gtk_widget_show (box1);
1374 /* Showing the window last so everything pops up at once. */
1375 gtk_widget_show (window);
1377 /* And of course, our main function. */
1380 /* Control returns here when gtk_main_quit() is called, but not when
1381 * gtk_exit is used. */
1388 <!-- ----------------------------------------------------------------- -->
1389 <sect1>Packing Using Tables
1391 Let's take a look at another way of packing - Tables. These can be
1392 extremely useful in certain situations.
1394 Using tables, we create a grid that we can place widgets in. The
1395 widgets may take up as many spaces as we specify.
1397 The first thing to look at of course, is the gtk_table_new function:
1400 GtkWidget *gtk_table_new( gint rows,
1405 The first argument is the number of rows to make in the table, while
1406 the second, obviously, is the number of columns.
1408 The homogeneous argument has to do with how the table's boxes are
1409 sized. If homogeneous is TRUE, the table boxes are resized to the size
1410 of the largest widget in the table. If homogeneous is FALSE, the size
1411 of a table boxes is dictated by the tallest widget in its same row,
1412 and the widest widget in its column.
1414 The rows and columns are laid out from 0 to n, where n was the number
1415 specified in the call to gtk_table_new. So, if you specify rows = 2
1416 and columns = 2, the layout would look something like this:
1420 0+----------+----------+
1422 1+----------+----------+
1424 2+----------+----------+
1427 Note that the coordinate system starts in the upper left hand corner.
1428 To place a widget into a box, use the following function:
1431 void gtk_table_attach( GtkTable *table,
1443 Where the first argument ("table") is the table you've created and the
1444 second ("child") the widget you wish to place in the table.
1446 The left and right attach arguments specify where to place the widget,
1447 and how many boxes to use. If you want a button in the lower right
1448 table entry of our 2x2 table, and want it to fill that entry ONLY,
1449 left_attach would be = 1, right_attach = 2, top_attach = 1,
1452 Now, if you wanted a widget to take up the whole top row of our 2x2
1453 table, you'd use left_attach = 0, right_attach = 2, top_attach = 0,
1456 The xoptions and yoptions are used to specify packing options and may
1457 be bitwise OR'ed together to allow multiple options.
1461 <item>GTK_FILL - If the table box is larger than the widget, and
1462 GTK_FILL is specified, the widget will expand to use all the room
1465 <item>GTK_SHRINK - If the table widget was allocated less space then
1466 was requested (usually by the user resizing the window), then the
1467 widgets would normally just be pushed off the bottom of the window and
1468 disappear. If GTK_SHRINK is specified, the widgets will shrink with
1471 <item>GTK_EXPAND - This will cause the table to expand to use up any
1472 remaining space in the window.
1475 Padding is just like in boxes, creating a clear area around the widget
1476 specified in pixels.
1478 gtk_table_attach() has a LOT of options. So, there's a shortcut:
1481 void gtk_table_attach_defaults( GtkTable *table,
1486 gint bottom_attach );
1489 The X and Y options default to GTK_FILL | GTK_EXPAND, and X and Y
1490 padding are set to 0. The rest of the arguments are identical to the
1493 We also have gtk_table_set_row_spacing() and
1494 gtk_table_set_col_spacing(). This places spacing between the rows at
1495 the specified row or column.
1498 void gtk_table_set_row_spacing( GtkTable *table,
1506 void gtk_table_set_col_spacing ( GtkTable *table,
1511 Note that for columns, the space goes to the right of the column, and
1512 for rows, the space goes below the row.
1514 You can also set a consistent spacing of all rows and/or columns with:
1517 void gtk_table_set_row_spacings( GtkTable *table,
1524 void gtk_table_set_col_spacings( GtkTable *table,
1528 Note that with these calls, the last row and last column do not get
1531 <!-- ----------------------------------------------------------------- -->
1532 <sect1>Table Packing Example
1534 Here we make a window with three buttons in a 2x2 table.
1535 The first two buttons will be placed in the upper row.
1536 A third, quit button, is placed in the lower row, spanning both columns.
1537 Which means it should look something like this:
1541 <IMG SRC="gtk_tut_table.gif" VSPACE="15" HSPACE="10"
1542 ALT="Table Packing Example Image" WIDTH="180" HEIGHT="120">
1546 Here's the source code:
1549 /* example-start table table.c */
1551 #include <gtk/gtk.h>
1554 * The data passed to this function is printed to stdout */
1555 void callback( GtkWidget *widget,
1558 g_print ("Hello again - %s was pressed\n", (char *) data);
1561 /* This callback quits the program */
1562 void delete_event( GtkWidget *widget,
1576 gtk_init (&argc, &argv);
1578 /* Create a new window */
1579 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1581 /* Set the window title */
1582 gtk_window_set_title (GTK_WINDOW (window), "Table");
1584 /* Set a handler for delete_event that immediately
1586 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
1587 GTK_SIGNAL_FUNC (delete_event), NULL);
1589 /* Sets the border width of the window. */
1590 gtk_container_set_border_width (GTK_CONTAINER (window), 20);
1592 /* Create a 2x2 table */
1593 table = gtk_table_new (2, 2, TRUE);
1595 /* Put the table in the main window */
1596 gtk_container_add (GTK_CONTAINER (window), table);
1598 /* Create first button */
1599 button = gtk_button_new_with_label ("button 1");
1601 /* When the button is clicked, we call the "callback" function
1602 * with a pointer to "button 1" as its argument */
1603 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1604 GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");
1607 /* Insert button 1 into the upper left quadrant of the table */
1608 gtk_table_attach_defaults (GTK_TABLE(table), button, 0, 1, 0, 1);
1610 gtk_widget_show (button);
1612 /* Create second button */
1614 button = gtk_button_new_with_label ("button 2");
1616 /* When the button is clicked, we call the "callback" function
1617 * with a pointer to "button 2" as its argument */
1618 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1619 GTK_SIGNAL_FUNC (callback), (gpointer) "button 2");
1620 /* Insert button 2 into the upper right quadrant of the table */
1621 gtk_table_attach_defaults (GTK_TABLE(table), button, 1, 2, 0, 1);
1623 gtk_widget_show (button);
1625 /* Create "Quit" button */
1626 button = gtk_button_new_with_label ("Quit");
1628 /* When the button is clicked, we call the "delete_event" function
1629 * and the program exits */
1630 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1631 GTK_SIGNAL_FUNC (delete_event), NULL);
1633 /* Insert the quit button into the both
1634 * lower quadrants of the table */
1635 gtk_table_attach_defaults (GTK_TABLE(table), button, 0, 2, 1, 2);
1637 gtk_widget_show (button);
1639 gtk_widget_show (table);
1640 gtk_widget_show (window);
1649 <!-- ***************************************************************** -->
1650 <sect>Widget Overview
1651 <!-- ***************************************************************** -->
1653 The general steps to creating a widget in GTK are:
1655 <item> gtk_*_new - one of various functions to create a new widget.
1656 These are all detailed in this section.
1658 <item> Connect all signals and events we wish to use to the
1659 appropriate handlers.
1661 <item> Set the attributes of the widget.
1663 <item> Pack the widget into a container using the appropriate call
1664 such as gtk_container_add() or gtk_box_pack_start().
1666 <item> gtk_widget_show() the widget.
1669 gtk_widget_show() lets GTK know that we are done setting the
1670 attributes of the widget, and it is ready to be displayed. You may
1671 also use gtk_widget_hide to make it disappear again. The order in
1672 which you show the widgets is not important, but I suggest showing the
1673 window last so the whole window pops up at once rather than seeing the
1674 individual widgets come up on the screen as they're formed. The
1675 children of a widget (a window is a widget too) will not be displayed
1676 until the window itself is shown using the gtk_widget_show() function.
1678 <!-- ----------------------------------------------------------------- -->
1681 You'll notice as you go on, that GTK uses a type casting system. This
1682 is always done using macros that both test the ability to cast the
1683 given item, and perform the cast. Some common ones you will see are:
1686 <item> GTK_WIDGET(widget)
1687 <item> GTK_OBJECT(object)
1688 <item> GTK_SIGNAL_FUNC(function)
1689 <item> GTK_CONTAINER(container)
1690 <item> GTK_WINDOW(window)
1694 These are all used to cast arguments in functions. You'll see them in the
1695 examples, and can usually tell when to use them simply by looking at the
1696 function's declaration.
1698 As you can see below in the class hierarchy, all GtkWidgets are
1699 derived from the GtkObject base class. This means you can use a widget
1700 in any place the function asks for an object - simply use the
1706 gtk_signal_connect( GTK_OBJECT(button), "clicked",
1707 GTK_SIGNAL_FUNC(callback_function), callback_data);
1710 This casts the button into an object, and provides a cast for the
1711 function pointer to the callback.
1713 Many widgets are also containers. If you look in the class hierarchy
1714 below, you'll notice that many widgets derive from the GtkContainer
1715 class. Any one of these widgets may be used with the GTK_CONTAINER
1716 macro to pass them to functions that ask for containers.
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 GtkEventBox. 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 The Button widget has the following signals:
2002 <!-- ----------------------------------------------------------------- -->
2003 <sect1> Toggle Buttons
2005 Toggle buttons are derived from normal buttons and are very similar,
2006 except they will always be in one of two states, alternated by a
2007 click. They may be depressed, and when you click again, they will pop
2008 back up. Click again, and they will pop back down.
2010 Toggle buttons are the basis for check buttons and radio buttons, as
2011 such, many of the calls used for toggle buttons are inherited by radio
2012 and check buttons. I will point these out when we come to them.
2014 Creating a new toggle button:
2017 GtkWidget *gtk_toggle_button_new( void );
2019 GtkWidget *gtk_toggle_button_new_with_label( gchar *label );
2022 As you can imagine, these work identically to the normal button widget
2023 calls. The first creates a blank toggle button, and the second, a
2024 button with a label widget already packed into it.
2026 To retrieve the state of the toggle widget, including radio and check
2027 buttons, we use a GTK macro as shown in our example below. This tests
2028 the state of the toggle in a callback. The signal of interest emitted
2029 to us by toggle buttons (the toggle button, check button, and radio
2030 button widgets), is the "toggled" signal. To check the state of these
2031 buttons, set up a signal handler to catch the toggled signal, and use
2032 the macro to determine its state. The callback will look something
2036 void toggle_button_callback (GtkWidget *widget, gpointer data)
2038 if (GTK_TOGGLE_BUTTON (widget)->active)
2040 /* If control reaches here, the toggle button is down */
2044 /* If control reaches here, the toggle button is up */
2050 void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,
2054 The above call can be used to set the state of the toggle button, and
2055 its children the radio and check buttons. Passing in your created
2056 button as the first argument, and a TRUE or FALSE for the second state
2057 argument to specify whether it should be down (depressed) or up
2058 (released). Default is up, or FALSE.
2060 Note that when you use the gtk_toggle_button_set_active() function, and
2061 the state is actually changed, it causes the "clicked" signal to be
2062 emitted from the button.
2065 void gtk_toggle_button_toggled (GtkToggleButton *toggle_button);
2068 This simply toggles the button, and emits the "toggled" signal.
2070 <!-- ----------------------------------------------------------------- -->
2071 <sect1> Check Buttons
2073 Check buttons inherent many properties and functions from the the
2074 toggle buttons above, but look a little different. Rather than being
2075 buttons with text inside them, they are small squares with the text to
2076 the right of them. These are often used for toggling options on and
2077 off in applications.
2079 The two creation functions are similar to those of the normal button.
2082 GtkWidget *gtk_check_button_new( void );
2084 GtkWidget *gtk_check_button_new_with_label ( gchar *label );
2087 The new_with_label function creates a check button with a label beside
2090 Checking the state of the check button is identical to that of the
2093 <!-- ----------------------------------------------------------------- -->
2094 <sect1> Radio Buttons <label id="sec_Radio_Buttons">
2096 Radio buttons are similar to check buttons except they are grouped so
2097 that only one may be selected/depressed at a time. This is good for
2098 places in your application where you need to select from a short list
2101 Creating a new radio button is done with one of these calls:
2104 GtkWidget *gtk_radio_button_new( GSList *group );
2106 GtkWidget *gtk_radio_button_new_with_label( GSList *group,
2110 You'll notice the extra argument to these calls. They require a group
2111 to perform their duty properly. The first call to
2112 gtk_radio_button_new_with_label or gtk_radio_button_new_with_label
2113 should pass NULL as the first argument. Then create a group using:
2116 GSList *gtk_radio_button_group( GtkRadioButton *radio_button );
2119 The important thing to remember is that gtk_radio_button_group must be
2120 called for each new button added to the group, with the previous
2121 button passed in as an argument. The result is then passed into the
2122 call to gtk_radio_button_new or gtk_radio_button_new_with_label. This
2123 allows a chain of buttons to be established. The example below should
2126 You can shorten this slightly by using the following syntax, which
2127 removes the need for a variable to hold the list of buttons. This form
2128 is used in the example to create the third button:
2131 button2 = gtk_radio_button_new_with_label(
2132 gtk_radio_button_group (GTK_RADIO_BUTTON (button1)),
2136 It is also a good idea to explicitly set which button should be the
2137 default depressed button with:
2140 void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,
2144 This is described in the section on toggle buttons, and works in
2145 exactly the same way.
2147 The following example creates a radio button group with three buttons.
2150 /* example-start radiobuttons radiobuttons.c */
2152 #include <gtk/gtk.h>
2155 void close_application( GtkWidget *widget,
2165 GtkWidget *window = NULL;
2169 GtkWidget *separator;
2172 gtk_init(&argc,&argv);
2174 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2176 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
2177 GTK_SIGNAL_FUNC(close_application),
2180 gtk_window_set_title (GTK_WINDOW (window), "radio buttons");
2181 gtk_container_set_border_width (GTK_CONTAINER (window), 0);
2183 box1 = gtk_vbox_new (FALSE, 0);
2184 gtk_container_add (GTK_CONTAINER (window), box1);
2185 gtk_widget_show (box1);
2187 box2 = gtk_vbox_new (FALSE, 10);
2188 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2189 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2190 gtk_widget_show (box2);
2192 button = gtk_radio_button_new_with_label (NULL, "button1");
2193 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2194 gtk_widget_show (button);
2196 group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
2197 button = gtk_radio_button_new_with_label(group, "button2");
2198 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2199 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2200 gtk_widget_show (button);
2202 button = gtk_radio_button_new_with_label(
2203 gtk_radio_button_group (GTK_RADIO_BUTTON (button)),
2205 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2206 gtk_widget_show (button);
2208 separator = gtk_hseparator_new ();
2209 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
2210 gtk_widget_show (separator);
2212 box2 = gtk_vbox_new (FALSE, 10);
2213 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2214 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
2215 gtk_widget_show (box2);
2217 button = gtk_button_new_with_label ("close");
2218 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2219 GTK_SIGNAL_FUNC(close_application),
2220 GTK_OBJECT (window));
2221 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2222 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
2223 gtk_widget_grab_default (button);
2224 gtk_widget_show (button);
2225 gtk_widget_show (window);
2234 <!-- TODO: check out gtk_radio_button_new_from_widget function - TRG -->
2236 <!-- ***************************************************************** -->
2237 <sect> Adjustments <label id="sec_Adjustment">
2238 <!-- ***************************************************************** -->
2240 GTK+ has various widgets that can be visually adjusted by the user
2241 using the mouse or the keyboard, such as the range widgets, described
2242 in the <ref id="sec_Range_Widgets" name="Range Widgets">
2243 section. There are also a few widgets that display some adjustable
2244 portion of a larger area of data, such as the text widget and the
2247 Obviously, an application needs to be able to react to changes the
2248 user makes in range widgets. One way to do this would be to have each
2249 widget emit its own type of signal when its adjustment changes, and
2250 either pass the new value to the signal handler, or require it to look
2251 inside the widget's data structure in order to ascertain the value.
2252 But you may also want to connect the adjustments of several widgets
2253 together, so that adjusting one adjusts the others. The most obvious
2254 example of this is connecting a scrollbar to a panning viewport or a
2255 scrolling text area. If each widget has its own way of setting or
2256 getting the adjustment value, then the programmer may have to write
2257 their own signal handlers to translate between the output of one
2258 widget's signal and the "input" of another's adjustment setting
2261 GTK+ solves this problem using the GtkAdjustment object, which is a
2262 way for widgets to store and pass adjustment information in an
2263 abstract and flexible form. The most obvious use of GtkAdjustment is
2264 to store the configuration parameters and values of range widgets,
2265 such as scrollbars and scale controls. However, since GtkAdjustments
2266 are derived from GtkObject, they have some special powers beyond those
2267 of normal data structures. Most importantly, they can emit signals,
2268 just like widgets, and these signals can be used not only to allow
2269 your program to react to user input on adjustable widgets, but also to
2270 propagate adjustment values transparently between adjustable widgets.
2272 <sect1> Creating an Adjustment
2274 You create an adjustment using:
2277 GtkObject *gtk_adjustment_new( gfloat value,
2280 gfloat step_increment,
2281 gfloat page_increment,
2285 The <tt/value/ argument is the initial value you want to give to the
2286 adjustment, usually corresponding to the topmost or leftmost position
2287 of an adjustable widget. The <tt/lower/ argument specifies the lowest
2288 value which the adjustment can hold. The <tt/step_increment/ argument
2289 specifies the "smaller" of the two increments by which the user can
2290 change the value, while the <tt/page_increment/ is the "larger" one.
2291 The <tt/page_size/ argument usually corresponds somehow to the visible
2292 area of a panning widget. The <tt/upper/ argument is used to represent
2293 the bottom most or right most coordinate in a panning widget's
2294 child. Therefore it is <em/not/ always the largest number that
2295 <tt/value/ can take, since the <tt/page_size/ of such widgets is
2298 <!-- ----------------------------------------------------------------- -->
2299 <sect1> Using Adjustments the Easy Way
2301 The adjustable widgets can be roughly divided into those which use and
2302 require specific units for these values and those which treat them as
2303 arbitrary numbers. The group which treats the values as arbitrary
2304 numbers includes the range widgets (scrollbars and scales, the
2305 progress bar widget, and the spin button widget). These widgets are
2306 all the widgets which are typically "adjusted" directly by the user
2307 with the mouse or keyboard. They will treat the <tt/lower/ and
2308 <tt/upper/ values of an adjustment as a range within which the user
2309 can manipulate the adjustment's <tt/value/. By default, they will only
2310 modify the <tt/value/ of an adjustment.
2312 The other group includes the text widget, the viewport widget, the
2313 compound list widget, and the scrolled window widget. All of these
2314 widgets use pixel values for their adjustments. These are also all
2315 widgets which are typically "adjusted" indirectly using scrollbars.
2316 While all widgets which use adjustments can either create their own
2317 adjustments or use ones you supply, you'll generally want to let this
2318 particular category of widgets create its own adjustments. Usually,
2319 they will eventually override all the values except the <tt/value/
2320 itself in whatever adjustments you give them, but the results are, in
2321 general, undefined (meaning, you'll have to read the source code to
2322 find out, and it may be different from widget to widget).
2324 Now, you're probably thinking, since text widgets and viewports insist
2325 on setting everything except the <tt/value/ of their adjustments,
2326 while scrollbars will <em/only/ touch the adjustment's <tt/value/, if
2327 you <em/share/ an adjustment object between a scrollbar and a text
2328 widget, manipulating the scrollbar will automagically adjust the text
2329 widget? Of course it will! Just like this:
2332 /* creates its own adjustments */
2333 text = gtk_text_new (NULL, NULL);
2334 /* uses the newly-created adjustment for the scrollbar as well */
2335 vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
2339 <!-- ----------------------------------------------------------------- -->
2340 <sect1> Adjustment Internals
2342 Ok, you say, that's nice, but what if I want to create my own handlers
2343 to respond when the user adjusts a range widget or a spin button, and
2344 how do I get at the value of the adjustment in these handlers? To
2345 answer these questions and more, let's start by taking a look at
2346 <tt>struct _GtkAdjustment</tt> itself:
2349 struct _GtkAdjustment
2356 gfloat step_increment;
2357 gfloat page_increment;
2362 The first thing you should know is that there aren't any handy-dandy
2363 macros or accessor functions for getting the <tt/value/ out of a
2364 GtkAdjustment, so you'll have to (horror of horrors) do it like a
2365 <em/real/ C programmer. Don't worry - the <tt>GTK_ADJUSTMENT
2366 (Object)</tt> macro does run-time type checking (as do all the GTK+
2367 type-casting macros, actually).
2369 Since, when you set the <tt/value/ of an adjustment, you generally
2370 want the change to be reflected by every widget that uses this
2371 adjustment, GTK+ provides this convenience function to do this:
2374 void gtk_adjustment_set_value( GtkAdjustment *adjustment,
2378 As mentioned earlier, GtkAdjustment is a subclass of GtkObject just
2379 like all the various widgets, and thus it is able to emit signals.
2380 This is, of course, why updates happen automagically when you share an
2381 adjustment object between a scrollbar and another adjustable widget;
2382 all adjustable widgets connect signal handlers to their adjustment's
2383 <tt/value_changed/ signal, as can your program. Here's the definition
2384 of this signal in <tt/struct _GtkAdjustmentClass/:
2387 void (* value_changed) (GtkAdjustment *adjustment);
2390 The various widgets that use the GtkAdjustment object will emit this
2391 signal on an adjustment whenever they change its value. This happens
2392 both when user input causes the slider to move on a range widget, as
2393 well as when the program explicitly changes the value with
2394 <tt/gtk_adjustment_set_value()/. So, for example, if you have a scale
2395 widget, and you want to change the rotation of a picture whenever its
2396 value changes, you would create a callback like this:
2399 void cb_rotate_picture (GtkAdjustment *adj, GtkWidget *picture)
2401 set_picture_rotation (picture, adj->value);
2405 and connect it to the scale widget's adjustment like this:
2408 gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
2409 GTK_SIGNAL_FUNC (cb_rotate_picture), picture);
2412 What about when a widget reconfigures the <tt/upper/ or <tt/lower/
2413 fields of its adjustment, such as when a user adds more text to a text
2414 widget? In this case, it emits the <tt/changed/ signal, which looks
2418 void (* changed) (GtkAdjustment *adjustment);
2421 Range widgets typically connect a handler to this signal, which
2422 changes their appearance to reflect the change - for example, the size
2423 of the slider in a scrollbar will grow or shrink in inverse proportion
2424 to the difference between the <tt/lower/ and <tt/upper/ values of its
2427 You probably won't ever need to attach a handler to this signal,
2428 unless you're writing a new type of range widget. However, if you
2429 change any of the values in a GtkAdjustment directly, you should emit
2430 this signal on it to reconfigure whatever widgets are using it, like
2434 gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");
2437 Now go forth and adjust!
2441 <!-- ***************************************************************** -->
2442 <sect> Range Widgets<label id="sec_Range_Widgets">
2443 <!-- ***************************************************************** -->
2446 The category of range widgets includes the ubiquitous scrollbar widget
2447 and the less common "scale" widget. Though these two types of widgets
2448 are generally used for different purposes, they are quite similar in
2449 function and implementation. All range widgets share a set of common
2450 graphic elements, each of which has its own X window and receives
2451 events. They all contain a "trough" and a "slider" (what is sometimes
2452 called a "thumbwheel" in other GUI environments). Dragging the slider
2453 with the pointer moves it back and forth within the trough, while
2454 clicking in the trough advances the slider towards the location of the
2455 click, either completely, or by a designated amount, depending on
2456 which mouse button is used.
2458 As mentioned in <ref id="sec_Adjustment" name="Adjustments"> above,
2459 all range widgets are associated with an adjustment object, from which
2460 they calculate the length of the slider and its position within the
2461 trough. When the user manipulates the slider, the range widget will
2462 change the value of the adjustment.
2464 <!-- ----------------------------------------------------------------- -->
2465 <sect1> Scrollbar Widgets
2467 These are your standard, run-of-the-mill scrollbars. These should be
2468 used only for scrolling some other widget, such as a list, a text box,
2469 or a viewport (and it's generally easier to use the scrolled window
2470 widget in most cases). For other purposes, you should use scale
2471 widgets, as they are friendlier and more featureful.
2473 There are separate types for horizontal and vertical scrollbars.
2474 There really isn't much to say about these. You create them with the
2475 following functions, defined in <tt><gtk/gtkhscrollbar.h></tt>
2476 and <tt><gtk/gtkvscrollbar.h></tt>:
2479 GtkWidget *gtk_hscrollbar_new( GtkAdjustment *adjustment );
2481 GtkWidget *gtk_vscrollbar_new( GtkAdjustment *adjustment );
2484 and that's about it (if you don't believe me, look in the header
2485 files!). The <tt/adjustment/ argument can either be a pointer to an
2486 existing GtkAdjustment, or NULL, in which case one will be created for
2487 you. Specifying NULL might actually be useful in this case, if you
2488 wish to pass the newly-created adjustment to the constructor function
2489 of some other widget which will configure it for you, such as a text
2493 <!-- ----------------------------------------------------------------- -->
2494 <sect1> Scale Widgets
2496 Scale widgets are used to allow the user to visually select and
2497 manipulate a value within a specific range. You might want to use a
2498 scale widget, for example, to adjust the magnification level on a
2499 zoomed preview of a picture, or to control the brightness of a colour,
2500 or to specify the number of minutes of inactivity before a screensaver
2501 takes over the screen.
2503 <!-- ----------------------------------------------------------------- -->
2504 <sect2>Creating a Scale Widget
2506 As with scrollbars, there are separate widget types for horizontal and
2507 vertical scale widgets. (Most programmers seem to favour horizontal
2508 scale widgets). Since they work essentially the same way, there's no
2509 need to treat them separately here. The following functions, defined
2510 in <tt><gtk/gtkvscale.h></tt> and
2511 <tt><gtk/gtkhscale.h></tt>, create vertical and horizontal scale
2512 widgets, respectively:
2516 GtkWidget *gtk_vscale_new( GtkAdjustment *adjustment );
2518 GtkWidget *gtk_hscale_new( GtkAdjustment *adjustment );
2522 The <tt/adjustment/ argument can either be an adjustment which has
2523 already been created with <tt/gtk_adjustment_new()/, or <tt/NULL/, in
2524 which case, an anonymous GtkAdjustment is created with all of its
2525 values set to <tt/0.0/ (which isn't very useful in this case). In
2526 order to avoid confusing yourself, you probably want to create your
2527 adjustment with a <tt/page_size/ of <tt/0.0/ so that its <tt/upper/
2528 value actually corresponds to the highest value the user can select.
2529 (If you're <em/already/ thoroughly confused, read the section on <ref
2530 id="sec_Adjustment" name="Adjustments"> again for an explanation of
2531 what exactly adjustments do and how to create and manipulate them).
2533 <!-- ----------------------------------------------------------------- -->
2534 <sect2> Functions and Signals (well, functions, at least)
2536 Scale widgets can display their current value as a number beside the
2537 trough. The default behaviour is to show the value, but you can change
2538 this with this function:
2541 void gtk_scale_set_draw_value( GtkScale *scale,
2545 As you might have guessed, <tt/draw_value/ is either <tt/TRUE/ or
2546 <tt/FALSE/, with predictable consequences for either one.
2548 The value displayed by a scale widget is rounded to one decimal point
2549 by default, as is the <tt/value/ field in its GtkAdjustment. You can
2554 void gtk_scale_set_digits( GtkScale *scale,
2559 where <tt/digits/ is the number of decimal places you want. You can
2560 set <tt/digits/ to anything you like, but no more than 13 decimal
2561 places will actually be drawn on screen.
2563 Finally, the value can be drawn in different positions
2564 relative to the trough:
2568 void gtk_scale_set_value_pos( GtkScale *scale,
2569 GtkPositionType pos );
2573 The argument <tt/pos/ is of type <tt>GtkPositionType</tt>, which is
2574 defined in <tt><gtk/gtkenums.h></tt>, and can take one of the
2579 <item> GTK_POS_RIGHT
2581 <item> GTK_POS_BOTTOM
2584 If you position the value on the "side" of the trough (e.g. on the top
2585 or bottom of a horizontal scale widget), then it will follow the
2586 slider up and down the trough.
2588 All the preceding functions are defined in
2589 <tt><gtk/gtkscale.h></tt>.
2593 <!-- ----------------------------------------------------------------- -->
2594 <sect1> Common Functions <label id="sec_Range_Functions">
2596 The GtkRange widget class is fairly complicated internally, but, like
2597 all the "base class" widgets, most of its complexity is only
2598 interesting if you want to hack on it. Also, almost all of the
2599 functions and signals it defines are only really used in writing
2600 derived widgets. There are, however, a few useful functions that are
2601 defined in <tt><gtk/gtkrange.h></tt> and will work on all range
2604 <!-- ----------------------------------------------------------------- -->
2605 <sect2> Setting the Update Policy
2607 The "update policy" of a range widget defines at what points during
2608 user interaction it will change the <tt/value/ field of its
2609 GtkAdjustment and emit the "value_changed" signal on this
2610 GtkAdjustment. The update policies, defined in
2611 <tt><gtk/gtkenums.h></tt> as type <tt>enum GtkUpdateType</tt>,
2615 <item>GTK_UPDATE_POLICY_CONTINUOUS - This is the default. The
2616 "value_changed" signal is emitted continuously, i.e. whenever the
2617 slider is moved by even the tiniest amount.
2619 <item>GTK_UPDATE_POLICY_DISCONTINUOUS - The "value_changed" signal is
2620 only emitted once the slider has stopped moving and the user has
2621 released the mouse button.
2623 <item>GTK_UPDATE_POLICY_DELAYED - The "value_change" signal is emitted
2624 when the user releases the mouse button, or if the slider stops moving
2625 for a short period of time.
2629 The update policy of a range widget can be set by casting it using the
2630 <tt>GTK_RANGE (Widget)</tt> macro and passing it to this function:
2633 void gtk_range_set_update_policy( GtkRange *range,
2634 GtkUpdateType policy) ;
2637 <!-- ----------------------------------------------------------------- -->
2638 <sect2>Getting and Setting Adjustments
2640 Getting and setting the adjustment for a range widget "on the fly" is
2641 done, predictably, with:
2644 GtkAdjustment* gtk_range_get_adjustment( GtkRange *range );
2646 void gtk_range_set_adjustment( GtkRange *range,
2647 GtkAdjustment *adjustment );
2650 <tt/gtk_range_get_adjustment()/ returns a pointer to the adjustment to
2651 which <tt/range/ is connected.
2653 <tt/gtk_range_set_adjustment()/ does absolutely nothing if you pass it
2654 the adjustment that <tt/range/ is already using, regardless of whether
2655 you changed any of its fields or not. If you pass it a new
2656 GtkAdjustment, it will unreference the old one if it exists (possibly
2657 destroying it), connect the appropriate signals to the new one, and
2658 call the private function <tt/gtk_range_adjustment_changed()/, which
2659 will (or at least, is supposed to...) recalculate the size and/or
2660 position of the slider and redraw if necessary. As mentioned in the
2661 section on adjustments, if you wish to reuse the same GtkAdjustment,
2662 when you modify its values directly, you should emit the "changed"
2663 signal on it, like this:
2666 gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");
2671 <!-- ----------------------------------------------------------------- -->
2672 <sect1> Key and Mouse bindings
2674 All of the GTK+ range widgets react to mouse clicks in more or less
2675 the same way. Clicking button-1 in the trough will cause its
2676 adjustment's <tt/page_increment/ to be added or subtracted from its
2677 <tt/value/, and the slider to be moved accordingly. Clicking mouse
2678 button-2 in the trough will jump the slider to the point at which the
2679 button was clicked. Clicking any button on a scrollbar's arrows will
2680 cause its adjustment's value to change <tt/step_increment/ at a time.
2682 It may take a little while to get used to, but by default, scrollbars
2683 as well as scale widgets can take the keyboard focus in GTK+. If you
2684 think your users will find this too confusing, you can always disable
2685 this by unsetting the GTK_CAN_FOCUS flag on the scrollbar, like this:
2688 GTK_WIDGET_UNSET_FLAGS (scrollbar, GTK_CAN_FOCUS);
2691 The key bindings (which are, of course, only active when the widget
2692 has focus) are slightly different between horizontal and vertical
2693 range widgets, for obvious reasons. They are also not quite the same
2694 for scale widgets as they are for scrollbars, for somewhat less
2695 obvious reasons (possibly to avoid confusion between the keys for
2696 horizontal and vertical scrollbars in scrolled windows, where both
2697 operate on the same area).
2699 <sect2> Vertical Range Widgets
2701 All vertical range widgets can be operated with the up and down arrow
2702 keys, as well as with the <tt/Page Up/ and <tt/Page Down/ keys. The
2703 arrows move the slider up and down by <tt/step_increment/, while
2704 <tt/Page Up/ and <tt/Page Down/ move it by <tt/page_increment/.
2706 The user can also move the slider all the way to one end or the other
2707 of the trough using the keyboard. With the GtkVScale widget, this is
2708 done with the <tt/Home/ and <tt/End/ keys, whereas with the
2709 GtkVScrollbar widget, this is done by typing <tt>Control-Page Up</tt>
2710 and <tt>Control-Page Down</tt>.
2712 <!-- ----------------------------------------------------------------- -->
2713 <sect2> Horizontal Range Widgets
2715 The left and right arrow keys work as you might expect in these
2716 widgets, moving the slider back and forth by <tt/step_increment/. The
2717 <tt/Home/ and <tt/End/ keys move the slider to the ends of the trough.
2718 For the GtkHScale widget, moving the slider by <tt/page_increment/ is
2719 accomplished with <tt>Control-Left</tt> and <tt>Control-Right</tt>,
2720 while for GtkHScrollbar, it's done with <tt>Control-Home</tt> and
2721 <tt>Control-End</tt>.
2725 <!-- ----------------------------------------------------------------- -->
2726 <sect1> Example<label id="sec_Range_Example">
2728 This example is a somewhat modified version of the "range controls"
2729 test from <tt/testgtk.c/. It basically puts up a window with three
2730 range widgets all connected to the same adjustment, and a couple of
2731 controls for adjusting some of the parameters mentioned above and in
2732 the seciton on adjustments, so you can see how they affect the way
2733 these widgets work for the user.
2736 /* example-start rangewidgets rangewidgets.c */
2738 #include <gtk/gtk.h>
2740 GtkWidget *hscale, *vscale;
2742 void cb_pos_menu_select( GtkWidget *item,
2743 GtkPositionType pos )
2745 /* Set the value position on both scale widgets */
2746 gtk_scale_set_value_pos (GTK_SCALE (hscale), pos);
2747 gtk_scale_set_value_pos (GTK_SCALE (vscale), pos);
2750 void cb_update_menu_select( GtkWidget *item,
2751 GtkUpdateType policy )
2753 /* Set the update policy for both scale widgets */
2754 gtk_range_set_update_policy (GTK_RANGE (hscale), policy);
2755 gtk_range_set_update_policy (GTK_RANGE (vscale), policy);
2758 void cb_digits_scale( GtkAdjustment *adj )
2760 /* Set the number of decimal places to which adj->value is rounded */
2761 gtk_scale_set_digits (GTK_SCALE (hscale), (gint) adj->value);
2762 gtk_scale_set_digits (GTK_SCALE (vscale), (gint) adj->value);
2765 void cb_page_size( GtkAdjustment *get,
2766 GtkAdjustment *set )
2768 /* Set the page size and page increment size of the sample
2769 * adjustment to the value specified by the "Page Size" scale */
2770 set->page_size = get->value;
2771 set->page_increment = get->value;
2772 /* Now emit the "changed" signal to reconfigure all the widgets that
2773 * are attached to this adjustment */
2774 gtk_signal_emit_by_name (GTK_OBJECT (set), "changed");
2777 void cb_draw_value( GtkToggleButton *button )
2779 /* Turn the value display on the scale widgets off or on depending
2780 * on the state of the checkbutton */
2781 gtk_scale_set_draw_value (GTK_SCALE (hscale), button->active);
2782 gtk_scale_set_draw_value (GTK_SCALE (vscale), button->active);
2785 /* Convenience functions */
2787 GtkWidget *make_menu_item( gchar *name,
2788 GtkSignalFunc callback,
2793 item = gtk_menu_item_new_with_label (name);
2794 gtk_signal_connect (GTK_OBJECT (item), "activate",
2796 gtk_widget_show (item);
2801 void scale_set_default_values( GtkScale *scale )
2803 gtk_range_set_update_policy (GTK_RANGE (scale),
2804 GTK_UPDATE_CONTINUOUS);
2805 gtk_scale_set_digits (scale, 1);
2806 gtk_scale_set_value_pos (scale, GTK_POS_TOP);
2807 gtk_scale_set_draw_value (scale, TRUE);
2810 /* makes the sample window */
2812 void create_range_controls( void )
2815 GtkWidget *box1, *box2, *box3;
2817 GtkWidget *scrollbar;
2818 GtkWidget *separator;
2819 GtkWidget *opt, *menu, *item;
2822 GtkObject *adj1, *adj2;
2824 /* Standard window-creating stuff */
2825 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2826 gtk_signal_connect (GTK_OBJECT (window), "destroy",
2827 GTK_SIGNAL_FUNC(gtk_main_quit),
2829 gtk_window_set_title (GTK_WINDOW (window), "range controls");
2831 box1 = gtk_vbox_new (FALSE, 0);
2832 gtk_container_add (GTK_CONTAINER (window), box1);
2833 gtk_widget_show (box1);
2835 box2 = gtk_hbox_new (FALSE, 10);
2836 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2837 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2838 gtk_widget_show (box2);
2840 /* calue, lower, upper, step_increment, page_increment, page_size */
2841 /* Note that the page_size value only makes a difference for
2842 * scrollbar widgets, and the highest value you'll get is actually
2843 * (upper - page_size). */
2844 adj1 = gtk_adjustment_new (0.0, 0.0, 101.0, 0.1, 1.0, 1.0);
2846 vscale = gtk_vscale_new (GTK_ADJUSTMENT (adj1));
2847 scale_set_default_values (GTK_SCALE (vscale));
2848 gtk_box_pack_start (GTK_BOX (box2), vscale, TRUE, TRUE, 0);
2849 gtk_widget_show (vscale);
2851 box3 = gtk_vbox_new (FALSE, 10);
2852 gtk_box_pack_start (GTK_BOX (box2), box3, TRUE, TRUE, 0);
2853 gtk_widget_show (box3);
2855 /* Reuse the same adjustment */
2856 hscale = gtk_hscale_new (GTK_ADJUSTMENT (adj1));
2857 gtk_widget_set_usize (GTK_WIDGET (hscale), 200, 30);
2858 scale_set_default_values (GTK_SCALE (hscale));
2859 gtk_box_pack_start (GTK_BOX (box3), hscale, TRUE, TRUE, 0);
2860 gtk_widget_show (hscale);
2862 /* Reuse the same adjustment again */
2863 scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adj1));
2864 /* Notice how this causes the scales to always be updated
2865 * continuously when the scrollbar is moved */
2866 gtk_range_set_update_policy (GTK_RANGE (scrollbar),
2867 GTK_UPDATE_CONTINUOUS);
2868 gtk_box_pack_start (GTK_BOX (box3), scrollbar, TRUE, TRUE, 0);
2869 gtk_widget_show (scrollbar);
2871 box2 = gtk_hbox_new (FALSE, 10);
2872 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2873 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2874 gtk_widget_show (box2);
2876 /* A checkbutton to control whether the value is displayed or not */
2877 button = gtk_check_button_new_with_label("Display value on scale widgets");
2878 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2879 gtk_signal_connect (GTK_OBJECT (button), "toggled",
2880 GTK_SIGNAL_FUNC(cb_draw_value), NULL);
2881 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2882 gtk_widget_show (button);
2884 box2 = gtk_hbox_new (FALSE, 10);
2885 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2887 /* An option menu to change the position of the value */
2888 label = gtk_label_new ("Scale Value Position:");
2889 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
2890 gtk_widget_show (label);
2892 opt = gtk_option_menu_new();
2893 menu = gtk_menu_new();
2895 item = make_menu_item ("Top",
2896 GTK_SIGNAL_FUNC(cb_pos_menu_select),
2897 GINT_TO_POINTER (GTK_POS_TOP));
2898 gtk_menu_append (GTK_MENU (menu), item);
2900 item = make_menu_item ("Bottom", GTK_SIGNAL_FUNC (cb_pos_menu_select),
2901 GINT_TO_POINTER (GTK_POS_BOTTOM));
2902 gtk_menu_append (GTK_MENU (menu), item);
2904 item = make_menu_item ("Left", GTK_SIGNAL_FUNC (cb_pos_menu_select),
2905 GINT_TO_POINTER (GTK_POS_LEFT));
2906 gtk_menu_append (GTK_MENU (menu), item);
2908 item = make_menu_item ("Right", GTK_SIGNAL_FUNC (cb_pos_menu_select),
2909 GINT_TO_POINTER (GTK_POS_RIGHT));
2910 gtk_menu_append (GTK_MENU (menu), item);
2912 gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
2913 gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
2914 gtk_widget_show (opt);
2916 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2917 gtk_widget_show (box2);
2919 box2 = gtk_hbox_new (FALSE, 10);
2920 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2922 /* Yet another option menu, this time for the update policy of the
2924 label = gtk_label_new ("Scale Update Policy:");
2925 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
2926 gtk_widget_show (label);
2928 opt = gtk_option_menu_new();
2929 menu = gtk_menu_new();
2931 item = make_menu_item ("Continuous",
2932 GTK_SIGNAL_FUNC (cb_update_menu_select),
2933 GINT_TO_POINTER (GTK_UPDATE_CONTINUOUS));
2934 gtk_menu_append (GTK_MENU (menu), item);
2936 item = make_menu_item ("Discontinuous",
2937 GTK_SIGNAL_FUNC (cb_update_menu_select),
2938 GINT_TO_POINTER (GTK_UPDATE_DISCONTINUOUS));
2939 gtk_menu_append (GTK_MENU (menu), item);
2941 item = make_menu_item ("Delayed",
2942 GTK_SIGNAL_FUNC (cb_update_menu_select),
2943 GINT_TO_POINTER (GTK_UPDATE_DELAYED));
2944 gtk_menu_append (GTK_MENU (menu), item);
2946 gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
2947 gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
2948 gtk_widget_show (opt);
2950 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2951 gtk_widget_show (box2);
2953 box2 = gtk_hbox_new (FALSE, 10);
2954 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2956 /* A GtkHScale widget for adjusting the number of digits on the
2958 label = gtk_label_new ("Scale Digits:");
2959 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
2960 gtk_widget_show (label);
2962 adj2 = gtk_adjustment_new (1.0, 0.0, 5.0, 1.0, 1.0, 0.0);
2963 gtk_signal_connect (GTK_OBJECT (adj2), "value_changed",
2964 GTK_SIGNAL_FUNC (cb_digits_scale), NULL);
2965 scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
2966 gtk_scale_set_digits (GTK_SCALE (scale), 0);
2967 gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
2968 gtk_widget_show (scale);
2970 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2971 gtk_widget_show (box2);
2973 box2 = gtk_hbox_new (FALSE, 10);
2974 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2976 /* And, one last GtkHScale widget for adjusting the page size of the
2978 label = gtk_label_new ("Scrollbar Page Size:");
2979 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
2980 gtk_widget_show (label);
2982 adj2 = gtk_adjustment_new (1.0, 1.0, 101.0, 1.0, 1.0, 0.0);
2983 gtk_signal_connect (GTK_OBJECT (adj2), "value_changed",
2984 GTK_SIGNAL_FUNC (cb_page_size), adj1);
2985 scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
2986 gtk_scale_set_digits (GTK_SCALE (scale), 0);
2987 gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
2988 gtk_widget_show (scale);
2990 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2991 gtk_widget_show (box2);
2993 separator = gtk_hseparator_new ();
2994 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
2995 gtk_widget_show (separator);
2997 box2 = gtk_vbox_new (FALSE, 10);
2998 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2999 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
3000 gtk_widget_show (box2);
3002 button = gtk_button_new_with_label ("Quit");
3003 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
3004 GTK_SIGNAL_FUNC(gtk_main_quit),
3006 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
3007 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
3008 gtk_widget_grab_default (button);
3009 gtk_widget_show (button);
3011 gtk_widget_show (window);
3017 gtk_init(&argc, &argv);
3019 create_range_controls();
3031 <!-- ***************************************************************** -->
3032 <sect> Miscellaneous Widgets
3033 <!-- ***************************************************************** -->
3035 <!-- ----------------------------------------------------------------- -->
3038 Labels are used a lot in GTK, and are relatively simple. Labels emit
3039 no signals as they do not have an associated X window. If you need to
3040 catch signals, or do clipping, use the <ref id="sec_EventBox"
3041 name="EventBox"> widget.
3043 To create a new label, use:
3046 GtkWidget *gtk_label_new( char *str );
3049 Where the sole argument is the string you wish the label to display.
3051 To change the label's text after creation, use the function:
3054 void gtk_label_set_text( GtkLabel *label,
3058 Where the first argument is the label you created previously (cast
3059 using the GTK_LABEL() macro), and the second is the new string.
3061 The space needed for the new string will be automatically adjusted if
3062 needed. You can produce multi-line labels by putting line breaks in
3065 To retrieve the current string, use:
3068 void gtk_label_get( GtkLabel *label,
3072 Where the first argument is the label you've created, and the second,
3073 the return for the string. Do not free the return string, as it is
3074 used internally by GTK.
3076 The label text can be justified using:
3079 void gtk_label_set_justify( GtkLabel *label,
3080 GtkJustification jtype );
3083 Values for <tt/jtype/ are:
3085 <item> GTK_JUSTIFY_LEFT
3086 <item> GTK_JUSTIFY_RIGHT
3087 <item> GTK_JUSTIFY_CENTER (the default)
3088 <item> GTK_JUSTIFY_FILL
3091 The label widget is also capable of line wrapping the text
3092 automatically. This can be activated using:
3095 void gtk_label_set_line_wrap (GtkLabel *label,
3099 The <//wrap/ argument takes a TRUE or FALSE value.
3101 If you want your label underlined, then you can set a pattern on the
3105 void gtk_label_set_pattern (GtkLabel *label,
3106 const gchar *pattern);
3109 The pattern argument indicates how the underlining should look. It
3110 consists of a string of underscore and space characters. An underscore
3111 indicates that the corresponding character in the label should be
3112 underlined. For example, the string <verb/"__ __"/ would underline the
3113 first two characters and eigth and ninth characters.
3115 Below is a short example to illustrate these functions. This example
3116 makes use of the Frame widget to better demonstrate the label
3117 styles. You can ignore this for now as the <ref id="sec_Frames"
3118 name="Frame"> widget is explained later on.
3121 /* example-start label label.c */
3123 #include <gtk/gtk.h>
3128 static GtkWidget *window = NULL;
3134 /* Initialise GTK */
3135 gtk_init(&argc, &argv);
3137 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3138 gtk_signal_connect (GTK_OBJECT (window), "destroy",
3139 GTK_SIGNAL_FUNC(gtk_main_quit),
3142 gtk_window_set_title (GTK_WINDOW (window), "Label");
3143 vbox = gtk_vbox_new (FALSE, 5);
3144 hbox = gtk_hbox_new (FALSE, 5);
3145 gtk_container_add (GTK_CONTAINER (window), hbox);
3146 gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
3147 gtk_container_set_border_width (GTK_CONTAINER (window), 5);
3149 frame = gtk_frame_new ("Normal Label");
3150 label = gtk_label_new ("This is a Normal label");
3151 gtk_container_add (GTK_CONTAINER (frame), label);
3152 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3154 frame = gtk_frame_new ("Multi-line Label");
3155 label = gtk_label_new ("This is a Multi-line label.\nSecond line\n" \
3157 gtk_container_add (GTK_CONTAINER (frame), label);
3158 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3160 frame = gtk_frame_new ("Left Justified Label");
3161 label = gtk_label_new ("This is a Left-Justified\n" \
3162 "Multi-line label.\nThird line");
3163 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
3164 gtk_container_add (GTK_CONTAINER (frame), label);
3165 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3167 frame = gtk_frame_new ("Right Justified Label");
3168 label = gtk_label_new ("This is a Right-Justified\nMulti-line label.\n" \
3169 "Fourth line, (j/k)");
3170 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT);
3171 gtk_container_add (GTK_CONTAINER (frame), label);
3172 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3174 vbox = gtk_vbox_new (FALSE, 5);
3175 gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
3176 frame = gtk_frame_new ("Line wrapped label");
3177 label = gtk_label_new ("This is an example of a line-wrapped label. It " \
3178 "should not be taking up the entire " /* big space to test spacing */\
3179 "width allocated to it, but automatically " \
3180 "wraps the words to fit. " \
3181 "The time has come, for all good men, to come to " \
3182 "the aid of their party. " \
3183 "The sixth sheik's six sheep's sick.\n" \
3184 " It supports multiple paragraphs correctly, " \
3185 "and correctly adds "\
3186 "many extra spaces. ");
3187 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
3188 gtk_container_add (GTK_CONTAINER (frame), label);
3189 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3191 frame = gtk_frame_new ("Filled, wrapped label");
3192 label = gtk_label_new ("This is an example of a line-wrapped, filled label. " \
3193 "It should be taking "\
3194 "up the entire width allocated to it. " \
3195 "Here is a seneance to prove "\
3196 "my point. Here is another sentence. "\
3197 "Here comes the sun, do de do de do.\n"\
3198 " This is a new paragraph.\n"\
3199 " This is another newer, longer, better " \
3200 "paragraph. It is coming to an end, "\
3202 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_FILL);
3203 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
3204 gtk_container_add (GTK_CONTAINER (frame), label);
3205 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3207 frame = gtk_frame_new ("Underlined label");
3208 label = gtk_label_new ("This label is underlined!\n"
3209 "This one is underlined in quite a funky fashion");
3210 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
3211 gtk_label_set_pattern (GTK_LABEL (label),
3212 "_________________________ _ _________ _ ______ __ _______ ___");
3213 gtk_container_add (GTK_CONTAINER (frame), label);
3214 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3216 gtk_widget_show_all (window);
3225 <!-- ----------------------------------------------------------------- -->
3228 The Arrow widget draws an arrowhead, facing in a number of possible
3229 directions and having a number of possible styles. It can be very
3230 useful when placed on a button in many applications.
3232 There are only two functions for manipulating an Arrow widget:
3235 GtkWidget *gtk_arrow_new( GtkArrowType arrow_type,
3236 GtkShadowType shadow_type );
3238 void gtk_arrow_set( GtkArrow *arrow,
3239 GtkArrowType arrow_type,
3240 GtkShadowType shadow_type );
3243 The first creates a new arrow widget with the indicated type and
3244 appearance. The second allows these values to be altered
3245 retrospectively. The <tt/arrow_type/ argument may take one of the
3250 <item> GTK_ARROW_DOWN
3251 <item> GTK_ARROW_LEFT
3252 <item> GTK_ARROW_RIGHT
3255 These values obviously indicate the direction in which the arrow will
3256 point. The <tt/shadow_type/ argument may take one of these values:
3259 <item> GTK_SHADOW_IN
3260 <item> GTK_SHADOW_OUT (the default)
3261 <item> GTK_SHADOW_ETCHED_IN
3262 <item> GTK_SHADOW_ETCHED_OUT
3265 Here's a brief example to illustrate their use.
3268 /* example-start arrow arrow.c */
3270 #include <gtk/gtk.h>
3272 /* Create an Arrow widget with the specified parameters
3273 * and pack it into a button */
3274 GtkWidget *create_arrow_button( GtkArrowType arrow_type,
3275 GtkShadowType shadow_type )
3280 button = gtk_button_new();
3281 arrow = gtk_arrow_new (arrow_type, shadow_type);
3283 gtk_container_add (GTK_CONTAINER (button), arrow);
3285 gtk_widget_show(button);
3286 gtk_widget_show(arrow);
3294 /* GtkWidget is the storage type for widgets */
3299 /* Initialize the toolkit */
3300 gtk_init (&argc, &argv);
3302 /* Create a new window */
3303 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3305 gtk_window_set_title (GTK_WINDOW (window), "Arrow Buttons");
3307 /* It's a good idea to do this for all windows. */
3308 gtk_signal_connect (GTK_OBJECT (window), "destroy",
3309 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
3311 /* Sets the border width of the window. */
3312 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
3314 /* Create a box to hold the arrows/buttons */
3315 box = gtk_hbox_new (FALSE, 0);
3316 gtk_container_set_border_width (GTK_CONTAINER (box), 2);
3317 gtk_container_add (GTK_CONTAINER (window), box);
3319 /* Pack and show all our widgets */
3320 gtk_widget_show(box);
3322 button = create_arrow_button(GTK_ARROW_UP, GTK_SHADOW_IN);
3323 gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3325 button = create_arrow_button(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
3326 gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3328 button = create_arrow_button(GTK_ARROW_LEFT, GTK_SHADOW_ETCHED_IN);
3329 gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3331 button = create_arrow_button(GTK_ARROW_RIGHT, GTK_SHADOW_ETCHED_OUT);
3332 gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3334 gtk_widget_show (window);
3336 /* Rest in gtk_main and wait for the fun to begin! */
3344 <!-- ----------------------------------------------------------------- -->
3345 <sect1>The Tooltips Widget
3347 These are the little text strings that pop up when you leave your
3348 pointer over a button or other widget for a few seconds. They are easy
3349 to use, so I will just explain them without giving an example. If you
3350 want to see some code, take a look at the testgtk.c program
3351 distributed with GTK.
3353 Widgets that do not receieve events (widgets that do not have their
3354 own window) will not work with tooltips.
3356 The first call you will use creates a new tooltip. You only need to do
3357 this once for a set of tooltips as the <tt/GtkTooltip/ object this
3358 function returns can be used to create multiple tooltips.
3361 GtkTooltips *gtk_tooltips_new( void );
3364 Once you have created a new tooltip, and the widget you wish to use it
3365 on, simply use this call to set it:
3368 void gtk_tooltips_set_tip( GtkTooltips *tooltips,
3370 const gchar *tip_text,
3371 const gchar *tip_private );
3374 The first argument is the tooltip you've already created, followed by
3375 the widget you wish to have this tooltip pop up for, and the text you
3376 wish it to say. The last argument is a text string that can be used as
3377 an identifier when using GtkTipsQuery to implement context sensitive
3378 help. For now, you can set it to NULL.
3380 <!-- TODO: sort out what how to do the context sensitive help -->
3382 Here's a short example:
3385 GtkTooltips *tooltips;
3390 tooltips = gtk_tooltips_new ();
3391 button = gtk_button_new_with_label ("button 1");
3395 gtk_tooltips_set_tip (tooltips, button, "This is button 1", NULL);
3398 There are other calls that can be used with tooltips. I will just list
3399 them with a brief description of what they do.
3402 void gtk_tooltips_enable( GtkTooltips *tooltips );
3405 Enable a disabled set of tooltips.
3408 void gtk_tooltips_disable( GtkTooltips *tooltips );
3411 Disable an enabled set of tooltips.
3414 void gtk_tooltips_set_delay( GtkTooltips *tooltips,
3419 Sets how many milliseconds you have to hold your pointer over the
3420 widget before the tooltip will pop up. The default is 500
3421 milliseconds (half a second).
3424 void gtk_tooltips_set_colors( GtkTooltips *tooltips,
3425 GdkColor *background,
3426 GdkColor *foreground );
3429 Set the foreground and background color of the tooltips.
3431 And that's all the functions associated with tooltips. More than
3432 you'll ever want to know :-)
3434 <!-- ----------------------------------------------------------------- -->
3435 <sect1> Progress Bars <label id="sec_ProgressBar">
3437 Progress bars are used to show the status of an operation. They are
3438 pretty easy to use, as you will see with the code below. But first
3439 lets start out with the calls to create a new progress bar.
3441 There are two ways to create a progress bar, one simple that takes
3442 no arguments, and one that takes a GtkAdjustment object as an
3443 argument. If the former is used, the progress bar creates its own
3447 GtkWidget *gtk_progress_bar_new( void );
3449 GtkWidget *gtk_progress_bar_new_with_adjustment( GtkAdjustment *adjustment );
3452 The second method has the advantage that we can use the adjustment
3453 object to specify our own range parameters for the progress bar.
3455 Now that the progress bar has been created we can use it.
3458 void gtk_progress_bar_update( GtkProgressBar *pbar,
3459 gfloat percentage );
3462 The first argument is the progress bar you wish to operate on, and the
3463 second argument is the amount 'completed', meaning the amount the
3464 progress bar has been filled from 0-100%. This is passed to the
3465 function as a real number ranging from 0 to 1.
3467 GTK v1.2 has added new functionality to the progress bar that enables
3468 it to display its value in different ways, and to inform the user of
3469 its current value and its range.
3471 A progress bar may be set to one of a number of orientations using the
3475 void gtk_progress_bar_set_orientation( GtkProgressBar *pbar,
3476 GtkProgressBarOrientation orientation );
3479 Where the <tt/orientation/ argument may take one of the following
3480 values to indicate the direction in which the progress bar moves:
3483 <item> GTK_PROGRESS_LEFT_TO_RIGHT
3484 <item> GTK_PROGRESS_RIGHT_TO_LEFT
3485 <item> GTK_PROGRESS_BOTTOM_TO_TOP
3486 <item> GTK_PROGRESS_TOP_TO_BOTTOM
3489 When used as a measure of how far a process has progressed, the
3490 GtkProgressBar can be set to display its value in either a continuous
3491 or discrete mode. In continuous mode, the progress bar is updated for
3492 each value. In discrete mode, the progress bar is updated in a number
3493 of discrete blocks. The number of blocks is also configurable.
3495 The style of a progress bar can be set using the following function.
3498 void gtk_progress_bar_set_bar_style( GtkProgressBar *pbar,
3499 GtkProgressBarStyle style );
3502 The <tt/style/ parameter can take one of two values:
3505 <item>GTK_PROGRESS_CONTINUOUS
3506 <item>GTK_PROGRESS_DISCRETE
3509 The number of discrete blocks can be set by calling
3512 void gtk_progress_bar_set_discrete_blocks( GtkProgressBar *pbar,
3516 As well as indicating the amount of progress that has occured, the
3517 progress bar may be set to just indicate that there is some
3518 activity. This can be useful in situations where progress cannot be
3519 measured against a value range. Activity mode is not effected by the
3520 bar style that is described above, and overrides it.This mode is
3521 selected by the following function.
3524 void gtk_progress_set_activity_mode( GtkProgress *progress,
3525 guint activity_mode );
3528 The step size of the activity indicator, and the number of blocks are
3529 set using the following functions.
3532 void gtk_progress_bar_set_activity_step( GtkProgressBar *pbar,
3535 void gtk_progress_bar_set_activity_blocks( GtkProgressBar *pbar,
3539 When in continuous mode, the progress bar can also display a
3540 configurable text string within its trough, using the following
3544 void gtk_progress_set_format_string( GtkProgress *progress,
3548 The <tt/format/ argument is similiar to one that would be used in a C
3549 <tt/printf/ statement. The following directives may be used within the
3553 <item> %p - percentage
3555 <item> %l - lower range value
3556 <item> %u - upper range value
3559 Progress Bars are usually used with timeouts or other such functions
3560 (see section on <ref id="sec_timeouts" name="Timeouts, I/O and Idle
3561 Functions">) to give the illusion of multitasking. All will employ the
3562 gtk_progress_bar_update function in the same manner.
3564 Here is an example of the progress bar, updated using timeouts. This
3565 code also shows you how to reset the Progress Bar.
3568 /* example-start progressbar progressbar.c */
3570 #include <gtk/gtk.h>
3572 typedef struct _ProgressData {
3578 /* Update the value of the progress bar so that we get
3580 gint progress_timeout( gpointer data )
3585 adj = GTK_PROGRESS (data)->adjustment;
3587 /* Calculate the value of the progress bar using the
3588 * value range set in the adjustment object */
3589 new_val = adj->value + 1;
3590 if (new_val > adj->upper)
3591 new_val = adj->lower;
3593 /* Set the new value */
3594 gtk_progress_set_value (GTK_PROGRESS (data), new_val);
3596 /* As this is a timeout function, return TRUE so that it
3597 * continues to get called */
3601 /* Callback that toggles the text display within the progress
3603 void toggle_show_text( GtkWidget *widget,
3604 ProgressData *pdata )
3606 gtk_progress_set_show_text (GTK_PROGRESS (pdata->pbar),
3607 GTK_TOGGLE_BUTTON (widget)->active);
3610 /* Callback that toggles the activity mode of the progress
3612 void toggle_activity_mode( GtkWidget *widget,
3613 ProgressData *pdata )
3615 gtk_progress_set_activity_mode (GTK_PROGRESS (pdata->pbar),
3616 GTK_TOGGLE_BUTTON (widget)->active);
3619 /* Callback that toggles the continuous mode of the progress
3621 void set_continuous_mode( GtkWidget *widget,
3622 ProgressData *pdata )
3624 gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
3625 GTK_PROGRESS_CONTINUOUS);
3628 /* Callback that toggles the discrete mode of the progress
3630 void set_discrete_mode( GtkWidget *widget,
3631 ProgressData *pdata )
3633 gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
3634 GTK_PROGRESS_DISCRETE);
3637 /* Clean up allocated memory and remove the timer */
3638 void destroy_progress( GtkWidget *widget,
3639 ProgressData *pdata)
3641 gtk_timeout_remove (pdata->timer);
3643 pdata->window = NULL;
3651 ProgressData *pdata;
3653 GtkWidget *separator;
3660 gtk_init (&argc, &argv);
3662 /* Allocate memory for the data that is passwd to the callbacks */
3663 pdata = g_malloc( sizeof(ProgressData) );
3665 pdata->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3666 gtk_window_set_policy (GTK_WINDOW (pdata->window), FALSE, FALSE, TRUE);
3668 gtk_signal_connect (GTK_OBJECT (pdata->window), "destroy",
3669 GTK_SIGNAL_FUNC (destroy_progress),
3671 gtk_window_set_title (GTK_WINDOW (pdata->window), "GtkProgressBar");
3672 gtk_container_set_border_width (GTK_CONTAINER (pdata->window), 0);
3674 vbox = gtk_vbox_new (FALSE, 5);
3675 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
3676 gtk_container_add (GTK_CONTAINER (pdata->window), vbox);
3677 gtk_widget_show(vbox);
3679 /* Create a centering alignment object */
3680 align = gtk_alignment_new (0.5, 0.5, 0, 0);
3681 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 5);
3682 gtk_widget_show(align);
3684 /* Create a GtkAdjusment object to hold the range of the
3686 adj = (GtkAdjustment *) gtk_adjustment_new (0, 1, 150, 0, 0, 0);
3688 /* Create the GtkProgressBar using the adjustment */
3689 pdata->pbar = gtk_progress_bar_new_with_adjustment (adj);
3691 /* Set the format of the string that can be displayed in the
3692 * trough of the progress bar:
3695 * %l - lower range value
3696 * %u - upper range value */
3697 gtk_progress_set_format_string (GTK_PROGRESS (pdata->pbar),
3698 "%v from [%l-%u] (=%p%%)");
3699 gtk_container_add (GTK_CONTAINER (align), pdata->pbar);
3700 gtk_widget_show(pdata->pbar);
3702 /* Add a timer callback to update the value of the progress bar */
3703 pdata->timer = gtk_timeout_add (100, progress_timeout, pdata->pbar);
3705 separator = gtk_hseparator_new ();
3706 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
3707 gtk_widget_show(separator);
3709 /* rows, columns, homogeneous */
3710 table = gtk_table_new (2, 3, FALSE);
3711 gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0);
3712 gtk_widget_show(table);
3714 /* Add a check button to select displaying of the trough text */
3715 check = gtk_check_button_new_with_label ("Show text");
3716 gtk_table_attach (GTK_TABLE (table), check, 0, 1, 0, 1,
3717 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3719 gtk_signal_connect (GTK_OBJECT (check), "clicked",
3720 GTK_SIGNAL_FUNC (toggle_show_text),
3722 gtk_widget_show(check);
3724 /* Add a check button to toggle activity mode */
3725 check = gtk_check_button_new_with_label ("Activity mode");
3726 gtk_table_attach (GTK_TABLE (table), check, 0, 1, 1, 2,
3727 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3729 gtk_signal_connect (GTK_OBJECT (check), "clicked",
3730 GTK_SIGNAL_FUNC (toggle_activity_mode),
3732 gtk_widget_show(check);
3734 separator = gtk_vseparator_new ();
3735 gtk_table_attach (GTK_TABLE (table), separator, 1, 2, 0, 2,
3736 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3738 gtk_widget_show(separator);
3740 /* Add a radio button to select continuous display mode */
3741 button = gtk_radio_button_new_with_label (NULL, "Continuous");
3742 gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1,
3743 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3745 gtk_signal_connect (GTK_OBJECT (button), "clicked",
3746 GTK_SIGNAL_FUNC (set_continuous_mode),
3748 gtk_widget_show (button);
3750 /* Add a radio button to select discrete display mode */
3751 button = gtk_radio_button_new_with_label(
3752 gtk_radio_button_group (GTK_RADIO_BUTTON (button)),
3754 gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2,
3755 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3757 gtk_signal_connect (GTK_OBJECT (button), "clicked",
3758 GTK_SIGNAL_FUNC (set_discrete_mode),
3760 gtk_widget_show (button);
3762 separator = gtk_hseparator_new ();
3763 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
3764 gtk_widget_show(separator);
3766 /* Add a button to exit the program */
3767 button = gtk_button_new_with_label ("close");
3768 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
3769 (GtkSignalFunc) gtk_widget_destroy,
3770 GTK_OBJECT (pdata->window));
3771 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
3773 /* This makes it so the button is the default. */
3774 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
3776 /* This grabs this button to be the default button. Simply hitting
3777 * the "Enter" key will cause this button to activate. */
3778 gtk_widget_grab_default (button);
3779 gtk_widget_show(button);
3781 gtk_widget_show (pdata->window);
3790 <!-- ----------------------------------------------------------------- -->
3793 The Dialog widget is very simple, and is actually just a window with a
3794 few things pre-packed into it for you. The structure for a Dialog is:
3802 GtkWidget *action_area;
3806 So you see, it simply creates a window, and then packs a vbox into the
3807 top, then a separator, and then an hbox for the "action_area".
3809 The Dialog widget can be used for pop-up messages to the user, and
3810 other similar tasks. It is really basic, and there is only one
3811 function for the dialog box, which is:
3814 GtkWidget *gtk_dialog_new( void );
3817 So to create a new dialog box, use,
3821 window = gtk_dialog_new ();
3824 This will create the dialog box, and it is now up to you to use it.
3825 you could pack a button in the action_area by doing something like this:
3829 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area),
3830 button, TRUE, TRUE, 0);
3831 gtk_widget_show (button);
3834 And you could add to the vbox area by packing, for instance, a label
3835 in it, try something like this:
3838 label = gtk_label_new ("Dialogs are groovy");
3839 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox),
3840 label, TRUE, TRUE, 0);
3841 gtk_widget_show (label);
3844 As an example in using the dialog box, you could put two buttons in
3845 the action_area, a Cancel button and an Ok button, and a label in the
3846 vbox area, asking the user a question or giving an error etc. Then
3847 you could attach a different signal to each of the buttons and perform
3848 the operation the user selects.
3850 If the simple functionality provided by the default vertical and
3851 horizontal boxes in the two areas does't give you enough control for
3852 your application, then you can simply pack another layout widget into
3853 the boxes provided. For example, you could pack a table into the
3856 <!-- ----------------------------------------------------------------- -->
3857 <sect1> Pixmaps <label id="sec_Pixmaps">
3859 Pixmaps are data structures that contain pictures. These pictures can
3860 be used in various places, but most visibly as icons on the X-Windows
3861 desktop, or as cursors.
3863 A pixmap which only has 2 colors is called a bitmap, and there are a
3864 few additional routines for handling this common special case.
3866 To understand pixmaps, it would help to understand how X-windows
3867 works. Under X-windows, applications do not need to be running on the
3868 same computer that is interacting with the user. Instead, the various
3869 applications, called "clients", all communicate with a program which
3870 displays the graphics and handles the keyboard and mouse. This
3871 program which interacts directly with the user is called a "display
3872 server" or "X server." Since the communication might take place over
3873 a network, it's important to keep some information with the X server.
3874 Pixmaps, for example, are stored in the memory of the X server. This
3875 means that once pixmap values are set, they don't need to keep getting
3876 transmitted over the network; instead a command is sent to "display
3877 pixmap number XYZ here." Even if you aren't using X-windows with GTK
3878 currently, using constructs such as Pixmaps will make your programs
3879 work acceptably under X-windows.
3881 To use pixmaps in GTK, we must first build a GdkPixmap structure using
3882 routines from the GDK layer. Pixmaps can either be created from
3883 in-memory data, or from data read from a file. We'll go through each
3884 of the calls to create a pixmap.
3887 GdkPixmap *gdk_bitmap_create_from_data( GdkWindow *window,
3893 This routine is used to create a single-plane pixmap (2 colors) from
3894 data in memory. Each bit of the data represents whether that pixel is
3895 off or on. Width and height are in pixels. The GdkWindow pointer is
3896 to the current window, since a pixmap resources are meaningful only in
3897 the context of the screen where it is to be displayed.
3900 GdkPixmap *gdk_pixmap_create_from_data( GdkWindow *window,
3909 This is used to create a pixmap of the given depth (number of colors) from
3910 the bitmap data specified. <tt/fg/ and <tt/bg/ are the foreground and
3911 background color to use.
3914 GdkPixmap *gdk_pixmap_create_from_xpm( GdkWindow *window,
3916 GdkColor *transparent_color,
3917 const gchar *filename );
3920 XPM format is a readable pixmap representation for the X Window
3921 System. It is widely used and many different utilities are available
3922 for creating image files in this format. The file specified by
3923 filename must contain an image in that format and it is loaded into
3924 the pixmap structure. The mask specifies which bits of the pixmap are
3925 opaque. All other bits are colored using the color specified by
3926 transparent_color. An example using this follows below.
3929 GdkPixmap *gdk_pixmap_create_from_xpm_d( GdkWindow *window,
3931 GdkColor *transparent_color,
3935 Small images can be incorporated into a program as data in the XPM
3936 format. A pixmap is created using this data, instead of reading it
3937 from a file. An example of such data is
3941 static const char * xpm_data[] = {
3944 ". c #000000000000",
3945 "X c #FFFFFFFFFFFF",
3964 When we're done using a pixmap and not likely to reuse it again soon,
3965 it is a good idea to release the resource using
3966 gdk_pixmap_unref(). Pixmaps should be considered a precious resource.
3968 Once we've created a pixmap, we can display it as a GTK widget. We
3969 must create a GTK pixmap widget to contain the GDK pixmap. This is
3973 GtkWidget *gtk_pixmap_new( GdkPixmap *pixmap,
3977 The other pixmap widget calls are
3980 guint gtk_pixmap_get_type( void );
3982 void gtk_pixmap_set( GtkPixmap *pixmap,
3986 void gtk_pixmap_get( GtkPixmap *pixmap,
3991 gtk_pixmap_set is used to change the pixmap that the widget is currently
3992 managing. Val is the pixmap created using GDK.
3994 The following is an example of using a pixmap in a button.
3997 /* example-start pixmap pixmap.c */
3999 #include <gtk/gtk.h>
4002 /* XPM data of Open-File icon */
4003 static const char * xpm_data[] = {
4006 ". c #000000000000",
4007 "X c #FFFFFFFFFFFF",
4026 /* when invoked (via signal delete_event), terminates the application.
4028 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
4033 /* is invoked when the button is clicked. It just prints a message.
4035 void button_clicked( GtkWidget *widget, gpointer data ) {
4036 printf( "button clicked\n" );
4039 int main( int argc, char *argv[] )
4041 /* GtkWidget is the storage type for widgets */
4042 GtkWidget *window, *pixmapwid, *button;
4047 /* create the main window, and attach delete_event signal to terminating
4049 gtk_init( &argc, &argv );
4050 window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
4051 gtk_signal_connect( GTK_OBJECT (window), "delete_event",
4052 GTK_SIGNAL_FUNC (close_application), NULL );
4053 gtk_container_set_border_width( GTK_CONTAINER (window), 10 );
4054 gtk_widget_show( window );
4056 /* now for the pixmap from gdk */
4057 style = gtk_widget_get_style( window );
4058 pixmap = gdk_pixmap_create_from_xpm_d( window->window, &mask,
4059 &style->bg[GTK_STATE_NORMAL],
4060 (gchar **)xpm_data );
4062 /* a pixmap widget to contain the pixmap */
4063 pixmapwid = gtk_pixmap_new( pixmap, mask );
4064 gtk_widget_show( pixmapwid );
4066 /* a button to contain the pixmap widget */
4067 button = gtk_button_new();
4068 gtk_container_add( GTK_CONTAINER(button), pixmapwid );
4069 gtk_container_add( GTK_CONTAINER(window), button );
4070 gtk_widget_show( button );
4072 gtk_signal_connect( GTK_OBJECT(button), "clicked",
4073 GTK_SIGNAL_FUNC(button_clicked), NULL );
4075 /* show the window */
4083 To load a file from an XPM data file called icon0.xpm in the current
4084 directory, we would have created the pixmap thus
4087 /* load a pixmap from a file */
4088 pixmap = gdk_pixmap_create_from_xpm( window->window, &mask,
4089 &style->bg[GTK_STATE_NORMAL],
4091 pixmapwid = gtk_pixmap_new( pixmap, mask );
4092 gtk_widget_show( pixmapwid );
4093 gtk_container_add( GTK_CONTAINER(window), pixmapwid );
4096 A disadvantage of using pixmaps is that the displayed object is always
4097 rectangular, regardless of the image. We would like to create desktops
4098 and applications with icons that have more natural shapes. For
4099 example, for a game interface, we would like to have round buttons to
4100 push. The way to do this is using shaped windows.
4102 A shaped window is simply a pixmap where the background pixels are
4103 transparent. This way, when the background image is multi-colored, we
4104 don't overwrite it with a rectangular, non-matching border around our
4105 icon. The following example displays a full wheelbarrow image on the
4109 /* example-start wheelbarrow wheelbarrow.c */
4111 #include <gtk/gtk.h>
4114 static char * WheelbarrowFull_xpm[] = {
4117 ". c #DF7DCF3CC71B",
4118 "X c #965875D669A6",
4119 "o c #71C671C671C6",
4120 "O c #A699A289A699",
4121 "+ c #965892489658",
4122 "@ c #8E38410330C2",
4123 "# c #D75C7DF769A6",
4124 "$ c #F7DECF3CC71B",
4125 "% c #96588A288E38",
4126 "& c #A69992489E79",
4127 "* c #8E3886178E38",
4128 "= c #104008200820",
4129 "- c #596510401040",
4130 "; c #C71B30C230C2",
4131 ": c #C71B9A699658",
4132 "> c #618561856185",
4133 ", c #20811C712081",
4134 "< c #104000000000",
4135 "1 c #861720812081",
4136 "2 c #DF7D4D344103",
4137 "3 c #79E769A671C6",
4138 "4 c #861782078617",
4139 "5 c #41033CF34103",
4140 "6 c #000000000000",
4141 "7 c #49241C711040",
4142 "8 c #492445144924",
4143 "9 c #082008200820",
4144 "0 c #69A618611861",
4145 "q c #B6DA71C65144",
4146 "w c #410330C238E3",
4147 "e c #CF3CBAEAB6DA",
4148 "r c #71C6451430C2",
4149 "t c #EFBEDB6CD75C",
4150 "y c #28A208200820",
4151 "u c #186110401040",
4152 "i c #596528A21861",
4153 "p c #71C661855965",
4154 "a c #A69996589658",
4155 "s c #30C228A230C2",
4156 "d c #BEFBA289AEBA",
4157 "f c #596545145144",
4158 "g c #30C230C230C2",
4159 "h c #8E3882078617",
4160 "j c #208118612081",
4161 "k c #38E30C300820",
4162 "l c #30C2208128A2",
4163 "z c #38E328A238E3",
4164 "x c #514438E34924",
4165 "c c #618555555965",
4166 "v c #30C2208130C2",
4167 "b c #38E328A230C2",
4168 "n c #28A228A228A2",
4169 "m c #41032CB228A2",
4170 "M c #104010401040",
4171 "N c #492438E34103",
4172 "B c #28A2208128A2",
4173 "V c #A699596538E3",
4174 "C c #30C21C711040",
4175 "Z c #30C218611040",
4176 "A c #965865955965",
4177 "S c #618534D32081",
4178 "D c #38E31C711040",
4179 "F c #082000000820",
4188 "ty> 459@>+&& ",
4190 "%$;=* *3:.Xa.dfg> ",
4191 "Oh$;ya *3d.a8j,Xe.d3g8+ ",
4192 " Oh$;ka *3d$a8lz,,xxc:.e3g54 ",
4193 " Oh$;kO *pd$%svbzz,sxxxxfX..&wn> ",
4194 " Oh$@mO *3dthwlsslszjzxxxxxxx3:td8M4 ",
4195 " Oh$@g& *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B* ",
4196 " Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5& ",
4197 " Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM* ",
4198 " OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
4199 " 2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
4200 " :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
4201 " +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
4202 " *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&en",
4203 " p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>",
4204 " OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ",
4205 " 3206Bwxxszx%et.eaAp77m77mmmf3&eeeg* ",
4206 " @26MvzxNzvlbwfpdettttttttttt.c,n& ",
4207 " *;16=lsNwwNwgsvslbwwvccc3pcfu<o ",
4208 " p;<69BvwwsszslllbBlllllllu<5+ ",
4209 " OS0y6FBlvvvzvzss,u=Blllj=54 ",
4210 " c1-699Blvlllllu7k96MMMg4 ",
4211 " *10y8n6FjvllllB<166668 ",
4212 " S-kg+>666<M<996-y6n<8* ",
4213 " p71=4 m69996kD8Z-66698&& ",
4214 " &i0ycm6n4 ogk17,0<6666g ",
4215 " N-k-<> >=01-kuu666> ",
4216 " ,6ky& &46-10ul,66, ",
4217 " Ou0<> o66y<ulw<66& ",
4218 " *kk5 >66By7=xu664 ",
4219 " <<M4 466lj<Mxu66o ",
4220 " *>> +66uv,zN666* ",
4230 /* When invoked (via signal delete_event), terminates the application */
4231 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
4235 int main (int argc, char *argv[])
4237 /* GtkWidget is the storage type for widgets */
4238 GtkWidget *window, *pixmap, *fixed;
4239 GdkPixmap *gdk_pixmap;
4244 /* Create the main window, and attach delete_event signal to terminate
4245 * the application. Note that the main window will not have a titlebar
4246 * since we're making it a popup. */
4247 gtk_init (&argc, &argv);
4248 window = gtk_window_new( GTK_WINDOW_POPUP );
4249 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
4250 GTK_SIGNAL_FUNC (close_application), NULL);
4251 gtk_widget_show (window);
4253 /* Now for the pixmap and the pixmap widget */
4254 style = gtk_widget_get_default_style();
4255 gc = style->black_gc;
4256 gdk_pixmap = gdk_pixmap_create_from_xpm_d( window->window, &mask,
4257 &style->bg[GTK_STATE_NORMAL],
4258 WheelbarrowFull_xpm );
4259 pixmap = gtk_pixmap_new( gdk_pixmap, mask );
4260 gtk_widget_show( pixmap );
4262 /* To display the pixmap, we use a fixed widget to place the pixmap */
4263 fixed = gtk_fixed_new();
4264 gtk_widget_set_usize( fixed, 200, 200 );
4265 gtk_fixed_put( GTK_FIXED(fixed), pixmap, 0, 0 );
4266 gtk_container_add( GTK_CONTAINER(window), fixed );
4267 gtk_widget_show( fixed );
4269 /* This masks out everything except for the image itself */
4270 gtk_widget_shape_combine_mask( window, mask, 0, 0 );
4272 /* show the window */
4273 gtk_widget_set_uposition( window, 20, 400 );
4274 gtk_widget_show( window );
4282 To make the wheelbarrow image sensitive, we could attach the button
4283 press event signal to make it do something. The following few lines
4284 would make the picture sensitive to a mouse button being pressed which
4285 makes the application terminate.
4288 gtk_widget_set_events( window,
4289 gtk_widget_get_events( window ) |
4290 GDK_BUTTON_PRESS_MASK );
4292 gtk_signal_connect( GTK_OBJECT(window), "button_press_event",
4293 GTK_SIGNAL_FUNC(close_application), NULL );
4296 <!-- ----------------------------------------------------------------- -->
4299 Ruler widgets are used to indicate the location of the mouse pointer
4300 in a given window. A window can have a vertical ruler spanning across
4301 the width and a horizontal ruler spanning down the height. A small
4302 triangular indicator on the ruler shows the exact location of the
4303 pointer relative to the ruler.
4305 A ruler must first be created. Horizontal and vertical rulers are
4309 GtkWidget *gtk_hruler_new( void ); /* horizontal ruler */
4311 GtkWidget *gtk_vruler_new( void ); /* vertical ruler */
4314 Once a ruler is created, we can define the unit of measurement. Units
4315 of measure for rulers can be GTK_PIXELS, GTK_INCHES or
4316 GTK_CENTIMETERS. This is set using
4319 void gtk_ruler_set_metric( GtkRuler *ruler,
4320 GtkMetricType metric );
4323 The default measure is GTK_PIXELS.
4326 gtk_ruler_set_metric( GTK_RULER(ruler), GTK_PIXELS );
4329 Other important characteristics of a ruler are how to mark the units
4330 of scale and where the position indicator is initially placed. These
4331 are set for a ruler using
4334 void gtk_ruler_set_range( GtkRuler *ruler,
4341 The lower and upper arguments define the extent of the ruler, and
4342 max_size is the largest possible number that will be displayed.
4343 Position defines the initial position of the pointer indicator within
4346 A vertical ruler can span an 800 pixel wide window thus
4349 gtk_ruler_set_range( GTK_RULER(vruler), 0, 800, 0, 800);
4352 The markings displayed on the ruler will be from 0 to 800, with a
4353 number for every 100 pixels. If instead we wanted the ruler to range
4354 from 7 to 16, we would code
4357 gtk_ruler_set_range( GTK_RULER(vruler), 7, 16, 0, 20);
4360 The indicator on the ruler is a small triangular mark that indicates
4361 the position of the pointer relative to the ruler. If the ruler is
4362 used to follow the mouse pointer, the motion_notify_event signal
4363 should be connected to the motion_notify_event method of the ruler.
4364 To follow all mouse movements within a window area, we would use
4367 #define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
4369 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4370 (GtkSignalFunc)EVENT_METHOD(ruler, motion_notify_event),
4371 GTK_OBJECT(ruler) );
4374 The following example creates a drawing area with a horizontal ruler
4375 above it and a vertical ruler to the left of it. The size of the
4376 drawing area is 600 pixels wide by 400 pixels high. The horizontal
4377 ruler spans from 7 to 13 with a mark every 100 pixels, while the
4378 vertical ruler spans from 0 to 400 with a mark every 100 pixels.
4379 Placement of the drawing area and the rulers is done using a table.
4382 /* example-start rulers rulers.c */
4384 #include <gtk/gtk.h>
4386 #define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
4391 /* This routine gets control when the close button is clicked */
4392 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
4396 /* The main routine */
4397 int main( int argc, char *argv[] ) {
4398 GtkWidget *window, *table, *area, *hrule, *vrule;
4400 /* Initialize GTK and create the main window */
4401 gtk_init( &argc, &argv );
4403 window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
4404 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
4405 GTK_SIGNAL_FUNC( close_application ), NULL);
4406 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
4408 /* Create a table for placing the ruler and the drawing area */
4409 table = gtk_table_new( 3, 2, FALSE );
4410 gtk_container_add( GTK_CONTAINER(window), table );
4412 area = gtk_drawing_area_new();
4413 gtk_drawing_area_size( (GtkDrawingArea *)area, XSIZE, YSIZE );
4414 gtk_table_attach( GTK_TABLE(table), area, 1, 2, 1, 2,
4415 GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0 );
4416 gtk_widget_set_events( area, GDK_POINTER_MOTION_MASK |
4417 GDK_POINTER_MOTION_HINT_MASK );
4419 /* The horizontal ruler goes on top. As the mouse moves across the
4420 * drawing area, a motion_notify_event is passed to the
4421 * appropriate event handler for the ruler. */
4422 hrule = gtk_hruler_new();
4423 gtk_ruler_set_metric( GTK_RULER(hrule), GTK_PIXELS );
4424 gtk_ruler_set_range( GTK_RULER(hrule), 7, 13, 0, 20 );
4425 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4426 (GtkSignalFunc)EVENT_METHOD(hrule,
4427 motion_notify_event),
4428 GTK_OBJECT(hrule) );
4429 /* GTK_WIDGET_CLASS(GTK_OBJECT(hrule)->klass)->motion_notify_event, */
4430 gtk_table_attach( GTK_TABLE(table), hrule, 1, 2, 0, 1,
4431 GTK_EXPAND|GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0 );
4433 /* The vertical ruler goes on the left. As the mouse moves across
4434 * the drawing area, a motion_notify_event is passed to the
4435 * appropriate event handler for the ruler. */
4436 vrule = gtk_vruler_new();
4437 gtk_ruler_set_metric( GTK_RULER(vrule), GTK_PIXELS );
4438 gtk_ruler_set_range( GTK_RULER(vrule), 0, YSIZE, 10, YSIZE );
4439 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4441 GTK_WIDGET_CLASS(GTK_OBJECT(vrule)->klass)->
4442 motion_notify_event,
4443 GTK_OBJECT(vrule) );
4444 gtk_table_attach( GTK_TABLE(table), vrule, 0, 1, 1, 2,
4445 GTK_FILL, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0 );
4447 /* Now show everything */
4448 gtk_widget_show( area );
4449 gtk_widget_show( hrule );
4450 gtk_widget_show( vrule );
4451 gtk_widget_show( table );
4452 gtk_widget_show( window );
4460 <!-- ----------------------------------------------------------------- -->
4463 Statusbars are simple widgets used to display a text message. They
4464 keep a stack of the messages pushed onto them, so that popping the
4465 current message will re-display the previous text message.
4467 In order to allow different parts of an application to use the same
4468 statusbar to display messages, the statusbar widget issues Context
4469 Identifiers which are used to identify different 'users'. The message
4470 on top of the stack is the one displayed, no matter what context it is
4471 in. Messages are stacked in last-in-first-out order, not context
4474 A statusbar is created with a call to:
4477 GtkWidget *gtk_statusbar_new( void );
4480 A new Context Identifier is requested using a call to the following
4481 function with a short textual description of the context:
4484 guint gtk_statusbar_get_context_id( GtkStatusbar *statusbar,
4485 const gchar *context_description );
4488 There are three functions that can operate on statusbars:
4491 guint gtk_statusbar_push( GtkStatusbar *statusbar,
4495 void gtk_statusbar_pop( GtkStatusbar *statusbar)
4498 void gtk_statusbar_remove( GtkStatusbar *statusbar,
4503 The first, gtk_statusbar_push, is used to add a new message to the
4504 statusbar. It returns a Message Identifier, which can be passed later
4505 to the function gtk_statusbar_remove to remove the message with the
4506 given Message and Context Identifiers from the statusbar's stack.
4508 The function gtk_statusbar_pop removes the message highest in the
4509 stack with the given Context Identifier.
4511 The following example creates a statusbar and two buttons, one for
4512 pushing items onto the statusbar, and one for popping the last item
4516 /* example-start statusbar statusbar.c */
4518 #include <gtk/gtk.h>
4521 GtkWidget *status_bar;
4523 void push_item (GtkWidget *widget, gpointer data)
4525 static int count = 1;
4528 g_snprintf(buff, 20, "Item %d", count++);
4529 gtk_statusbar_push( GTK_STATUSBAR(status_bar), GPOINTER_TO_INT(data), buff);
4534 void pop_item (GtkWidget *widget, gpointer data)
4536 gtk_statusbar_pop( GTK_STATUSBAR(status_bar), GPOINTER_TO_INT(data) );
4540 int main (int argc, char *argv[])
4549 gtk_init (&argc, &argv);
4551 /* create a new window */
4552 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4553 gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
4554 gtk_window_set_title(GTK_WINDOW (window), "GTK Statusbar Example");
4555 gtk_signal_connect(GTK_OBJECT (window), "delete_event",
4556 (GtkSignalFunc) gtk_exit, NULL);
4558 vbox = gtk_vbox_new(FALSE, 1);
4559 gtk_container_add(GTK_CONTAINER(window), vbox);
4560 gtk_widget_show(vbox);
4562 status_bar = gtk_statusbar_new();
4563 gtk_box_pack_start (GTK_BOX (vbox), status_bar, TRUE, TRUE, 0);
4564 gtk_widget_show (status_bar);
4566 context_id = gtk_statusbar_get_context_id(
4567 GTK_STATUSBAR(status_bar), "Statusbar example");
4569 button = gtk_button_new_with_label("push item");
4570 gtk_signal_connect(GTK_OBJECT(button), "clicked",
4571 GTK_SIGNAL_FUNC (push_item), GINT_TO_POINTER(context_id) );
4572 gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 2);
4573 gtk_widget_show(button);
4575 button = gtk_button_new_with_label("pop last item");
4576 gtk_signal_connect(GTK_OBJECT(button), "clicked",
4577 GTK_SIGNAL_FUNC (pop_item), GINT_TO_POINTER(context_id) );
4578 gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 2);
4579 gtk_widget_show(button);
4581 /* always display the window as the last step so it all splashes on
4582 * the screen at once. */
4583 gtk_widget_show(window);
4592 <!-- ----------------------------------------------------------------- -->
4595 The Entry widget allows text to be typed and displayed in a single line
4596 text box. The text may be set with function calls that allow new text
4597 to replace, prepend or append the current contents of the Entry widget.
4599 There are two functions for creating Entry widgets:
4602 GtkWidget *gtk_entry_new( void );
4604 GtkWidget *gtk_entry_new_with_max_length( guint16 max );
4607 The first just creates a new Entry widget, whilst the second creates a
4608 new Entry and sets a limit on the length of the text within the Entry.
4610 There are several functions for altering the text which is currently
4611 within the Entry widget.
4614 void gtk_entry_set_text( GtkEntry *entry,
4615 const gchar *text );
4617 void gtk_entry_append_text( GtkEntry *entry,
4618 const gchar *text );
4620 void gtk_entry_prepend_text( GtkEntry *entry,
4621 const gchar *text );
4624 The function gtk_entry_set_text sets the contents of the Entry widget,
4625 replacing the current contents. The functions gtk_entry_append_text
4626 and gtk_entry_prepend_text allow the current contents to be appended
4629 The next function allows the current insertion point to be set.
4632 void gtk_entry_set_position( GtkEntry *entry,
4636 The contents of the Entry can be retrieved by using a call to the
4637 following function. This is useful in the callback functions described below.
4640 gchar *gtk_entry_get_text( GtkEntry *entry );
4643 The value returned by this function is used internally, and must not
4644 be freed using either free() or g_free()
4646 If we don't want the contents of the Entry to be changed by someone typing
4647 into it, we can change its editable state.
4650 void gtk_entry_set_editable( GtkEntry *entry,
4651 gboolean editable );
4654 The function above allows us to toggle the editable state of the
4655 Entry widget by passing in a TRUE or FALSE value for the <tt/editable/
4658 If we are using the Entry where we don't want the text entered to be
4659 visible, for example when a password is being entered, we can use the
4660 following function, which also takes a boolean flag.
4663 void gtk_entry_set_visibility( GtkEntry *entry,
4667 A region of the text may be set as selected by using the following
4668 function. This would most often be used after setting some default
4669 text in an Entry, making it easy for the user to remove it.
4672 void gtk_entry_select_region( GtkEntry *entry,
4677 If we want to catch when the user has entered text, we can connect to
4678 the <tt/activate/ or <tt/changed/ signal. Activate is raised when the
4679 user hits the enter key within the Entry widget. Changed is raised
4680 when the text changes at all, e.g. for every character entered or
4683 The following code is an example of using an Entry widget.
4686 /* example-start entry entry.c */
4688 #include <gtk/gtk.h>
4690 void enter_callback(GtkWidget *widget, GtkWidget *entry)
4693 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
4694 printf("Entry contents: %s\n", entry_text);
4697 void entry_toggle_editable (GtkWidget *checkbutton,
4700 gtk_entry_set_editable(GTK_ENTRY(entry),
4701 GTK_TOGGLE_BUTTON(checkbutton)->active);
4704 void entry_toggle_visibility (GtkWidget *checkbutton,
4707 gtk_entry_set_visibility(GTK_ENTRY(entry),
4708 GTK_TOGGLE_BUTTON(checkbutton)->active);
4711 int main (int argc, char *argv[])
4715 GtkWidget *vbox, *hbox;
4720 gtk_init (&argc, &argv);
4722 /* create a new window */
4723 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4724 gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
4725 gtk_window_set_title(GTK_WINDOW (window), "GTK Entry");
4726 gtk_signal_connect(GTK_OBJECT (window), "delete_event",
4727 (GtkSignalFunc) gtk_exit, NULL);
4729 vbox = gtk_vbox_new (FALSE, 0);
4730 gtk_container_add (GTK_CONTAINER (window), vbox);
4731 gtk_widget_show (vbox);
4733 entry = gtk_entry_new_with_max_length (50);
4734 gtk_signal_connect(GTK_OBJECT(entry), "activate",
4735 GTK_SIGNAL_FUNC(enter_callback),
4737 gtk_entry_set_text (GTK_ENTRY (entry), "hello");
4738 gtk_entry_append_text (GTK_ENTRY (entry), " world");
4739 gtk_entry_select_region (GTK_ENTRY (entry),
4740 0, GTK_ENTRY(entry)->text_length);
4741 gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0);
4742 gtk_widget_show (entry);
4744 hbox = gtk_hbox_new (FALSE, 0);
4745 gtk_container_add (GTK_CONTAINER (vbox), hbox);
4746 gtk_widget_show (hbox);
4748 check = gtk_check_button_new_with_label("Editable");
4749 gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
4750 gtk_signal_connect (GTK_OBJECT(check), "toggled",
4751 GTK_SIGNAL_FUNC(entry_toggle_editable), entry);
4752 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);
4753 gtk_widget_show (check);
4755 check = gtk_check_button_new_with_label("Visible");
4756 gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
4757 gtk_signal_connect (GTK_OBJECT(check), "toggled",
4758 GTK_SIGNAL_FUNC(entry_toggle_visibility), entry);
4759 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);
4760 gtk_widget_show (check);
4762 button = gtk_button_new_with_label ("Close");
4763 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
4764 GTK_SIGNAL_FUNC(gtk_exit),
4765 GTK_OBJECT (window));
4766 gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
4767 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
4768 gtk_widget_grab_default (button);
4769 gtk_widget_show (button);
4771 gtk_widget_show(window);
4779 <!-- ----------------------------------------------------------------- -->
4782 The Spin Button widget is generally used to allow the user to select a
4783 value from a range of numeric values. It consists of a text
4784 entry box with up and down arrow buttons attached to the
4785 side. Selecting one of the buttons causes the value to 'spin' up and
4786 down the range of possible values. The entry box may also be edited
4787 directly to enter a specific value.
4789 The Spin Button allows the value to have zero or a number of decimal
4790 places and to be incremented/decremented in configurable steps. The
4791 action of holding down one of the buttons optionally result in an
4792 acceleration of change in the value according to how long it is
4795 The Spin Button uses an <ref id="sec_Adjustment" name="Adjustment">
4796 object to hold information about the range of values that the spin
4797 button can take. This makes for a powerful Spin Button widget.
4799 Recall that an adjustment widget is created with the following
4800 function, which illustrates the information that it holds:
4803 GtkObject *gtk_adjustment_new( gfloat value,
4806 gfloat step_increment,
4807 gfloat page_increment,
4811 These attributes of an Adjustment are used by the Spin Button in the
4815 <item> <tt/value/: initial value for the Spin Button
4816 <item> <tt/lower/: lower range value
4817 <item> <tt/upper/: upper range value
4818 <item> <tt/step_increment/: value to increment/decrement when pressing
4819 mouse button 1 on a button
4820 <item> <tt/page_increment/: value to increment/decrement when pressing
4821 mouse button 2 on a button
4822 <item> <tt/page_size/: unused
4825 Additionally, mouse button 3 can be used to jump directly to the
4826 <tt/upper/ or <tt/lower/ values when used to select one of the
4827 buttons. Lets look at how to create a Spin Button:
4830 GtkWidget *gtk_spin_button_new( GtkAdjustment *adjustment,
4835 The <tt/climb_rate/ argument take a value between 0.0 and 1.0 and
4836 indicates the amount of acceleration that the Spin Button has. The
4837 <tt/digits/ argument specifies the number of decimal places to which
4838 the value will be displayed.
4840 A Spin Button can be reconfigured after creation using the following
4844 void gtk_spin_button_configure( GtkSpinButton *spin_button,
4845 GtkAdjustment *adjustment,
4850 The <tt/spin_button/ argument specifies the Spin Button widget that is
4851 to be reconfigured. The other arguments are as specified above.
4853 The adjustment can be set and retrieved independantly using the
4854 following two functions:
4857 void gtk_spin_button_set_adjustment( GtkSpinButton *spin_button,
4858 GtkAdjustment *adjustment );
4860 GtkAdjustment *gtk_spin_button_get_adjustment( GtkSpinButton *spin_button );
4863 The number of decimal places can also be altered using:
4866 void gtk_spin_button_set_digits( GtkSpinButton *spin_button,
4870 The value that a Spin Button is currently displaying can be changed
4871 using the following function:
4874 void gtk_spin_button_set_value( GtkSpinButton *spin_button,
4878 The current value of a Spin Button can be retrieved as either a
4879 floating point or integer value with the following functions:
4882 gfloat gtk_spin_button_get_value_as_float( GtkSpinButton *spin_button );
4884 gint gtk_spin_button_get_value_as_int( GtkSpinButton *spin_button );
4887 If you want to alter the value of a Spin Value relative to its current
4888 value, then the following function can be used:
4891 void gtk_spin_button_spin( GtkSpinButton *spin_button,
4892 GtkSpinType direction,
4896 The <tt/direction/ parameter can take one of the following values:
4899 <item> GTK_SPIN_STEP_FORWARD
4900 <item> GTK_SPIN_STEP_BACKWARD
4901 <item> GTK_SPIN_PAGE_FORWARD
4902 <item> GTK_SPIN_PAGE_BACKWARD
4903 <item> GTK_SPIN_HOME
4905 <item> GTK_SPIN_USER_DEFINED
4908 This function packs in quite a bit of functionality, which I will
4909 attempt to clearly explain. Many of these settings use values from the
4910 Adjustment object that is associated with a Spin Button.
4912 GTK_SPIN_STEP_FORWARD and GTK_SPIN_STEP_BACKWARD change the value of
4913 the Spin Button by the amount specified by <tt/increment/, unless
4914 <tt/increment/ is equal to 0, in which case the value is changed by
4915 the value of <tt/step_increment/ in theAdjustment.
4917 GTK_SPIN_PAGE_FORWARD and GTK_SPIN_PAGE_BACKWARD simply alter the value of
4918 the Spin Button by <tt/increment/.
4920 GTK_SPIN_HOME sets the value of the Spin Button to the bottom of the
4923 GTK_SPIN_END sets the value of the Spin Button to the top of the
4926 GTK_SPIN_USER_DEFINED simply alters the value of the Spin Button by
4927 the specified amount.
4929 We move away from functions for setting and retreving the range attributes
4930 of the Spin Button now, and move onto functions that effect the
4931 appearance and behaviour of the Spin Button widget itself.
4933 The first of these functions is used to constrain the text box of the
4934 Spin Button such that it may only contain a numric value. This
4935 prevents a user from typing anything other than numeric values into
4936 the text box of a Spin Button:
4939 void gtk_spin_button_set_numeric( GtkSpinButton *spin_button,
4943 You can set whether a Spin Button will wrap around between the upper
4944 and lower range values with the following function:
4947 void gtk_spin_button_set_wrap( GtkSpinButton *spin_button,
4951 You can set a Spin Button to round the value to the nearest
4952 <tt/step_increment/, which is set within the Adjustment object used
4953 with the Spin Button. This is accomplished with the following
4957 void gtk_spin_button_set_snap_to_ticks( GtkSpinButton *spin_button,
4958 gboolean snap_to_ticks );
4961 The update policy of a Spin Button can be changed with the following
4965 void gtk_spin_button_set_update_policy( GtkSpinButton *spin_button,
4966 GtkSpinButtonUpdatePolicy policy );
4969 <!-- TODO: find out what this does - TRG -->
4971 The possible values of <tt/policy/ are either GTK_UPDATE_ALWAYS or
4972 GTK_UPDATE_IF_VALID.
4974 These policies affect the behavior of a Spin Button when parsing
4975 inserted text and syncing it's value with the values of the
4978 In the case of GTK_UPDATE_IF_VALID the Spin Button only value gets
4979 changed if the text input is a numeric value that
4980 is within the range specified by the Adjustment. Otherwise
4981 the text is reset to the current value.
4983 In case of GTK_UPDATE_ALWAYS we ignore errors while converting text
4984 into a numeric value.
4986 The appearance of the buttons used in a Spin Button can be changed
4987 using the following function:
4990 void gtk_spin_button_set_shadow_type( GtkSpinButton *spin_button,
4991 GtkShadowType shadow_type );
4994 As usual, the <tt/shadow_type/ can be one of:
4997 <item> GTK_SHADOW_IN
4998 <item> GTK_SHADOW_OUT
4999 <item> GTK_SHADOW_ETCHED_IN
5000 <item> GTK_SHADOW_ETCHED_OUT
5003 Finally, you can explicitly request that a Spin Button update itself:
5006 void gtk_spin_button_update( GtkSpinButton *spin_button );
5009 It's example time again.
5012 /* example-start spinbutton spinbutton.c */
5014 #include <gtk/gtk.h>
5016 static GtkWidget *spinner1;
5018 void toggle_snap( GtkWidget *widget,
5019 GtkSpinButton *spin )
5021 gtk_spin_button_set_snap_to_ticks (spin, GTK_TOGGLE_BUTTON (widget)->active);
5024 void toggle_numeric( GtkWidget *widget,
5025 GtkSpinButton *spin )
5027 gtk_spin_button_set_numeric (spin, GTK_TOGGLE_BUTTON (widget)->active);
5030 void change_digits( GtkWidget *widget,
5031 GtkSpinButton *spin )
5033 gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinner1),
5034 gtk_spin_button_get_value_as_int (spin));
5037 void get_value( GtkWidget *widget,
5042 GtkSpinButton *spin;
5044 spin = GTK_SPIN_BUTTON (spinner1);
5045 label = GTK_LABEL (gtk_object_get_user_data (GTK_OBJECT (widget)));
5046 if (GPOINTER_TO_INT (data) == 1)
5047 sprintf (buf, "%d", gtk_spin_button_get_value_as_int (spin));
5049 sprintf (buf, "%0.*f", spin->digits,
5050 gtk_spin_button_get_value_as_float (spin));
5051 gtk_label_set_text (label, buf);
5061 GtkWidget *main_vbox;
5064 GtkWidget *spinner2;
5068 GtkWidget *val_label;
5071 /* Initialise GTK */
5072 gtk_init(&argc, &argv);
5074 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5076 gtk_signal_connect (GTK_OBJECT (window), "destroy",
5077 GTK_SIGNAL_FUNC (gtk_main_quit),
5080 gtk_window_set_title (GTK_WINDOW (window), "Spin Button");
5082 main_vbox = gtk_vbox_new (FALSE, 5);
5083 gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 10);
5084 gtk_container_add (GTK_CONTAINER (window), main_vbox);
5086 frame = gtk_frame_new ("Not accelerated");
5087 gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
5089 vbox = gtk_vbox_new (FALSE, 0);
5090 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
5091 gtk_container_add (GTK_CONTAINER (frame), vbox);
5093 /* Day, month, year spinners */
5095 hbox = gtk_hbox_new (FALSE, 0);
5096 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
5098 vbox2 = gtk_vbox_new (FALSE, 0);
5099 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5101 label = gtk_label_new ("Day :");
5102 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5103 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5105 adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 31.0, 1.0,
5107 spinner = gtk_spin_button_new (adj, 0, 0);
5108 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
5109 gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
5111 gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5113 vbox2 = gtk_vbox_new (FALSE, 0);
5114 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5116 label = gtk_label_new ("Month :");
5117 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5118 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5120 adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 12.0, 1.0,
5122 spinner = gtk_spin_button_new (adj, 0, 0);
5123 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
5124 gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
5125 GTK_SHADOW_ETCHED_IN);
5126 gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5128 vbox2 = gtk_vbox_new (FALSE, 0);
5129 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5131 label = gtk_label_new ("Year :");
5132 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5133 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5135 adj = (GtkAdjustment *) gtk_adjustment_new (1998.0, 0.0, 2100.0,
5137 spinner = gtk_spin_button_new (adj, 0, 0);
5138 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), FALSE);
5139 gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
5141 gtk_widget_set_usize (spinner, 55, 0);
5142 gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5144 frame = gtk_frame_new ("Accelerated");
5145 gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
5147 vbox = gtk_vbox_new (FALSE, 0);
5148 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
5149 gtk_container_add (GTK_CONTAINER (frame), vbox);
5151 hbox = gtk_hbox_new (FALSE, 0);
5152 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5154 vbox2 = gtk_vbox_new (FALSE, 0);
5155 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5157 label = gtk_label_new ("Value :");
5158 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5159 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5161 adj = (GtkAdjustment *) gtk_adjustment_new (0.0, -10000.0, 10000.0,
5163 spinner1 = gtk_spin_button_new (adj, 1.0, 2);
5164 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner1), TRUE);
5165 gtk_widget_set_usize (spinner1, 100, 0);
5166 gtk_box_pack_start (GTK_BOX (vbox2), spinner1, FALSE, TRUE, 0);
5168 vbox2 = gtk_vbox_new (FALSE, 0);
5169 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5171 label = gtk_label_new ("Digits :");
5172 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5173 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5175 adj = (GtkAdjustment *) gtk_adjustment_new (2, 1, 5, 1, 1, 0);
5176 spinner2 = gtk_spin_button_new (adj, 0.0, 0);
5177 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner2), TRUE);
5178 gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
5179 GTK_SIGNAL_FUNC (change_digits),
5180 (gpointer) spinner2);
5181 gtk_box_pack_start (GTK_BOX (vbox2), spinner2, FALSE, TRUE, 0);
5183 hbox = gtk_hbox_new (FALSE, 0);
5184 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5186 button = gtk_check_button_new_with_label ("Snap to 0.5-ticks");
5187 gtk_signal_connect (GTK_OBJECT (button), "clicked",
5188 GTK_SIGNAL_FUNC (toggle_snap),
5190 gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
5191 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
5193 button = gtk_check_button_new_with_label ("Numeric only input mode");
5194 gtk_signal_connect (GTK_OBJECT (button), "clicked",
5195 GTK_SIGNAL_FUNC (toggle_numeric),
5197 gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
5198 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
5200 val_label = gtk_label_new ("");
5202 hbox = gtk_hbox_new (FALSE, 0);
5203 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5204 button = gtk_button_new_with_label ("Value as Int");
5205 gtk_object_set_user_data (GTK_OBJECT (button), val_label);
5206 gtk_signal_connect (GTK_OBJECT (button), "clicked",
5207 GTK_SIGNAL_FUNC (get_value),
5208 GINT_TO_POINTER (1));
5209 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
5211 button = gtk_button_new_with_label ("Value as Float");
5212 gtk_object_set_user_data (GTK_OBJECT (button), val_label);
5213 gtk_signal_connect (GTK_OBJECT (button), "clicked",
5214 GTK_SIGNAL_FUNC (get_value),
5215 GINT_TO_POINTER (2));
5216 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
5218 gtk_box_pack_start (GTK_BOX (vbox), val_label, TRUE, TRUE, 0);
5219 gtk_label_set_text (GTK_LABEL (val_label), "0");
5221 hbox = gtk_hbox_new (FALSE, 0);
5222 gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, TRUE, 0);
5224 button = gtk_button_new_with_label ("Close");
5225 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
5226 GTK_SIGNAL_FUNC (gtk_widget_destroy),
5227 GTK_OBJECT (window));
5228 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
5230 gtk_widget_show_all (window);
5232 /* Enter the event loop */
5240 <!-- ----------------------------------------------------------------- -->
5243 The combo box is another fairly simple widget that is really just a
5244 collection of other widgets. From the users point of view, the widget
5245 consists of a text entry box and a pull down menu from which the user
5246 can select one of a set of predefined entries. Alternatively, the user
5247 can type a different option directly into the text box.
5249 The following extract from the structure that defines a Combo Box
5250 identifies several of the components:
5263 As you can see, the Combo Box has two principle parts that you really
5264 care about: an entry and a list.
5266 First off, to create a combo box, use:
5269 GtkWidget *gtk_combo_new( void );
5272 Now, if you want to set the string in the entry section of the combo
5273 box, this is done by manipulating the <tt/entry/ widget directly:
5276 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), "My String.");
5279 To set the values in the popdown list, one uses the function:
5282 void gtk_combo_set_popdown_strings( GtkCombo *combo,
5286 Before you can do this, you have to assemble a GList of the strings
5287 that you want. GList is a linked list implementation that is part of
5288 <ref id="sec_glib" name="glib">, a library supporing GTK. For the
5289 moment, the quick and dirty explanation is that you need to set up a
5290 GList pointer, set it equal to NULL, then append strings to it with
5293 GList *g_list_append( GList *glist,
5297 It is important that you set the initial GList pointer to NULL. The
5298 value returned from the g_list_append function must be used as the new
5299 pointer to the GList.
5301 Here's a typical code segment for creating a set of options:
5306 glist = g_list_append(glist, "String 1");
5307 glist = g_list_append(glist, "String 2");
5308 glist = g_list_append(glist, "String 3");
5309 glist = g_list_append(glist, "String 4");
5311 gtk_combo_set_popdown_strings( GTK_COMBO(combo), glist) ;
5314 At this point you have a working combo box that has been set up.
5315 There are a few aspects of its behavior that you can change. These
5316 are accomplished with the functions:
5319 void gtk_combo_set_use_arrows( GtkCombo *combo,
5322 void gtk_combo_set_use_arrows_always( GtkCombo *combo,
5325 void gtk_combo_set_case_sensitive( GtkCombo *combo,
5329 <tt/gtk_combo_set_use_arrows()/ lets the user change the value in the
5330 entry using the up/down arrow keys. This doesn't bring up the list, but
5331 rather replaces the current text in the entry with the next list entry
5332 (up or down, as your key choice indicates). It does this by searching
5333 in the list for the item corresponding to the current value in the
5334 entry and selecting the previous/next item accordingly. Usually in an
5335 entry the arrow keys are used to change focus (you can do that anyway
5336 using TAB). Note that when the current item is the last of the list
5337 and you press arrow-down it changes the focus (the same applies with
5338 the first item and arrow-up).
5340 If the current value in the entry is not in the list, then the
5341 function of <tt/gtk_combo_set_use_arrows()/ is disabled.
5343 <tt/gtk_combo_set_use_arrows_always()/ similarly allows the use the
5344 the up/down arrow keys to cycle through the choices in the dropdown
5345 list, except that it wraps around the values in the list, completely
5346 disabling the use of the up and down arrow keys for changing focus.
5348 <tt/gtk_combo_set_case_sensitive()/ toggles whether or not GTK
5349 searches for entries in a case sensitive manner. This is used when
5350 the Combo widget is asked to find a value from the list using the
5351 current entry in the text box. This completion can be performed in
5352 eother a case sensitive or insensitive manner, depending upon the use
5353 of this function. The Combo widget can also simply complete the
5354 current entry if the user presses the key combination MOD-1 and
5355 'Tab'. MOD-1 is often mapped to the 'Alt' key. Note, however that some
5356 Window managers also use this key combination, which will override
5357 it's use within GTK.
5359 Now that we have a combo box, tailored to look and act how we want it,
5360 all that remains is being able to get data from the combo box. This is
5361 relatively straight forward. The majority of the time, all you are
5362 going to care about getting data from is the entry. The entry is
5363 accessed simply by GTK_ENTRY(GTK_COMBO(combo)->entry). The two
5364 principle things that you are going to want to do with it are attach
5365 to the activate signal, which indicates that the user has pressed the
5366 Return or Enter key,and read the text. The first is accomplished
5367 using something like:
5370 gtk_signal_connect(GTK_OBJECT(GTK_COMB(combo)->entry), "activate",
5371 GTK_SIGNAL_FUNC (my_callback_function), my_data);
5374 Getting the text at any arbitrary time is accomplished by simply using
5378 gchar *gtk_entry_get_text(GtkEntry *entry);
5386 string = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry));
5389 That's about all there is to it. There is a function
5392 void gtk_combo_disable_activate(GtkCombo *combo);
5395 that will disable the activate signal on the entry widget in the combo
5396 box. Personally, I can't think of why you'd want to use it, but it
5399 <!-- There are also a function to set the string on a particular item, void
5400 gtk_combo_set_item_string(GtkCombo *combo, GtkItem *item, const gchar
5401 *item_value), but this requires that you have a pointer to the
5402 appropriate GtkItem. Frankly, I have no idea how to do that.
5405 <!-- ----------------------------------------------------------------- -->
5406 <sect1> Color Selection
5408 The color selection widget is, not surprisingly, a widget for
5409 interactive selection of colors. This composite widget lets the user
5410 select a color by manipulating RGB (Red, Green, Blue) and HSV (Hue,
5411 Saturation, Value) triples. This is done either by adjusting single
5412 values with sliders or entries, or by picking the desired color from a
5413 hue-saturation wheel/value bar. Optionally, the opacity of the color
5416 The color selection widget currently emits only one signal,
5417 "color_changed", which is emitted whenever the current color in the
5418 widget changes, either when the user changes it or if it's set
5419 explicitly through gtk_color_selection_set_color().
5421 Lets have a look at what the color selection widget has to offer
5422 us. The widget comes in two flavours: gtk_color_selection and
5423 gtk_color_selection_dialog.
5426 GtkWidget *gtk_color_selection_new( void );
5429 You'll probably not be using this constructor directly. It creates an
5430 orphan GtkColorSelection widget which you'll have to parent
5431 yourself. The GtkColorSelection widget inherits from the GtkVBox
5435 GtkWidget *gtk_color_selection_dialog_new( const gchar *title );
5438 This is the most common color selection constructor. It creates a
5439 GtkColorSelectionDialog, which inherits from a GtkDialog. It consists
5440 of a GtkFrame containing a GtkColorSelection widget, a GtkHSeparator
5441 and a GtkHBox with three buttons, "Ok", "Cancel" and "Help". You can
5442 reach these buttons by accessing the "ok_button", "cancel_button" and
5443 "help_button" widgets in the GtkColorSelectionDialog structure,
5444 (i.e. GTK_COLOR_SELECTION_DIALOG(colorseldialog)->ok_button).
5447 void gtk_color_selection_set_update_policy( GtkColorSelection *colorsel,
5448 GtkUpdateType policy );
5451 This function sets the update policy. The default policy is
5452 GTK_UPDATE_CONTINUOUS which means that the current color is updated
5453 continuously when the user drags the sliders or presses the mouse and
5454 drags in the hue-saturation wheel or value bar. If you experience
5455 performance problems, you may want to set the policy to
5456 GTK_UPDATE_DISCONTINUOUS or GTK_UPDATE_DELAYED.
5459 void gtk_color_selection_set_opacity( GtkColorSelection *colorsel,
5463 The color selection widget supports adjusting the opacity of a color
5464 (also known as the alpha channel). This is disabled by
5465 default. Calling this function with use_opacity set to TRUE enables
5466 opacity. Likewise, use_opacity set to FALSE will disable opacity.
5469 void gtk_color_selection_set_color( GtkColorSelection *colorsel,
5473 You can set the current color explicitly by calling this function with
5474 a pointer to an array of colors (gdouble). The length of the array
5475 depends on whether opacity is enabled or not. Position 0 contains the
5476 red component, 1 is green, 2 is blue and opacity is at position 3
5477 (only if opacity is enabled, see
5478 gtk_color_selection_set_opacity()). All values are between 0.0 and
5482 void gtk_color_selection_get_color( GtkColorSelection *colorsel,
5486 When you need to query the current color, typically when you've
5487 received a "color_changed" signal, you use this function. Color is a
5488 pointer to the array of colors to fill in. See the
5489 gtk_color_selection_set_color() function for the description of this
5492 <!-- Need to do a whole section on DnD - TRG
5496 The color sample areas (right under the hue-saturation wheel) supports
5497 drag and drop. The type of drag and drop is "application/x-color". The
5498 message data consists of an array of 4 (or 5 if opacity is enabled)
5499 gdouble values, where the value at position 0 is 0.0 (opacity on) or
5500 1.0 (opacity off) followed by the red, green and blue values at
5501 positions 1,2 and 3 respectively. If opacity is enabled, the opacity
5502 is passed in the value at position 4.
5505 Here's a simple example demonstrating the use of the
5506 GtkColorSelectionDialog. The program displays a window containing a
5507 drawing area. Clicking on it opens a color selection dialog, and
5508 changing the color in the color selection dialog changes the
5512 /* example-start colorsel colorsel.c */
5515 #include <gdk/gdk.h>
5516 #include <gtk/gtk.h>
5518 GtkWidget *colorseldlg = NULL;
5519 GtkWidget *drawingarea = NULL;
5521 /* Color changed handler */
5523 void color_changed_cb (GtkWidget *widget, GtkColorSelection *colorsel)
5527 GdkColormap *colormap;
5529 /* Get drawingarea colormap */
5531 colormap = gdk_window_get_colormap (drawingarea->window);
5533 /* Get current color */
5535 gtk_color_selection_get_color (colorsel,color);
5537 /* Fit to a unsigned 16 bit integer (0..65535) and
5538 * insert into the GdkColor structure */
5540 gdk_color.red = (guint16)(color[0]*65535.0);
5541 gdk_color.green = (guint16)(color[1]*65535.0);
5542 gdk_color.blue = (guint16)(color[2]*65535.0);
5544 /* Allocate color */
5546 gdk_color_alloc (colormap, &gdk_color);
5548 /* Set window background color */
5550 gdk_window_set_background (drawingarea->window, &gdk_color);
5554 gdk_window_clear (drawingarea->window);
5557 /* Drawingarea event handler */
5559 gint area_event (GtkWidget *widget, GdkEvent *event, gpointer client_data)
5561 gint handled = FALSE;
5562 GtkWidget *colorsel;
5564 /* Check if we've received a button pressed event */
5566 if (event->type == GDK_BUTTON_PRESS && colorseldlg == NULL)
5568 /* Yes, we have an event and there's no colorseldlg yet! */
5572 /* Create color selection dialog */
5574 colorseldlg = gtk_color_selection_dialog_new("Select background color");
5576 /* Get the GtkColorSelection widget */
5578 colorsel = GTK_COLOR_SELECTION_DIALOG(colorseldlg)->colorsel;
5580 /* Connect to the "color_changed" signal, set the client-data
5581 * to the colorsel widget */
5583 gtk_signal_connect(GTK_OBJECT(colorsel), "color_changed",
5584 (GtkSignalFunc)color_changed_cb, (gpointer)colorsel);
5586 /* Show the dialog */
5588 gtk_widget_show(colorseldlg);
5594 /* Close down and exit handler */
5596 void destroy_window (GtkWidget *widget, gpointer client_data)
5603 gint main (gint argc, gchar *argv[])
5607 /* Initialize the toolkit, remove gtk-related commandline stuff */
5609 gtk_init (&argc,&argv);
5611 /* Create toplevel window, set title and policies */
5613 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5614 gtk_window_set_title (GTK_WINDOW(window), "Color selection test");
5615 gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, TRUE);
5617 /* Attach to the "delete" and "destroy" events so we can exit */
5619 gtk_signal_connect (GTK_OBJECT(window), "delete_event",
5620 (GtkSignalFunc)destroy_window, (gpointer)window);
5622 gtk_signal_connect (GTK_OBJECT(window), "destroy",
5623 (GtkSignalFunc)destroy_window, (gpointer)window);
5625 /* Create drawingarea, set size and catch button events */
5627 drawingarea = gtk_drawing_area_new ();
5629 gtk_drawing_area_size (GTK_DRAWING_AREA(drawingarea), 200, 200);
5631 gtk_widget_set_events (drawingarea, GDK_BUTTON_PRESS_MASK);
5633 gtk_signal_connect (GTK_OBJECT(drawingarea), "event",
5634 (GtkSignalFunc)area_event, (gpointer)drawingarea);
5636 /* Add drawingarea to window, then show them both */
5638 gtk_container_add (GTK_CONTAINER(window), drawingarea);
5640 gtk_widget_show (drawingarea);
5641 gtk_widget_show (window);
5643 /* Enter the gtk main loop (this never returns) */
5647 /* Satisfy grumpy compilers */
5654 <!-- ----------------------------------------------------------------- -->
5655 <sect1> File Selections
5657 The file selection widget is a quick and simple way to display a File
5658 dialog box. It comes complete with Ok, Cancel, and Help buttons, a
5659 great way to cut down on programming time.
5661 To create a new file selection box use:
5664 GtkWidget *gtk_file_selection_new( gchar *title );
5667 To set the filename, for example to bring up a specific directory, or
5668 give a default filename, use this function:
5671 void gtk_file_selection_set_filename( GtkFileSelection *filesel,
5675 To grab the text that the user has entered or clicked on, use this
5679 gchar *gtk_file_selection_get_filename( GtkFileSelection *filesel );
5682 There are also pointers to the widgets contained within the file
5683 selection widget. These are:
5688 <item>selection_entry
5689 <item>selection_text
5696 Most likely you will want to use the ok_button, cancel_button, and
5697 help_button pointers in signaling their use.
5699 Included here is an example stolen from testgtk.c, modified to run on
5700 its own. As you will see, there is nothing much to creating a file
5701 selection widget. While in this example the Help button appears on the
5702 screen, it does nothing as there is not a signal attached to it.
5705 /* example-start filesel filesel.c */
5707 #include <gtk/gtk.h>
5709 /* Get the selected filename and print it to the console */
5710 void file_ok_sel (GtkWidget *w, GtkFileSelection *fs)
5712 g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
5715 void destroy (GtkWidget *widget, gpointer data)
5720 int main (int argc, char *argv[])
5724 gtk_init (&argc, &argv);
5726 /* Create a new file selection widget */
5727 filew = gtk_file_selection_new ("File selection");
5729 gtk_signal_connect (GTK_OBJECT (filew), "destroy",
5730 (GtkSignalFunc) destroy, &filew);
5731 /* Connect the ok_button to file_ok_sel function */
5732 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
5733 "clicked", (GtkSignalFunc) file_ok_sel, filew );
5735 /* Connect the cancel_button to destroy the widget */
5736 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION
5737 (filew)->cancel_button),
5738 "clicked", (GtkSignalFunc) gtk_widget_destroy,
5739 GTK_OBJECT (filew));
5741 /* Lets set the filename, as if this were a save dialog, and we are giving
5742 a default filename */
5743 gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew),
5746 gtk_widget_show(filew);
5753 <!-- ***************************************************************** -->
5754 <sect> Container Widgets
5755 <!-- ***************************************************************** -->
5757 <!-- ----------------------------------------------------------------- -->
5758 <sect1>The EventBox <label id="sec_EventBox">
5760 Some GTK widgets don't have associated X windows, so they just draw on
5761 their parents. Because of this, they cannot receive events and if they
5762 are incorrectly sized, they don't clip so you can get messy
5763 overwriting etc. If you require more from these widgets, the EventBox
5766 At first glance, the EventBox widget might appear to be totally
5767 useless. It draws nothing on the screen and responds to no
5768 events. However, it does serve a function - it provides an X window
5769 for its child widget. This is important as many GTK widgets do not
5770 have an associated X window. Not having an X window saves memory and
5771 improves performance, but also has some drawbacks. A widget without an
5772 X window cannot receive events, and does not perform any clipping on
5773 its contents. Although the name <em/EventBox/ emphasizes the
5774 event-handling function, the widget can also be used for clipping.
5775 (and more, see the example below).
5777 To create a new EventBox widget, use:
5780 GtkWidget *gtk_event_box_new( void );
5783 A child widget can then be added to this EventBox:
5786 gtk_container_add( GTK_CONTAINER(event_box), child_widget );
5789 The following example demonstrates both uses of an EventBox - a label
5790 is created that is clipped to a small box, and set up so that a
5791 mouse-click on the label causes the program to exit. Resizing the
5792 window reveals varying amounts of the label.
5795 /* example-start eventbox eventbox.c */
5797 #include <gtk/gtk.h>
5800 main (int argc, char *argv[])
5803 GtkWidget *event_box;
5806 gtk_init (&argc, &argv);
5808 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5810 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
5812 gtk_signal_connect (GTK_OBJECT (window), "destroy",
5813 GTK_SIGNAL_FUNC (gtk_exit), NULL);
5815 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
5817 /* Create an EventBox and add it to our toplevel window */
5819 event_box = gtk_event_box_new ();
5820 gtk_container_add (GTK_CONTAINER(window), event_box);
5821 gtk_widget_show (event_box);
5823 /* Create a long label */
5825 label = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
5826 gtk_container_add (GTK_CONTAINER (event_box), label);
5827 gtk_widget_show (label);
5829 /* Clip it short. */
5830 gtk_widget_set_usize (label, 110, 20);
5832 /* And bind an action to it */
5833 gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
5834 gtk_signal_connect (GTK_OBJECT(event_box), "button_press_event",
5835 GTK_SIGNAL_FUNC (gtk_exit), NULL);
5837 /* Yet one more thing you need an X window for ... */
5839 gtk_widget_realize (event_box);
5840 gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1));
5842 gtk_widget_show (window);
5851 <!-- ----------------------------------------------------------------- -->
5852 <sect1>The Alignment widget <label id="sec_Alignment">
5854 The alignment widget allows you to place a widget within its window at
5855 a position and size relative to the size of the Alignment widget
5856 itself. For example, it can be very useful for centering a widget
5859 There are only two functions associated with the Alignment widget:
5862 GtkWidget* gtk_alignment_new( gfloat xalign,
5867 void gtk_alignment_set( GtkAlignment *alignment,
5874 The first function creates a new Alignment widget with the specified
5875 parameters. The second function allows the alignment paramters of an
5876 exisiting Alignment widget to be altered.
5878 All four alignment parameters are floating point numbers which can
5879 range from 0.0 to 1.0. The <tt/xalign/ and <tt/yalign/ arguments
5880 affect the position of the widget placed within the Alignment
5881 widget. The <tt/xscale/ and <tt/yscale/ arguments effect the amount of
5882 space allocated to the widget.
5884 A child widget can be added to this Alignment widget using:
5887 gtk_container_add( GTK_CONTAINER(alignment), child_widget );
5890 For an example of using an Alignment widget, refer to the example for
5891 the <ref id="sec_ProgressBar" name="Progress Bar"> widget.
5893 <!-- ----------------------------------------------------------------- -->
5894 <sect1> Fixed Container
5896 The Fixed container allows you to place widgets at a fixed position
5897 within it's window, relative to it's upper left hand corner. The
5898 position of the widgets can be changed dynamically.
5900 There are only three functions associated with the fixed widget:
5903 GtkWidget* gtk_fixed_new( void );
5905 void gtk_fixed_put( GtkFixed *fixed,
5910 void gtk_fixed_move( GtkFixed *fixed,
5916 The function <tt/gtk_fixed_new/ allows you to create a new Fixed
5919 <tt/gtk_fixed_put/ places <tt/widget/ in the container <tt/fixed/ at
5920 the position specified by <tt/x/ and <tt/y/.
5922 <tt/gtk_fixed_move/ allows the specified widget to be moved to a new
5925 The following example illustrates how to use the Fixed Container.
5928 /* example-start fixed fixed.c */
5930 #include <gtk/gtk.h>
5932 /* I'm going to be lazy and use some global variables to
5933 * store the position of the widget within the fixed
5938 /* This callback function moves the button to a new position
5939 * in the Fixed container. */
5940 void move_button( GtkWidget *widget,
5945 gtk_fixed_move( GTK_FIXED(fixed), widget, x, y);
5951 /* GtkWidget is the storage type for widgets */
5957 /* Initialise GTK */
5958 gtk_init(&argc, &argv);
5960 /* Create a new window */
5961 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5962 gtk_window_set_title(GTK_WINDOW(window), "Fixed Container");
5964 /* Here we connect the "destroy" event to a signal handler */
5965 gtk_signal_connect (GTK_OBJECT (window), "destroy",
5966 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
5968 /* Sets the border width of the window. */
5969 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
5971 /* Create a Fixed Container */
5972 fixed = gtk_fixed_new();
5973 gtk_container_add(GTK_CONTAINER(window), fixed);
5974 gtk_widget_show(fixed);
5976 for (i = 1 ; i <= 3 ; i++) {
5977 /* Creates a new button with the label "Press me" */
5978 button = gtk_button_new_with_label ("Press me");
5980 /* When the button receives the "clicked" signal, it will call the
5981 * function move_button() passing it the Fixed Containter as its
5983 gtk_signal_connect (GTK_OBJECT (button), "clicked",
5984 GTK_SIGNAL_FUNC (move_button), fixed);
5986 /* This packs the button into the fixed containers window. */
5987 gtk_fixed_put (GTK_FIXED (fixed), button, i*50, i*50);
5989 /* The final step is to display this newly created widget. */
5990 gtk_widget_show (button);
5993 /* Display the window */
5994 gtk_widget_show (window);
5996 /* Enter the event loop */
6004 <!-- ----------------------------------------------------------------- -->
6005 <sect1> Layout Container
6007 The Layout container is similar to the Fixed container except that it
6008 implements an infinite (where infinity is less than 2^32) scrolling
6009 area. Xwindows has a limitation where windows can be at most 32767
6010 pixels wide or tall. The Layout container gets around this limitation
6011 by doing some exotic stuff using window and bit gravities, so that you
6012 can have smooth scrolling even when you have many child widgets in
6013 your scrolling area.
6015 A Layout container is created using:
6018 GtkWidget *gtk_layout_new( GtkAdjustment *hadjustment,
6019 GtkAdjustment *vadjustment );
6022 As you can see, you can optionally specify the Adjustment objects that
6023 the Layout widget will use for it's scrolling.
6025 You can add and move widgets in the Layout container using the
6026 following two functions:
6029 void gtk_layout_put( GtkLayout *layout,
6034 void gtk_layout_move( GtkLayout *layout,
6040 The size of the Layout container can be set using the next function:
6043 void gtk_layout_set_size( GtkLayout *layout,
6048 Layout containers are one of the very few widgets in the GTK widget
6049 set that actively repaint themselves on screen as they are changed
6050 using the above functions (the vast majority of widgets queue
6051 requests which are then processed when control returns to the
6052 <tt/gtk_main()/ function).
6054 When you want to make a large number of changes to a Layout container,
6055 you can use the following two functions to disable and re-enable this
6056 repainting functionality:
6059 void gtk_layout_freeze( GtkLayout *layout );
6061 void gtk_layout_thaw( GtkLayout *layout );
6064 The final four functions for use with Layout widgets are for
6065 manipulating the horizontal and vertical adjustment widgets:
6068 GtkAdjustment* gtk_layout_get_hadjustment( GtkLayout *layout );
6070 GtkAdjustment* gtk_layout_get_vadjustment( GtkLayout *layout );
6072 void gtk_layout_set_hadjustment( GtkLayout *layout,
6073 GtkAdjustment *adjustment );
6075 void gtk_layout_set_vadjustment( GtkLayout *layout,
6076 GtkAdjustment *adjustment);
6079 <!-- ----------------------------------------------------------------- -->
6080 <sect1> Frames <label id="sec_Frames">
6082 Frames can be used to enclose one or a group of widgets with a box
6083 which can optionally be labelled. The position of the label and the
6084 style of the box can be altered to suit.
6086 A Frame can be created with the following function:
6089 GtkWidget *gtk_frame_new( const gchar *label );
6092 The label is by default placed in the upper left hand corner of the
6093 frame. A value of NULL for the <tt/label/ argument will result in no
6094 label being displayed. The text of the label can be changed using the
6098 void gtk_frame_set_label( GtkFrame *frame,
6099 const gchar *label );
6102 The position of the label can be changed using this function:
6105 void gtk_frame_set_label_align( GtkFrame *frame,
6110 <tt/xalign/ and <tt/yalign/ take values between 0.0 and 1.0. <tt/xalign/
6111 indicates the position of the label along the top horizontal of the
6112 frame. <tt/yalign/ is not currently used. The default value of xalign
6113 is 0.0 which places the label at the left hand end of the frame.
6115 The next function alters the style of the box that is used to outline
6119 void gtk_frame_set_shadow_type( GtkFrame *frame,
6120 GtkShadowType type);
6123 The <tt/type/ argument can take one of the following values:
6125 <item> GTK_SHADOW_NONE
6126 <item> GTK_SHADOW_IN
6127 <item> GTK_SHADOW_OUT
6128 <item> GTK_SHADOW_ETCHED_IN (the default)
6129 <item> GTK_SHADOW_ETCHED_OUT
6132 The following code example illustrates the use of the Frame widget.
6135 /* example-start frame frame.c */
6137 #include <gtk/gtk.h>
6142 /* GtkWidget is the storage type for widgets */
6148 /* Initialise GTK */
6149 gtk_init(&argc, &argv);
6151 /* Create a new window */
6152 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6153 gtk_window_set_title(GTK_WINDOW(window), "Frame Example");
6155 /* Here we connect the "destroy" event to a signal handler */
6156 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6157 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
6159 gtk_widget_set_usize(window, 300, 300);
6160 /* Sets the border width of the window. */
6161 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6163 /* Create a Frame */
6164 frame = gtk_frame_new(NULL);
6165 gtk_container_add(GTK_CONTAINER(window), frame);
6167 /* Set the frames label */
6168 gtk_frame_set_label( GTK_FRAME(frame), "GTK Frame Widget" );
6170 /* Align the label at the right of the frame */
6171 gtk_frame_set_label_align( GTK_FRAME(frame), 1.0, 0.0);
6173 /* Set the style of the frame */
6174 gtk_frame_set_shadow_type( GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
6176 gtk_widget_show(frame);
6178 /* Display the window */
6179 gtk_widget_show (window);
6181 /* Enter the event loop */
6190 <!-- ----------------------------------------------------------------- -->
6191 <sect1> Aspect Frames
6193 The aspect frame widget is like a frame widget, except that it also
6194 enforces the aspect ratio (that is, the ratio of the width to the
6195 height) of the child widget to have a certain value, adding extra
6196 space if necessary. This is useful, for instance, if you want to
6197 preview a larger image. The size of the preview should vary when the
6198 user resizes the window, but the aspect ratio needs to always match
6201 To create a new aspect frame use:
6204 GtkWidget *gtk_aspect_frame_new( const gchar *label,
6211 <tt/xalign/ and <tt/yalign/ specify alignment as with Alignment
6212 widgets. If <tt/obey_child/ is true, the aspect ratio of a child
6213 widget will match the aspect ratio of the ideal size it requests.
6214 Otherwise, it is given by <tt/ratio/.
6216 To change the options of an existing aspect frame, you can use:
6219 void gtk_aspect_frame_set( GtkAspectFrame *aspect_frame,
6226 As an example, the following program uses an AspectFrame to present a
6227 drawing area whose aspect ratio will always be 2:1, no matter how the
6228 user resizes the top-level window.
6231 /* example-start aspectframe aspectframe.c */
6233 #include <gtk/gtk.h>
6236 main (int argc, char *argv[])
6239 GtkWidget *aspect_frame;
6240 GtkWidget *drawing_area;
6241 gtk_init (&argc, &argv);
6243 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6244 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
6245 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6246 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
6247 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6249 /* Create an aspect_frame and add it to our toplevel window */
6251 aspect_frame = gtk_aspect_frame_new ("2x1", /* label */
6254 2, /* xsize/ysize = 2 */
6255 FALSE /* ignore child's aspect */);
6257 gtk_container_add (GTK_CONTAINER(window), aspect_frame);
6258 gtk_widget_show (aspect_frame);
6260 /* Now add a child widget to the aspect frame */
6262 drawing_area = gtk_drawing_area_new ();
6264 /* Ask for a 200x200 window, but the AspectFrame will give us a 200x100
6265 * window since we are forcing a 2x1 aspect ratio */
6266 gtk_widget_set_usize (drawing_area, 200, 200);
6267 gtk_container_add (GTK_CONTAINER(aspect_frame), drawing_area);
6268 gtk_widget_show (drawing_area);
6270 gtk_widget_show (window);
6277 <!-- ----------------------------------------------------------------- -->
6278 <sect1> Paned Window Widgets
6280 The paned window widgets are useful when you want to divide an area
6281 into two parts, with the relative size of the two parts controlled by
6282 the user. A groove is drawn between the two portions with a handle
6283 that the user can drag to change the ratio. The division can either be
6284 horizontal (HPaned) or vertical (VPaned).
6286 To create a new paned window, call one of:
6289 GtkWidget *gtk_hpaned_new (void);
6291 GtkWidget *gtk_vpaned_new (void);
6294 After creating the paned window widget, you need to add child widgets
6295 to its two halves. To do this, use the functions:
6298 void gtk_paned_add1 (GtkPaned *paned, GtkWidget *child);
6300 void gtk_paned_add2 (GtkPaned *paned, GtkWidget *child);
6303 <tt/gtk_paned_add1()/ adds the child widget to the left or top half of
6304 the paned window. <tt/gtk_paned_add2()/ adds the child widget to the
6305 right or bottom half of the paned window.
6307 A paned widget can be changed visually using the following two
6311 void gtk_paned_set_handle_size( GtkPaned *paned,
6314 void gtk_paned_set_gutter_size( GtkPaned *paned,
6318 The first of these sets the size of the handle and the second sets the
6319 size of the gutter that is between the two parts of the paned window.
6321 As an example, we will create part of the user interface of an
6322 imaginary email program. A window is divided into two portions
6323 vertically, with the top portion being a list of email messages and
6324 the bottom portion the text of the email message. Most of the program
6325 is pretty straightforward. A couple of points to note: text can't be
6326 added to a Text widget until it is realized. This could be done by
6327 calling <tt/gtk_widget_realize()/, but as a demonstration of an
6328 alternate technique, we connect a handler to the "realize" signal to
6329 add the text. Also, we need to add the <tt/GTK_SHRINK/ option to some
6330 of the items in the table containing the text window and its
6331 scrollbars, so that when the bottom portion is made smaller, the
6332 correct portions shrink instead of being pushed off the bottom of the
6336 /* example-start paned paned.c */
6338 #include <gtk/gtk.h>
6340 /* Create the list of "messages" */
6345 GtkWidget *scrolled_window;
6347 GtkWidget *list_item;
6352 /* Create a new scrolled window, with scrollbars only if needed */
6353 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
6354 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
6355 GTK_POLICY_AUTOMATIC,
6356 GTK_POLICY_AUTOMATIC);
6358 /* Create a new list and put it in the scrolled window */
6359 list = gtk_list_new ();
6360 gtk_scrolled_window_add_with_viewport (
6361 GTK_SCROLLED_WINDOW (scrolled_window), list);
6362 gtk_widget_show (list);
6364 /* Add some messages to the window */
6365 for (i=0; i<10; i++) {
6367 sprintf(buffer,"Message #%d",i);
6368 list_item = gtk_list_item_new_with_label (buffer);
6369 gtk_container_add (GTK_CONTAINER(list), list_item);
6370 gtk_widget_show (list_item);
6374 return scrolled_window;
6377 /* Add some text to our text widget - this is a callback that is invoked
6378 when our window is realized. We could also force our window to be
6379 realized with gtk_widget_realize, but it would have to be part of
6380 a hierarchy first */
6383 realize_text (GtkWidget *text, gpointer data)
6385 gtk_text_freeze (GTK_TEXT (text));
6386 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
6387 "From: pathfinder@nasa.gov\n"
6388 "To: mom@nasa.gov\n"
6389 "Subject: Made it!\n"
6391 "We just got in this morning. The weather has been\n"
6392 "great - clear but cold, and there are lots of fun sights.\n"
6393 "Sojourner says hi. See you soon.\n"
6396 gtk_text_thaw (GTK_TEXT (text));
6399 /* Create a scrolled text area that displays a "message" */
6405 GtkWidget *hscrollbar;
6406 GtkWidget *vscrollbar;
6408 /* Create a table to hold the text widget and scrollbars */
6409 table = gtk_table_new (2, 2, FALSE);
6411 /* Put a text widget in the upper left hand corner. Note the use of
6412 * GTK_SHRINK in the y direction */
6413 text = gtk_text_new (NULL, NULL);
6414 gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
6415 GTK_FILL | GTK_EXPAND,
6416 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
6417 gtk_widget_show (text);
6419 /* Put a HScrollbar in the lower left hand corner */
6420 hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
6421 gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
6422 GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
6423 gtk_widget_show (hscrollbar);
6425 /* And a VScrollbar in the upper right */
6426 vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
6427 gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
6428 GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
6429 gtk_widget_show (vscrollbar);
6431 /* Add a handler to put a message in the text widget when it is realized */
6432 gtk_signal_connect (GTK_OBJECT (text), "realize",
6433 GTK_SIGNAL_FUNC (realize_text), NULL);
6439 main (int argc, char *argv[])
6446 gtk_init (&argc, &argv);
6448 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6449 gtk_window_set_title (GTK_WINDOW (window), "Paned Windows");
6450 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6451 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
6452 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6453 gtk_widget_set_usize (GTK_WIDGET(window), 450, 400);
6455 /* create a vpaned widget and add it to our toplevel window */
6457 vpaned = gtk_vpaned_new ();
6458 gtk_container_add (GTK_CONTAINER(window), vpaned);
6459 gtk_paned_set_handle_size (GTK_PANED(vpaned),
6461 gtk_paned_set_gutter_size (GTK_PANED(vpaned),
6463 gtk_widget_show (vpaned);
6465 /* Now create the contents of the two halves of the window */
6467 list = create_list ();
6468 gtk_paned_add1 (GTK_PANED(vpaned), list);
6469 gtk_widget_show (list);
6471 text = create_text ();
6472 gtk_paned_add2 (GTK_PANED(vpaned), text);
6473 gtk_widget_show (text);
6474 gtk_widget_show (window);
6481 <!-- ----------------------------------------------------------------- -->
6482 <sect1>Viewports <label id="sec_Viewports">
6484 It is unlikely that you will ever need to use the Viewport widget
6485 directly. You are much more likely to use the
6486 <ref id="sec_ScrolledWindows" name="Scrolled Windows"> widget which
6487 itself uses the Viewport.
6489 A viewport widget allows you to place a larger widget within it such
6490 that you can view a part of it at a time. It uses
6491 <ref id="sec_Adjustment" name="Adjustments"> to define the area that
6492 is currently in view.
6494 A Viewport is created with the function
6497 GtkWidget *gtk_viewport_new( GtkAdjustment *hadjustment,
6498 GtkAdjustment *vadjustment );
6501 As you can see you can specify the horizontal and vertical Adjustments
6502 that the widget is to use when you create the widget. It will create
6503 it's own if you pass NULL as the value of the arguments.
6505 You can get and set the adjustments after the widget has been created
6506 using the following four functions:
6509 GtkAdjustment *gtk_viewport_get_hadjustment (GtkViewport *viewport );
6511 GtkAdjustment *gtk_viewport_get_vadjustment (GtkViewport *viewport );
6513 void gtk_viewport_set_hadjustment( GtkViewport *viewport,
6514 GtkAdjustment *adjustment );
6516 void gtk_viewport_set_vadjustment( GtkViewport *viewport,
6517 GtkAdjustment *adjustment );
6520 The only other viewport function is used to alter its appearance:
6523 void gtk_viewport_set_shadow_type( GtkViewport *viewport,
6524 GtkShadowType type );
6527 Possible values for the <tt/type/ parameter are:
6529 <item> GTK_SHADOW_NONE,
6530 <item> GTK_SHADOW_IN,
6531 <item> GTK_SHADOW_OUT,
6532 <item> GTK_SHADOW_ETCHED_IN,
6533 <item> GTK_SHADOW_ETCHED_OUT
6536 <!-- ----------------------------------------------------------------- -->
6537 <sect1>Scrolled Windows <label id="sec_ScrolledWindows">
6539 Scrolled windows are used to create a scrollable area inside a real
6540 window. You may insert any type of widget into a scrolled window, and
6541 it will be accessible regardless of the size by using the scrollbars.
6543 The following function is used to create a new scrolled window.
6546 GtkWidget *gtk_scrolled_window_new( GtkAdjustment *hadjustment,
6547 GtkAdjustment *vadjustment );
6550 Where the first argument is the adjustment for the horizontal
6551 direction, and the second, the adjustment for the vertical direction.
6552 These are almost always set to NULL.
6555 void gtk_scrolled_window_set_policy( GtkScrolledWindow *scrolled_window,
6556 GtkPolicyType hscrollbar_policy,
6557 GtkPolicyType vscrollbar_policy );
6560 This sets the policy to be used with respect to the scrollbars.
6561 The first argument is the scrolled window you wish to change. The second
6562 sets the policy for the horizontal scrollbar, and the third the policy for
6563 the vertical scrollbar.
6565 The policy may be one of GTK_POLICY_AUTOMATIC, or GTK_POLICY_ALWAYS.
6566 GTK_POLICY_AUTOMATIC will automatically decide whether you need
6567 scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars
6570 You can then place your object into the scrolled window using the
6574 void gtk_scrolled_window_add_with_viewport( GtkScrolledWindow *scrolled_window,
6578 Here is a simple example that packs 100 toggle buttons into a scrolled
6579 window. I've only commented on the parts that may be new to you.
6582 /* example-start scrolledwin scrolledwin.c */
6584 #include <gtk/gtk.h>
6586 void destroy(GtkWidget *widget, gpointer data)
6591 int main (int argc, char *argv[])
6593 static GtkWidget *window;
6594 GtkWidget *scrolled_window;
6600 gtk_init (&argc, &argv);
6602 /* Create a new dialog window for the scrolled window to be
6603 * packed into. A dialog is just like a normal window except it has a
6604 * vbox and a horizontal separator packed into it. It's just a shortcut
6605 * for creating dialogs */
6606 window = gtk_dialog_new ();
6607 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6608 (GtkSignalFunc) destroy, NULL);
6609 gtk_window_set_title (GTK_WINDOW (window), "GtkScrolledWindow example");
6610 gtk_container_set_border_width (GTK_CONTAINER (window), 0);
6611 gtk_widget_set_usize(window, 300, 300);
6613 /* create a new scrolled window. */
6614 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
6616 gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 10);
6618 /* the policy is one of GTK_POLICY AUTOMATIC, or GTK_POLICY_ALWAYS.
6619 * GTK_POLICY_AUTOMATIC will automatically decide whether you need
6620 * scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars
6621 * there. The first one is the horizontal scrollbar, the second,
6623 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
6624 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
6625 /* The dialog window is created with a vbox packed into it. */
6626 gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)->vbox), scrolled_window,
6628 gtk_widget_show (scrolled_window);
6630 /* create a table of 10 by 10 squares. */
6631 table = gtk_table_new (10, 10, FALSE);
6633 /* set the spacing to 10 on x and 10 on y */
6634 gtk_table_set_row_spacings (GTK_TABLE (table), 10);
6635 gtk_table_set_col_spacings (GTK_TABLE (table), 10);
6637 /* pack the table into the scrolled window */
6638 gtk_scrolled_window_add_with_viewport (
6639 GTK_SCROLLED_WINDOW (scrolled_window), table);
6640 gtk_widget_show (table);
6642 /* this simply creates a grid of toggle buttons on the table
6643 * to demonstrate the scrolled window. */
6644 for (i = 0; i < 10; i++)
6645 for (j = 0; j < 10; j++) {
6646 sprintf (buffer, "button (%d,%d)\n", i, j);
6647 button = gtk_toggle_button_new_with_label (buffer);
6648 gtk_table_attach_defaults (GTK_TABLE (table), button,
6650 gtk_widget_show (button);
6653 /* Add a "close" button to the bottom of the dialog */
6654 button = gtk_button_new_with_label ("close");
6655 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
6656 (GtkSignalFunc) gtk_widget_destroy,
6657 GTK_OBJECT (window));
6659 /* this makes it so the button is the default. */
6661 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
6662 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0);
6664 /* This grabs this button to be the default button. Simply hitting
6665 * the "Enter" key will cause this button to activate. */
6666 gtk_widget_grab_default (button);
6667 gtk_widget_show (button);
6669 gtk_widget_show (window);
6678 Try playing with resizing the window. You'll notice how the scrollbars
6679 react. You may also wish to use the gtk_widget_set_usize() call to set
6680 the default size of the window or other widgets.
6682 <!-- ----------------------------------------------------------------- -->
6685 Button Boxes are a convenient way to quickly layout a group of
6686 buttons. They come in both horizontal and vertical flavours. You
6687 create a new Button Box with one of the following calls, which create
6688 a horizontal or vertical box, respectively:
6691 GtkWidget *gtk_hbutton_box_new( void );
6693 GtkWidget *gtk_vbutton_box_new( void );
6696 The only attributes pertaining to button boxes effect how the buttons
6697 are layed out. You can change the spacing between the buttons with:
6700 void gtk_hbutton_box_set_spacing_default( gint spacing );
6702 void gtk_vbutton_box_set_spacing_default( gint spacing );
6705 Similarly, the current spacing values can be queried using:
6708 gint gtk_hbutton_box_get_spacing_default( void );
6710 gint gtk_vbutton_box_get_spacing_default( void );
6713 The second attribute that we can access effects the layour of the
6714 buttons within the box. It is set using one of:
6717 void gtk_hbutton_box_set_layout_default( GtkButtonBoxStyle layout );
6719 void gtk_vbutton_box_set_layout_default( GtkButtonBoxStyle layout );
6722 The <tt/layout/ argument can take one of the following values:
6725 <item> GTK_BUTTONBOX_DEFAULT_STYLE
6726 <item> GTK_BUTTONBOX_SPREAD
6727 <item> GTK_BUTTONBOX_EDGE
6728 <item> GTK_BUTTONBOX_START
6729 <item> GTK_BUTTONBOX_END
6732 The current layout setting can be retrieved using:
6735 GtkButtonBoxStyle gtk_hbutton_box_get_layout_default( void );
6737 GtkButtonBoxStyle gtk_vbutton_box_get_layout_default( void );
6740 Buttons are added to a Button Box using the usual function:
6743 gtk_container_add( GTK_CONTAINER(button_box), child_widget );
6746 Here's an example that illustrates all the different layout settings
6750 /* example-start buttonbox buttonbox.c */
6752 #include <gtk/gtk.h>
6754 /* Create a Button Box with the specified parameters */
6755 GtkWidget *create_bbox (gint horizontal,
6766 frame = gtk_frame_new (title);
6769 bbox = gtk_hbutton_box_new ();
6771 bbox = gtk_vbutton_box_new ();
6773 gtk_container_set_border_width (GTK_CONTAINER (bbox), 5);
6774 gtk_container_add (GTK_CONTAINER (frame), bbox);
6776 /* Set the appearance of the Button Box */
6777 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), layout);
6778 gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), spacing);
6779 gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), child_w, child_h);
6781 button = gtk_button_new_with_label ("OK");
6782 gtk_container_add (GTK_CONTAINER (bbox), button);
6784 button = gtk_button_new_with_label ("Cancel");
6785 gtk_container_add (GTK_CONTAINER (bbox), button);
6787 button = gtk_button_new_with_label ("Help");
6788 gtk_container_add (GTK_CONTAINER (bbox), button);
6796 static GtkWidget* window = NULL;
6797 GtkWidget *main_vbox;
6800 GtkWidget *frame_horz;
6801 GtkWidget *frame_vert;
6803 /* Initialize GTK */
6804 gtk_init( &argc, &argv );
6806 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6807 gtk_window_set_title (GTK_WINDOW (window), "Button Boxes");
6809 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6810 GTK_SIGNAL_FUNC(gtk_main_quit),
6813 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6815 main_vbox = gtk_vbox_new (FALSE, 0);
6816 gtk_container_add (GTK_CONTAINER (window), main_vbox);
6818 frame_horz = gtk_frame_new ("Horizontal Button Boxes");
6819 gtk_box_pack_start (GTK_BOX (main_vbox), frame_horz, TRUE, TRUE, 10);
6821 vbox = gtk_vbox_new (FALSE, 0);
6822 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
6823 gtk_container_add (GTK_CONTAINER (frame_horz), vbox);
6825 gtk_box_pack_start (GTK_BOX (vbox),
6826 create_bbox (TRUE, "Spread (spacing 40)", 40, 85, 20, GTK_BUTTONBOX_SPREAD),
6829 gtk_box_pack_start (GTK_BOX (vbox),
6830 create_bbox (TRUE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
6833 gtk_box_pack_start (GTK_BOX (vbox),
6834 create_bbox (TRUE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
6837 gtk_box_pack_start (GTK_BOX (vbox),
6838 create_bbox (TRUE, "End (spacing 10)", 10, 85, 20, GTK_BUTTONBOX_END),
6841 frame_vert = gtk_frame_new ("Vertical Button Boxes");
6842 gtk_box_pack_start (GTK_BOX (main_vbox), frame_vert, TRUE, TRUE, 10);
6844 hbox = gtk_hbox_new (FALSE, 0);
6845 gtk_container_set_border_width (GTK_CONTAINER (hbox), 10);
6846 gtk_container_add (GTK_CONTAINER (frame_vert), hbox);
6848 gtk_box_pack_start (GTK_BOX (hbox),
6849 create_bbox (FALSE, "Spread (spacing 5)", 5, 85, 20, GTK_BUTTONBOX_SPREAD),
6852 gtk_box_pack_start (GTK_BOX (hbox),
6853 create_bbox (FALSE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
6856 gtk_box_pack_start (GTK_BOX (hbox),
6857 create_bbox (FALSE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
6860 gtk_box_pack_start (GTK_BOX (hbox),
6861 create_bbox (FALSE, "End (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_END),
6864 gtk_widget_show_all (window);
6866 /* Enter the event loop */
6874 <!-- ----------------------------------------------------------------- -->
6877 Toolbars are usually used to group some number of widgets in order to
6878 simplify customization of their look and layout. Typically a toolbar
6879 consists of buttons with icons, labels and tooltips, but any other
6880 widget can also be put inside a toolbar. Finally, items can be
6881 arranged horizontally or vertically and buttons can be displayed with
6882 icons, labels or both.
6884 Creating a toolbar is (as one may already suspect) done with the
6888 GtkWidget *gtk_toolbar_new( GtkOrientation orientation,
6889 GtkToolbarStyle style );
6892 where orientation may be one of:
6895 GTK_ORIENTATION_HORIZONTAL
6896 GTK_ORIENTATION_VERTICAL
6907 The style applies to all the buttons created with the `item' functions
6908 (not to buttons inserted into toolbar as separate widgets).
6910 After creating a toolbar one can append, prepend and insert items
6911 (that means simple buttons) into the toolbar. To describe an item we
6912 need a label text, a tooltip text, a private tooltip text, an icon for
6913 the button and a callback function for it. For example, to append or
6914 prepend an item you may use the following functions:
6917 GtkWidget *gtk_toolbar_append_item( GtkToolbar *toolbar,
6919 const char *tooltip_text,
6920 const char *tooltip_private_text,
6922 GtkSignalFunc callback,
6923 gpointer user_data );
6925 GtkWidget *gtk_toolbar_prepend_item( GtkToolbar *toolbar,
6927 const char *tooltip_text,
6928 const char *tooltip_private_text,
6930 GtkSignalFunc callback,
6931 gpointer user_data );
6934 If you want to use gtk_toolbar_insert_item, the only additional
6935 parameter which must be specified is the position in which the item
6936 should be inserted, thus:
6939 GtkWidget *gtk_toolbar_insert_item( GtkToolbar *toolbar,
6941 const char *tooltip_text,
6942 const char *tooltip_private_text,
6944 GtkSignalFunc callback,
6949 To simplify adding spaces between toolbar items, you may use the
6950 following functions:
6953 void gtk_toolbar_append_space( GtkToolbar *toolbar );
6955 void gtk_toolbar_prepend_space( GtkToolbar *toolbar );
6957 void gtk_toolbar_insert_space( GtkToolbar *toolbar,
6962 While the size of the added space can be set globally for a
6963 whole toolbar with the function:
6966 void gtk_toolbar_set_space_size( GtkToolbar *toolbar,
6970 If it's required, the orientation of a toolbar and its style can be
6971 changed `on the fly' using the following functions:
6974 void gtk_toolbar_set_orientation( GtkToolbar *toolbar,
6975 GtkOrientation orientation );
6977 void gtk_toolbar_set_style( GtkToolbar *toolbar,
6978 GtkToolbarStyle style );
6980 void gtk_toolbar_set_tooltips( GtkToolbar *toolbar,
6984 Where <tt/orientation/ is one of GTK_ORIENTATION_HORIZONTAL or
6985 GTK_ORIENTATION_VERTICAL. The <tt/style/ is used to set appearance of
6986 the toolbar items by using one of GTK_TOOLBAR_ICONS, GTK_TOOLBAR_TEXT
6987 or GTK_TOOLBAR_BOTH.
6989 To show some other things that can be done with a toolbar, let's take
6990 the following program (we'll interrupt the listing with some
6991 additional explanations):
6994 #include <gtk/gtk.h>
6998 /* This function is connected to the Close button or
6999 * closing the window from the WM */
7000 void delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
7006 The above beginning seems for sure familiar to you if it's not your first
7007 GTK program. There is one additional thing though, we include a nice XPM
7008 picture to serve as an icon for all of the buttons.
7011 GtkWidget* close_button; /* This button will emit signal to close
7013 GtkWidget* tooltips_button; /* to enable/disable tooltips */
7014 GtkWidget* text_button,
7016 * both_button; /* radio buttons for toolbar style */
7017 GtkWidget* entry; /* a text entry to show packing any widget into
7021 In fact not all of the above widgets are needed here, but to make things
7022 clearer I put them all together.
7025 /* that's easy... when one of the buttons is toggled, we just
7026 * check which one is active and set the style of the toolbar
7028 * ATTENTION: our toolbar is passed as data to callback ! */
7029 void radio_event (GtkWidget *widget, gpointer data)
7031 if (GTK_TOGGLE_BUTTON (text_button)->active)
7032 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_TEXT);
7033 else if (GTK_TOGGLE_BUTTON (icon_button)->active)
7034 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_ICONS);
7035 else if (GTK_TOGGLE_BUTTON (both_button)->active)
7036 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_BOTH);
7039 /* even easier, just check given toggle button and enable/disable
7041 void toggle_event (GtkWidget *widget, gpointer data)
7043 gtk_toolbar_set_tooltips (GTK_TOOLBAR ( data ),
7044 GTK_TOGGLE_BUTTON (widget)->active );
7048 The above are just two callback functions that will be called when
7049 one of the buttons on a toolbar is pressed. You should already be
7050 familiar with things like this if you've already used toggle buttons (and
7054 int main (int argc, char *argv[])
7056 /* Here is our main window (a dialog) and a handle for the handlebox */
7058 GtkWidget* handlebox;
7060 /* Ok, we need a toolbar, an icon with a mask (one for all of
7061 the buttons) and an icon widget to put this icon in (but
7062 we'll create a separate widget for each button) */
7063 GtkWidget * toolbar;
7068 /* this is called in all GTK application. */
7069 gtk_init (&argc, &argv);
7071 /* create a new window with a given title, and nice size */
7072 dialog = gtk_dialog_new ();
7073 gtk_window_set_title ( GTK_WINDOW ( dialog ) , "GTKToolbar Tutorial");
7074 gtk_widget_set_usize( GTK_WIDGET ( dialog ) , 600 , 300 );
7075 GTK_WINDOW ( dialog ) ->allow_shrink = TRUE;
7077 /* typically we quit if someone tries to close us */
7078 gtk_signal_connect ( GTK_OBJECT ( dialog ), "delete_event",
7079 GTK_SIGNAL_FUNC ( delete_event ), NULL);
7081 /* we need to realize the window because we use pixmaps for
7082 * items on the toolbar in the context of it */
7083 gtk_widget_realize ( dialog );
7085 /* to make it nice we'll put the toolbar into the handle box,
7086 * so that it can be detached from the main window */
7087 handlebox = gtk_handle_box_new ();
7088 gtk_box_pack_start ( GTK_BOX ( GTK_DIALOG(dialog)->vbox ),
7089 handlebox, FALSE, FALSE, 5 );
7092 The above should be similar to any other GTK application. Just
7093 initialization of GTK, creating the window etc.. There is only one
7094 thing that probably needs some explanation: a handle box. A handle box
7095 is just another box that can be used to pack widgets in to. The
7096 difference between it and typical boxes is that it can be detached
7097 from a parent window (or, in fact, the handle box remains in the
7098 parent, but it is reduced to a very small rectangle, while all of its
7099 contents are reparented to a new freely floating window). It is
7100 usually nice to have a detachable toolbar, so these two widgets occur
7101 together quite often.
7104 /* toolbar will be horizontal, with both icons and text, and
7105 * with 5pxl spaces between items and finally,
7106 * we'll also put it into our handlebox */
7107 toolbar = gtk_toolbar_new ( GTK_ORIENTATION_HORIZONTAL,
7109 gtk_container_set_border_width ( GTK_CONTAINER ( toolbar ) , 5 );
7110 gtk_toolbar_set_space_size ( GTK_TOOLBAR ( toolbar ), 5 );
7111 gtk_container_add ( GTK_CONTAINER ( handlebox ) , toolbar );
7113 /* now we create icon with mask: we'll reuse it to create
7114 * icon widgets for toolbar items */
7115 icon = gdk_pixmap_create_from_xpm_d ( dialog->window, &mask,
7116 &dialog->style->white, gtk_xpm );
7119 Well, what we do above is just a straight-forward initialization of
7120 the toolbar widget and creation of a GDK pixmap with its mask. If you
7121 want to know something more about using pixmaps, refer to GDK
7122 documentation or to the <ref id="sec_Pixmaps" name="Pixmaps"> section
7123 earlier in this tutorial.
7126 /* our first item is <close> button */
7127 iconw = gtk_pixmap_new ( icon, mask ); /* icon widget */
7129 gtk_toolbar_append_item ( GTK_TOOLBAR (toolbar), /* our toolbar */
7130 "Close", /* button label */
7131 "Closes this app", /* this button's tooltip */
7132 "Private", /* tooltip private info */
7133 iconw, /* icon widget */
7134 GTK_SIGNAL_FUNC (delete_event), /* a signal */
7136 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) ); /* space after item */
7139 In the above code you see the simplest case: adding a button to
7140 toolbar. Just before appending a new item, we have to construct a
7141 pixmap widget to serve as an icon for this item; this step will have
7142 to be repeated for each new item. Just after the item we also add a
7143 space, so the following items will not touch each other. As you see
7144 gtk_toolbar_append_item returns a pointer to our newly created button
7145 widget, so that we can work with it in the normal way.
7148 /* now, let's make our radio buttons group... */
7149 iconw = gtk_pixmap_new ( icon, mask );
7150 icon_button = gtk_toolbar_append_element(
7151 GTK_TOOLBAR(toolbar),
7152 GTK_TOOLBAR_CHILD_RADIOBUTTON, /* a type of element */
7153 NULL, /* pointer to widget */
7155 "Only icons in toolbar", /* tooltip */
7156 "Private", /* tooltip private string */
7158 GTK_SIGNAL_FUNC (radio_event), /* signal */
7159 toolbar); /* data for signal */
7160 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7163 Here we begin creating a radio buttons group. To do this we use
7164 gtk_toolbar_append_element. In fact, using this function one can also
7165 add simple items or even spaces (type = GTK_TOOLBAR_CHILD_SPACE or
7166 GTK_TOOLBAR_CHILD_BUTTON). In the above case we start creating a radio
7167 group. In creating other radio buttons for this group a pointer to the
7168 previous button in the group is required, so that a list of buttons
7169 can be easily constructed (see the section on <ref
7170 id="sec_Radio_Buttons" name="Radio Buttons"> earlier in this
7174 /* following radio buttons refer to previous ones */
7175 iconw = gtk_pixmap_new ( icon, mask );
7177 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
7178 GTK_TOOLBAR_CHILD_RADIOBUTTON,
7181 "Only texts in toolbar",
7184 GTK_SIGNAL_FUNC (radio_event),
7186 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7188 iconw = gtk_pixmap_new ( icon, mask );
7190 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
7191 GTK_TOOLBAR_CHILD_RADIOBUTTON,
7194 "Icons and text in toolbar",
7197 GTK_SIGNAL_FUNC (radio_event),
7199 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7200 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(both_button),TRUE);
7203 In the end we have set the state of one of the buttons manually (otherwise
7204 they all stay in active state, preventing us from switching between them).
7207 /* here we have just a simple toggle button */
7208 iconw = gtk_pixmap_new ( icon, mask );
7210 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
7211 GTK_TOOLBAR_CHILD_TOGGLEBUTTON,
7214 "Toolbar with or without tips",
7217 GTK_SIGNAL_FUNC (toggle_event),
7219 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7220 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tooltips_button),TRUE);
7223 A toggle button can be created in the obvious way (if one knows how to create
7224 radio buttons already).
7227 /* to pack a widget into toolbar, we only have to
7228 * create it and append it with an appropriate tooltip */
7229 entry = gtk_entry_new ();
7230 gtk_toolbar_append_widget( GTK_TOOLBAR (toolbar),
7232 "This is just an entry",
7235 /* well, it isn't created within thetoolbar, so we must still show it */
7236 gtk_widget_show ( entry );
7239 As you see, adding any kind of widget to a toolbar is simple. The
7240 one thing you have to remember is that this widget must be shown manually
7241 (contrary to other items which will be shown together with the toolbar).
7244 /* that's it ! let's show everything. */
7245 gtk_widget_show ( toolbar );
7246 gtk_widget_show (handlebox);
7247 gtk_widget_show ( dialog );
7249 /* rest in gtk_main and wait for the fun to begin! */
7256 So, here we are at the end of toolbar tutorial. Of course, to appreciate
7257 it in full you need also this nice XPM icon, so here it is:
7261 static char * gtk_xpm[] = {
7268 "................+...............",
7269 "..............+++++.............",
7270 "............+++++@@++...........",
7271 "..........+++++@@@@@@++.........",
7272 "........++++@@@@@@@@@@++........",
7273 "......++++@@++++++++@@@++.......",
7274 ".....+++@@@+++++++++++@@@++.....",
7275 "...+++@@@@+++@@@@@@++++@@@@+....",
7276 "..+++@@@@+++@@@@@@@@+++@@@@@++..",
7277 ".++@@@@@@+++@@@@@@@@@@@@@@@@@@++",
7278 ".+#+@@@@@@++@@@@+++@@@@@@@@@@@@+",
7279 ".+##++@@@@+++@@@+++++@@@@@@@@$@.",
7280 ".+###++@@@@+++@@@+++@@@@@++$$$@.",
7281 ".+####+++@@@+++++++@@@@@+@$$$$@.",
7282 ".+#####+++@@@@+++@@@@++@$$$$$$+.",
7283 ".+######++++@@@@@@@++@$$$$$$$$+.",
7284 ".+#######+##+@@@@+++$$$$$$@@$$+.",
7285 ".+###+++##+##+@@++@$$$$$$++$$$+.",
7286 ".+###++++##+##+@@$$$$$$$@+@$$@+.",
7287 ".+###++++++#+++@$$@+@$$@++$$$@+.",
7288 ".+####+++++++#++$$@+@$$++$$$$+..",
7289 ".++####++++++#++$$@+@$++@$$$$+..",
7290 ".+#####+++++##++$$++@+++$$$$$+..",
7291 ".++####+++##+#++$$+++++@$$$$$+..",
7292 ".++####+++####++$$++++++@$$$@+..",
7293 ".+#####++#####++$$+++@++++@$@+..",
7294 ".+#####++#####++$$++@$$@+++$@@..",
7295 ".++####++#####++$$++$$$$$+@$@++.",
7296 ".++####++#####++$$++$$$$$$$$+++.",
7297 ".+++####+#####++$$++$$$$$$$@+++.",
7298 "..+++#########+@$$+@$$$$$$+++...",
7299 "...+++########+@$$$$$$$$@+++....",
7300 ".....+++######+@$$$$$$$+++......",
7301 "......+++#####+@$$$$$@++........",
7302 ".......+++####+@$$$$+++.........",
7303 ".........++###+$$$@++...........",
7304 "..........++##+$@+++............",
7305 "...........+++++++..............",
7306 ".............++++..............."};
7309 <!-- ----------------------------------------------------------------- -->
7312 The NoteBook Widget is a collection of 'pages' that overlap each
7313 other, each page contains different information. This widget has
7314 become more common lately in GUI programming, and it is a good way to
7315 show blocks of similar information that warrant separation in their
7318 The first function call you will need to know, as you can probably
7319 guess by now, is used to create a new notebook widget.
7322 GtkWidget *gtk_notebook_new( void );
7325 Once the notebook has been created, there are a number of functions
7326 that operate on the notebook widget. Let's look at them individually.
7328 The first one we will look at is how to position the page indicators.
7329 These page indicators or 'tabs' as they are referred to, can be
7330 positioned in four ways: top, bottom, left, or right.
7333 void gtk_notebook_set_tab_pos( GtkNotebook *notebook,
7334 GtkPositionType pos );
7337 GtkPostionType will be one of the following, which are pretty self
7341 <item> GTK_POS_RIGHT
7343 <item> GTK_POS_BOTTOM
7346 GTK_POS_TOP is the default.
7348 Next we will look at how to add pages to the notebook. There are three
7349 ways to add pages to the NoteBook. Let's look at the first two
7350 together as they are quite similar.
7353 void gtk_notebook_append_page( GtkNotebook *notebook,
7355 GtkWidget *tab_label );
7357 void gtk_notebook_prepend_page( GtkNotebook *notebook,
7359 GtkWidget *tab_label );
7362 These functions add pages to the notebook by inserting them from the
7363 back of the notebook (append), or the front of the notebook (prepend).
7364 <tt/child/ is the widget that is placed within the notebook page, and
7365 <tt/tab_label/ is the label for the page being added. The <tt/child/
7366 widget must be created separately, and is typically a set of options
7367 setout witin one of the other container widgets, such as a table.
7369 The final function for adding a page to the notebook contains all of
7370 the properties of the previous two, but it allows you to specify what
7371 position you want the page to be in the notebook.
7374 void gtk_notebook_insert_page( GtkNotebook *notebook,
7376 GtkWidget *tab_label,
7380 The parameters are the same as _append_ and _prepend_ except it
7381 contains an extra parameter, <tt/position/. This parameter is used to
7382 specify what place this page will be inserted into.
7384 Now that we know how to add a page, lets see how we can remove a page
7388 void gtk_notebook_remove_page( GtkNotebook *notebook,
7392 This function takes the page specified by <tt/page_num/ and removes it
7393 from the widget pointed to by <tt/notebook/.
7395 To find out what the current page is in a notebook use the function:
7398 gint gtk_notebook_get_current_page( GtkNotebook *notebook );
7401 These next two functions are simple calls to move the notebook page
7402 forward or backward. Simply provide the respective function call with
7403 the notebook widget you wish to operate on. Note: when the NoteBook is
7404 currently on the last page, and gtk_notebook_next_page is called, the
7405 notebook will wrap back to the first page. Likewise, if the NoteBook
7406 is on the first page, and gtk_notebook_prev_page is called, the
7407 notebook will wrap to the last page.
7410 void gtk_notebook_next_page( GtkNoteBook *notebook );
7412 void gtk_notebook_prev_page( GtkNoteBook *notebook );
7415 This next function sets the 'active' page. If you wish the notebook to
7416 be opened to page 5 for example, you would use this function. Without
7417 using this function, the notebook defaults to the first page.
7420 void gtk_notebook_set_page( GtkNotebook *notebook,
7424 The next two functions add or remove the notebook page tabs and the
7425 notebook border respectively.
7428 void gtk_notebook_set_show_tabs( GtkNotebook *notebook,
7429 gboolean show_tabs);
7431 void gtk_notebook_set_show_border( GtkNotebook *notebook,
7432 gboolean show_border );
7435 The next function is useful when the you have a large number of pages,
7436 and the tabs don't fit on the page. It allows the tabs to be scrolled
7437 through using two arrow buttons.
7440 void gtk_notebook_set_scrollable( GtkNotebook *notebook,
7441 gboolean scrollable );
7444 <tt/show_tabs/, <tt/show_border/ and <tt/scrollable/ can be either
7447 Now lets look at an example, it is expanded from the testgtk.c code
7448 that comes with the GTK distribution. This small program creates a
7449 window with a notebook and six buttons. The notebook contains 11
7450 pages, added in three different ways, appended, inserted, and
7451 prepended. The buttons allow you rotate the tab positions, add/remove
7452 the tabs and border, remove a page, change pages in both a forward and
7453 backward manner, and exit the program.
7456 /* example-start notebook notebook.c */
7458 #include <gtk/gtk.h>
7460 /* This function rotates the position of the tabs */
7461 void rotate_book (GtkButton *button, GtkNotebook *notebook)
7463 gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos +1) %4);
7466 /* Add/Remove the page tabs and the borders */
7467 void tabsborder_book (GtkButton *button, GtkNotebook *notebook)
7471 if (notebook->show_tabs == 0)
7473 if (notebook->show_border == 0)
7476 gtk_notebook_set_show_tabs (notebook, tval);
7477 gtk_notebook_set_show_border (notebook, bval);
7480 /* Remove a page from the notebook */
7481 void remove_book (GtkButton *button, GtkNotebook *notebook)
7485 page = gtk_notebook_get_current_page(notebook);
7486 gtk_notebook_remove_page (notebook, page);
7487 /* Need to refresh the widget --
7488 This forces the widget to redraw itself. */
7489 gtk_widget_draw(GTK_WIDGET(notebook), NULL);
7492 void delete (GtkWidget *widget, GtkWidget *event, gpointer data)
7497 int main (int argc, char *argv[])
7502 GtkWidget *notebook;
7505 GtkWidget *checkbutton;
7510 gtk_init (&argc, &argv);
7512 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
7514 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
7515 GTK_SIGNAL_FUNC (delete), NULL);
7517 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
7519 table = gtk_table_new(3,6,FALSE);
7520 gtk_container_add (GTK_CONTAINER (window), table);
7522 /* Create a new notebook, place the position of the tabs */
7523 notebook = gtk_notebook_new ();
7524 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
7525 gtk_table_attach_defaults(GTK_TABLE(table), notebook, 0,6,0,1);
7526 gtk_widget_show(notebook);
7528 /* Lets append a bunch of pages to the notebook */
7529 for (i=0; i < 5; i++) {
7530 sprintf(bufferf, "Append Frame %d", i+1);
7531 sprintf(bufferl, "Page %d", i+1);
7533 frame = gtk_frame_new (bufferf);
7534 gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
7535 gtk_widget_set_usize (frame, 100, 75);
7536 gtk_widget_show (frame);
7538 label = gtk_label_new (bufferf);
7539 gtk_container_add (GTK_CONTAINER (frame), label);
7540 gtk_widget_show (label);
7542 label = gtk_label_new (bufferl);
7543 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
7546 /* Now lets add a page to a specific spot */
7547 checkbutton = gtk_check_button_new_with_label ("Check me please!");
7548 gtk_widget_set_usize(checkbutton, 100, 75);
7549 gtk_widget_show (checkbutton);
7551 label = gtk_label_new ("Add page");
7552 gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, label, 2);
7554 /* Now finally lets prepend pages to the notebook */
7555 for (i=0; i < 5; i++) {
7556 sprintf(bufferf, "Prepend Frame %d", i+1);
7557 sprintf(bufferl, "PPage %d", i+1);
7559 frame = gtk_frame_new (bufferf);
7560 gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
7561 gtk_widget_set_usize (frame, 100, 75);
7562 gtk_widget_show (frame);
7564 label = gtk_label_new (bufferf);
7565 gtk_container_add (GTK_CONTAINER (frame), label);
7566 gtk_widget_show (label);
7568 label = gtk_label_new (bufferl);
7569 gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook), frame, label);
7572 /* Set what page to start at (page 4) */
7573 gtk_notebook_set_page (GTK_NOTEBOOK(notebook), 3);
7575 /* Create a bunch of buttons */
7576 button = gtk_button_new_with_label ("close");
7577 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
7578 GTK_SIGNAL_FUNC (delete), NULL);
7579 gtk_table_attach_defaults(GTK_TABLE(table), button, 0,1,1,2);
7580 gtk_widget_show(button);
7582 button = gtk_button_new_with_label ("next page");
7583 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
7584 (GtkSignalFunc) gtk_notebook_next_page,
7585 GTK_OBJECT (notebook));
7586 gtk_table_attach_defaults(GTK_TABLE(table), button, 1,2,1,2);
7587 gtk_widget_show(button);
7589 button = gtk_button_new_with_label ("prev page");
7590 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
7591 (GtkSignalFunc) gtk_notebook_prev_page,
7592 GTK_OBJECT (notebook));
7593 gtk_table_attach_defaults(GTK_TABLE(table), button, 2,3,1,2);
7594 gtk_widget_show(button);
7596 button = gtk_button_new_with_label ("tab position");
7597 gtk_signal_connect (GTK_OBJECT (button), "clicked",
7598 (GtkSignalFunc) rotate_book,
7599 GTK_OBJECT(notebook));
7600 gtk_table_attach_defaults(GTK_TABLE(table), button, 3,4,1,2);
7601 gtk_widget_show(button);
7603 button = gtk_button_new_with_label ("tabs/border on/off");
7604 gtk_signal_connect (GTK_OBJECT (button), "clicked",
7605 (GtkSignalFunc) tabsborder_book,
7606 GTK_OBJECT (notebook));
7607 gtk_table_attach_defaults(GTK_TABLE(table), button, 4,5,1,2);
7608 gtk_widget_show(button);
7610 button = gtk_button_new_with_label ("remove page");
7611 gtk_signal_connect (GTK_OBJECT (button), "clicked",
7612 (GtkSignalFunc) remove_book,
7613 GTK_OBJECT(notebook));
7614 gtk_table_attach_defaults(GTK_TABLE(table), button, 5,6,1,2);
7615 gtk_widget_show(button);
7617 gtk_widget_show(table);
7618 gtk_widget_show(window);
7627 Hopefully this helps you on your way with creating notebooks for your
7630 <!-- ***************************************************************** -->
7632 <!-- ***************************************************************** -->
7634 <!-- ----------------------------------------------------------------- -->
7636 The GtkCList widget has replaced the GtkList widget (which is still
7639 The GtkCList widget is a multi-column list widget that is capable of
7640 handling literally thousands of rows of information. Each column can
7641 optionally have a title, which itself is optionally active, allowing
7642 us to bind a function to its selection.
7644 <!-- ----------------------------------------------------------------- -->
7645 <sect1>Creating a GtkCList widget
7647 Creating a GtkCList is quite straightforward, once you have learned
7648 about widgets in general. It provides the almost standard two ways,
7649 that is the hard way, and the easy way. But before we create it, there
7650 is one thing we should figure out beforehand: how many columns should
7653 Not all columns have to be visible and can be used to store data that
7654 is related to a certain cell in the list.
7657 GtkWidget *gtk_clist_new ( gint columns );
7659 GtkWidget *gtk_clist_new_with_titles( gint columns,
7663 The first form is very straight forward, the second might require some
7664 explanation. Each column can have a title associated with it, and this
7665 title can be a label or a button that reacts when we click on it. If
7666 we use the second form, we must provide pointers to the title texts,
7667 and the number of pointers should equal the number of columns
7668 specified. Of course we can always use the first form, and manually
7671 Note: the GtkCList widget does not have its own scrollbars and should
7672 be placed within a GtkScrolledWindow widget if your require this
7673 functionality. This is a change from the GTK 1.0 implementation.
7675 <!-- ----------------------------------------------------------------- -->
7676 <sect1>Modes of operation
7678 There are several attributes that can be used to alter the behaviour of
7679 a GtkCList. First there is
7682 void gtk_clist_set_selection_mode( GtkCList *clist,
7683 GtkSelectionMode mode );
7686 which, as the name implies, sets the selection mode of the
7687 GtkCList. The first argument is the GtkCList widget, and the second
7688 specifies the cell selection mode (they are defined in gtkenums.h). At
7689 the time of this writing, the following modes are available to us:
7692 <item> GTK_SELECTION_SINGLE - The selection is either NULL or contains
7693 a GList pointer for a single selected item.
7695 <item> GTK_SELECTION_BROWSE - The selection is NULL if the list
7696 contains no widgets or insensitive ones only, otherwise it contains a
7697 GList pointer for one GList structure, and therefore exactly one list
7700 <item> GTK_SELECTION_MULTIPLE - The selection is NULL if no list items
7701 are selected or a GList pointer for the first selected item. That in
7702 turn points to a GList structure for the second selected item and so
7703 on. This is currently the <bf>default</bf> for the GtkCList widget.
7705 <item> GTK_SELECTION_EXTENDED - The selection is always NULL.
7708 Others might be added in later revisions of GTK.
7710 We can also define what the border of the GtkCList widget should look
7711 like. It is done through
7714 void gtk_clist_set_shadow_type( GtkCList *clist,
7715 GtkShadowType border );
7718 And the possible values for the second argument are
7721 <item> GTK_SHADOW_NONE
7723 <item> GTK_SHADOW_IN
7725 <item> GTK_SHADOW_OUT
7727 <item> GTK_SHADOW_ETCHED_IN
7729 <item> GTK_SHADOW_ETCHED_OUT
7732 <!-- ----------------------------------------------------------------- -->
7733 <sect1>Working with titles
7735 When you create a GtkCList widget, you will also get a set of title
7736 buttons automatically. They live in the top of the CList window, and
7737 can act either as normal buttons that respond to being pressed, or
7738 they can be passive, in which case they are nothing more than a
7739 title. There are four different calls that aid us in setting the
7740 status of the title buttons.
7743 void gtk_clist_column_title_active( GtkCList *clist,
7746 void gtk_clist_column_title_passive( GtkCList *clist,
7749 void gtk_clist_column_titles_active( GtkCList *clist );
7751 void gtk_clist_column_titles_passive( GtkCList *clist );
7754 An active title is one which acts as a normal button, a passive one is
7755 just a label. The first two calls above will activate/deactivate the
7756 title button above the specific column, while the last two calls
7757 activate/deactivate all title buttons in the supplied clist widget.
7759 But of course there are those cases when we don't want them at all,
7760 and so they can be hidden and shown at will using the following two
7764 void gtk_clist_column_titles_show( GtkCList *clist );
7766 void gtk_clist_column_titles_hide( GtkCList *clist );
7769 For titles to be really useful we need a mechanism to set and change
7770 them, and this is done using
7773 void gtk_clist_set_column_title( GtkCList *clist,
7778 Note that only the title of one column can be set at a time, so if all
7779 the titles are known from the beginning, then I really suggest using
7780 gtk_clist_new_with_titles (as described above) to set them. Saves you
7781 coding time, and makes your program smaller. There are some cases
7782 where getting the job done the manual way is better, and that's when
7783 not all titles will be text. GtkCList provides us with title buttons
7784 that can in fact incorporate whole widgets, for example a pixmap. It's
7788 void gtk_clist_set_column_widget( GtkCList *clist,
7790 GtkWidget *widget );
7793 which should require no special explanation.
7795 <!-- ----------------------------------------------------------------- -->
7796 <sect1>Manipulating the list itself
7798 It is possible to change the justification for a column, and it is
7802 void gtk_clist_set_column_justification( GtkCList *clist,
7804 GtkJustification justification );
7807 The GtkJustification type can take the following values:
7810 <item>GTK_JUSTIFY_LEFT - The text in the column will begin from the
7813 <item>GTK_JUSTIFY_RIGHT - The text in the column will begin from the
7816 <item>GTK_JUSTIFY_CENTER - The text is placed in the center of the
7819 <item>GTK_JUSTIFY_FILL - The text will use up all available space in
7820 the column. It is normally done by inserting extra blank spaces
7821 between words (or between individual letters if it's a single
7822 word). Much in the same way as any ordinary WYSIWYG text editor.
7825 The next function is a very important one, and should be standard in
7826 the setup of all GtkCList widgets. When the list is created, the width
7827 of the various columns are chosen to match their titles, and since
7828 this is seldom the right width we have to set it using
7831 void gtk_clist_set_column_width( GtkCList *clist,
7836 Note that the width is given in pixels and not letters. The same goes
7837 for the height of the cells in the columns, but as the default value
7838 is the height of the current font this isn't as critical to the
7839 application. Still, it is done through
7842 void gtk_clist_set_row_height( GtkCList *clist,
7846 Again, note that the height is given in pixels.
7848 We can also move the list around without user interaction, however, it
7849 does require that we know what we are looking for. Or in other words,
7850 we need the row and column of the item we want to scroll to.
7853 void gtk_clist_moveto( GtkCList *clist,
7860 The gfloat row_align is pretty important to understand. It's a value
7861 between 0.0 and 1.0, where 0.0 means that we should scroll the list so
7862 the row appears at the top, while if the value of row_align is 1.0,
7863 the row will appear at the bottom instead. All other values between
7864 0.0 and 1.0 are also valid and will place the row between the top and
7865 the bottom. The last argument, gfloat col_align works in the same way,
7866 though 0.0 marks left and 1.0 marks right instead.
7868 Depending on the application's needs, we don't have to scroll to an
7869 item that is already visible to us. So how do we know if it is
7870 visible? As usual, there is a function to find that out as well.
7873 GtkVisibility gtk_clist_row_is_visible( GtkCList *clist,
7877 The return value is is one of the following:
7880 <item>GTK_VISIBILITY_NONE
7882 <item>GTK_VISIBILITY_PARTIAL
7884 <item>GTK_VISIBILITY_FULL
7887 Note that it will only tell us if a row is visible. Currently there is
7888 no way to determine this for a column. We can get partial information
7889 though, because if the return is GTK_VISIBILITY_PARTIAL, then some of
7890 it is hidden, but we don't know if it is the row that is being cut by
7891 the lower edge of the listbox, or if the row has columns that are
7894 We can also change both the foreground and background colors of a
7895 particular row. This is useful for marking the row selected by the
7896 user, and the two functions that is used to do it are
7899 void gtk_clist_set_foreground( GtkCList *clist,
7903 void gtk_clist_set_background( GtkCList *clist,
7908 Please note that the colors must have been previously allocated.
7910 <!-- ----------------------------------------------------------------- -->
7911 <sect1>Adding rows to the list
7913 We can add rows in three ways. They can be prepended or appended to
7917 gint gtk_clist_prepend( GtkCList *clist,
7920 gint gtk_clist_append( GtkCList *clist,
7924 The return value of these two functions indicate the index of the row
7925 that was just added. We can insert a row at a given place using
7928 void gtk_clist_insert( GtkCList *clist,
7933 In these calls we have to provide a collection of pointers that are
7934 the texts we want to put in the columns. The number of pointers should
7935 equal the number of columns in the list. If the text[] argument is
7936 NULL, then there will be no text in the columns of the row. This is
7937 useful, for example, if we want to add pixmaps instead (something that
7938 has to be done manually).
7940 Also, please note that the numbering of both rows and columns start at 0.
7942 To remove an individual row we use
7945 void gtk_clist_remove( GtkCList *clist,
7949 There is also a call that removes all rows in the list. This is a lot
7950 faster than calling gtk_clist_remove once for each row, which is the
7954 void gtk_clist_clear( GtkCList *clist );
7957 There are also two convenience functions that should be used when a
7958 lot of changes have to be made to the list. This is to prevent the
7959 list flickering while being repeatedly updated, which may be highly
7960 annoying to the user. So instead it is a good idea to freeze the list,
7961 do the updates to it, and finally thaw it which causes the list to be
7962 updated on the screen.
7965 void gtk_clist_freeze( GtkCList * clist );
7967 void gtk_clist_thaw( GtkCList * clist );
7970 <!-- ----------------------------------------------------------------- -->
7971 <sect1>Setting text and pixmaps in the cells
7973 A cell can contain a pixmap, text or both. To set them the following
7977 void gtk_clist_set_text( GtkCList *clist,
7982 void gtk_clist_set_pixmap( GtkCList *clist,
7988 void gtk_clist_set_pixtext( GtkCList *clist,
7997 It's quite straightforward. All the calls have the GtkCList as the
7998 first argument, followed by the row and column of the cell, followed
7999 by the data to be set. The <tt/spacing/ argument in
8000 gtk_clist_set_pixtext is the number of pixels between the pixmap and
8001 the beginning of the text.
8003 To read back the data, we instead use
8006 gint gtk_clist_get_text( GtkCList *clist,
8011 gint gtk_clist_get_pixmap( GtkCList *clist,
8017 gint gtk_clist_get_pixtext( GtkCList *clist,
8026 It isn't necessary to read it all back in case you aren't
8027 interested. Any of the pointers that are meant for return values (all
8028 except the clist) can be NULL. So if we want to read back only the
8029 text from a cell that is of type pixtext, then we would do the
8030 following, assuming that clist, row and column already exist:
8035 gtk_clist_get_pixtext(clist, row, column, &mytext, NULL, NULL, NULL);
8038 There is one more call that is related to what's inside a cell in the
8042 GtkCellType gtk_clist_get_cell_type( GtkCList *clist,
8047 which returns the type of data in a cell. The return value is one of
8050 <item>GTK_CELL_EMPTY
8054 <item>GTK_CELL_PIXMAP
8056 <item>GTK_CELL_PIXTEXT
8058 <item>GTK_CELL_WIDGET
8061 There is also a function that will let us set the indentation, both
8062 vertical and horizontal, of a cell. The indentation value is of type
8063 gint, given in pixels, and can be both positive and negative.
8066 void gtk_clist_set_shift( GtkCList *clist,
8073 <!-- ----------------------------------------------------------------- -->
8074 <sect1>Storing data pointers
8076 With a GtkCList it is possible to set a data pointer for a row. This
8077 pointer will not be visible for the user, but is merely a convenience
8078 for the programmer to associate a row with a pointer to some
8081 The functions should be fairly self-explanatory by now
8084 void gtk_clist_set_row_data( GtkCList *clist,
8088 void gtk_clist_set_row_data_full( GtkCList *clist,
8091 GtkDestroyNotify destroy );
8093 gpointer gtk_clist_get_row_data( GtkCList *clist,
8096 gint gtk_clist_find_row_from_data( GtkCList *clist,
8100 <!-- ----------------------------------------------------------------- -->
8101 <sect1>Working with selections
8103 There are also functions available that let us force the (un)selection
8107 void gtk_clist_select_row( GtkCList *clist,
8111 void gtk_clist_unselect_row( GtkCList *clist,
8116 And also a function that will take x and y coordinates (for example,
8117 read from the mousepointer), and map that onto the list, returning the
8118 corresponding row and column.
8121 gint gtk_clist_get_selection_info( GtkCList *clist,
8128 When we detect something of interest, it might be movement of the
8129 pointer, a click somewhere in the list, we can read the pointer
8130 coordinates and find out where in the list the pointer is. Cumbersome?
8131 Luckily, there is a simpler way...
8133 <!-- ----------------------------------------------------------------- -->
8134 <sect1>The signals that bring it together
8136 As with all other widgets, there are a few signals that can be used. The
8137 GtkCList widget is derived from the GtkContainer widget, and so has all the
8138 same signals, but also the adds following:
8141 <item>select_row - This signal will send the following information, in
8142 order: GtkCList *clist, gint row, gint column, GtkEventButton *event
8144 <item>unselect_row - When the user unselects a row, this signal is
8145 activated. It sends the same information as select_row
8147 <item>click_column - Send GtkCList *clist, gint column
8150 So if we want to connect a callback to select_row, the callback
8151 function would be declared like this
8154 void select_row_callback(GtkWidget *widget,
8157 GdkEventButton *event,
8161 The callback is connected as usual with
8164 gtk_signal_connect(GTK_OBJECT( clist),
8166 GTK_SIGNAL_FUNC(select_row_callback),
8170 <!-- ----------------------------------------------------------------- -->
8171 <sect1>A GtkCList example
8175 /* example-start clist clist.c */
8177 #include <gtk/gtk.h>
8180 /* These are just the prototypes of the various callbacks */
8181 void button_add_clicked( GtkWidget *button, gpointer data);
8182 void button_clear_clicked( GtkWidget *button, gpointer data);
8183 void button_hide_show_clicked( GtkWidget *button, gpointer data);
8184 void selection_made( GtkWidget *clist, gint row, gint column,
8185 GdkEventButton *event, gpointer data);
8187 gint main (int argc, gchar *argv[])
8190 GtkWidget *vbox, *hbox;
8192 GtkWidget *button_add, *button_clear, *button_hide_show;
8193 gchar *titles[2] = {"Ingredients","Amount"};
8195 gtk_init(&argc, &argv);
8198 window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
8199 gtk_widget_set_usize(GTK_WIDGET(window), 300, 150);
8201 gtk_window_set_title(GTK_WINDOW(window), "GtkCList Example");
8202 gtk_signal_connect(GTK_OBJECT(window),
8204 GTK_SIGNAL_FUNC(gtk_main_quit),
8207 vbox=gtk_vbox_new(FALSE, 5);
8208 gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
8209 gtk_container_add(GTK_CONTAINER(window), vbox);
8210 gtk_widget_show(vbox);
8212 /* Create the GtkCList. For this example we use 2 columns */
8213 clist = gtk_clist_new_with_titles( 2, titles);
8215 /* When a selection is made, we want to know about it. The callback
8216 * used is selection_made, and its code can be found further down */
8217 gtk_signal_connect(GTK_OBJECT(clist), "select_row",
8218 GTK_SIGNAL_FUNC(selection_made),
8221 /* It isn't necessary to shadow the border, but it looks nice :) */
8222 gtk_clist_set_shadow_type (GTK_CLIST(clist), GTK_SHADOW_OUT);
8224 /* What however is important, is that we set the column widths as
8225 * they will never be right otherwise. Note that the columns are
8226 * numbered from 0 and up (to 1 in this case).
8228 gtk_clist_set_column_width (GTK_CLIST(clist), 0, 150);
8230 /* Add the GtkCList widget to the vertical box and show it. */
8231 gtk_box_pack_start(GTK_BOX(vbox), clist, TRUE, TRUE, 0);
8232 gtk_widget_show(clist);
8234 /* Create the buttons and add them to the window. See the button
8235 * tutorial for more examples and comments on this.
8237 hbox = gtk_hbox_new(FALSE, 0);
8238 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
8239 gtk_widget_show(hbox);
8241 button_add = gtk_button_new_with_label("Add List");
8242 button_clear = gtk_button_new_with_label("Clear List");
8243 button_hide_show = gtk_button_new_with_label("Hide/Show titles");
8245 gtk_box_pack_start(GTK_BOX(hbox), button_add, TRUE, TRUE, 0);
8246 gtk_box_pack_start(GTK_BOX(hbox), button_clear, TRUE, TRUE, 0);
8247 gtk_box_pack_start(GTK_BOX(hbox), button_hide_show, TRUE, TRUE, 0);
8249 /* Connect our callbacks to the three buttons */
8250 gtk_signal_connect_object(GTK_OBJECT(button_add), "clicked",
8251 GTK_SIGNAL_FUNC(button_add_clicked),
8253 gtk_signal_connect_object(GTK_OBJECT(button_clear), "clicked",
8254 GTK_SIGNAL_FUNC(button_clear_clicked),
8256 gtk_signal_connect_object(GTK_OBJECT(button_hide_show), "clicked",
8257 GTK_SIGNAL_FUNC(button_hide_show_clicked),
8260 gtk_widget_show(button_add);
8261 gtk_widget_show(button_clear);
8262 gtk_widget_show(button_hide_show);
8264 /* The interface is completely set up so we show the window and
8265 * enter the gtk_main loop.
8267 gtk_widget_show(window);
8273 /* User clicked the "Add List" button. */
8274 void button_add_clicked( GtkWidget *button, gpointer data)
8278 /* Something silly to add to the list. 4 rows of 2 columns each */
8279 gchar *drink[4][2] = {{"Milk", "3 Oz"},
8284 /* Here we do the actual adding of the text. It's done once for
8287 for( indx=0; indx < 4; indx++)
8288 gtk_clist_append( (GtkCList*) data, drink[indx]);
8293 /* User clicked the "Clear List" button. */
8294 void button_clear_clicked( GtkWidget *button, gpointer data)
8296 /* Clear the list using gtk_clist_clear. This is much faster than
8297 * calling gtk_clist_remove once for each row.
8299 gtk_clist_clear((GtkCList*) data);
8304 /* The user clicked the "Hide/Show titles" button. */
8305 void button_hide_show_clicked( GtkWidget *button, gpointer data)
8307 /* Just a flag to remember the status. 0 = currently visible */
8308 static short int flag = 0;
8312 /* Hide the titles and set the flag to 1 */
8313 gtk_clist_column_titles_hide((GtkCList*) data);
8318 /* Show the titles and reset flag to 0 */
8319 gtk_clist_column_titles_show((GtkCList*) data);
8326 /* If we come here, then the user has selected a row in the list. */
8327 void selection_made( GtkWidget *clist, gint row, gint column,
8328 GdkEventButton *event, gpointer data)
8332 /* Get the text that is stored in the selected row and column
8333 * which was clicked in. We will receive it as a pointer in the
8336 gtk_clist_get_text(GTK_CLIST(clist), row, column, &text);
8338 /* Just prints some information about the selected row */
8339 g_print("You selected row %d. More specifically you clicked in column %d, and the text in this cell is %s\n\n", row, column, text);
8346 <!-- ***************************************************************** -->
8347 <sect> Tree Widget <label id="sec_Tree_Widgets">
8348 <!-- ***************************************************************** -->
8350 The purpose of tree widgets is to display hierarchically-organized
8351 data. The GtkTree widget itself is a vertical container for widgets of
8352 type GtkTreeItem. GtkTree itself is not terribly different from
8353 GtkList - both are derived directly from GtkContainer, and the
8354 GtkContainer methods work in the same way on GtkTree widgets as on
8355 GtkList widgets. The difference is that GtkTree widgets can be nested
8356 within other GtkTree widgets. We'll see how to do this shortly.
8358 The GtkTree widget has its own window, and defaults to a white
8359 background, as does GtkList. Also, most of the GtkTree methods work in
8360 the same way as the corresponding GtkList ones. However, GtkTree is
8361 not derived from GtkList, so you cannot use them interchangeably.
8363 <sect1> Creating a Tree
8365 A GtkTree is created in the usual way, using:
8368 GtkWidget* gtk_tree_new( void );
8371 Like the GtkList widget, a GtkTree will simply keep growing as more
8372 items are added to it, as well as when subtrees are expanded. For
8373 this reason, they are almost always packed into a
8374 GtkScrolledWindow. You might want to use gtk_widget_set_usize() on the
8375 scrolled window to ensure that it is big enough to see the tree's
8376 items, as the default size for GtkScrolledWindow is quite small.
8378 Now that you have a tree, you'll probably want to add some items to
8379 it. <ref id="sec_Tree_Item_Widget" name="The Tree Item Widget"> below
8380 explains the gory details of GtkTreeItem. For now, it'll suffice to
8384 GtkWidget* gtk_tree_item_new_with_label( gchar *label );
8387 You can then add it to the tree using one of the following (see
8388 <ref id="sec_GtkTree_Functions" name="Functions and Macros">
8389 below for more options):
8392 void gtk_tree_append( GtkTree *tree,
8393 GtkWidget *tree_item );
8395 void gtk_tree_prepend( GtkTree *tree,
8396 GtkWidget *tree_item );
8399 Note that you must add items to a GtkTree one at a time - there is no
8400 equivalent to gtk_list_*_items().
8402 <!-- ----------------------------------------------------------------- -->
8403 <sect1> Adding a Subtree
8405 A subtree is created like any other GtkTree widget. A subtree is added
8406 to another tree beneath a tree item, using:
8409 void gtk_tree_item_set_subtree( GtkTreeItem *tree_item,
8410 GtkWidget *subtree );
8413 You do not need to call gtk_widget_show() on a subtree before or after
8414 adding it to a GtkTreeItem. However, you <em>must</em> have added the
8415 GtkTreeItem in question to a parent tree before calling
8416 gtk_tree_item_set_subtree(). This is because, technically, the parent
8417 of the subtree is <em>not</em> the GtkTreeItem which "owns" it, but
8418 rather the GtkTree which holds that GtkTreeItem.
8420 When you add a subtree to a GtkTreeItem, a plus or minus sign appears
8421 beside it, which the user can click on to "expand" or "collapse" it,
8422 meaning, to show or hide its subtree. GtkTreeItems are collapsed by
8423 default. Note that when you collapse a GtkTreeItem, any selected
8424 items in its subtree remain selected, which may not be what the user
8427 <!-- ----------------------------------------------------------------- -->
8428 <sect1> Handling the Selection List
8430 As with GtkList, the GtkTree type has a <tt>selection</tt> field, and
8431 it is possible to control the behaviour of the tree (somewhat) by
8432 setting the selection type using:
8435 void gtk_tree_set_selection_mode( GtkTree *tree,
8436 GtkSelectionMode mode );
8439 The semantics associated with the various selection modes are
8440 described in the section on the GtkList widget. As with the GtkList
8441 widget, the "select_child", "unselect_child" (not really - see <ref
8442 id="sec_GtkTree_Signals" name="Signals"> below for an explanation),
8443 and "selection_changed" signals are emitted when list items are
8444 selected or unselected. However, in order to take advantage of these
8445 signals, you need to know <em>which</em> GtkTree widget they will be
8446 emitted by, and where to find the list of selected items.
8448 This is a source of potential confusion. The best way to explain this
8449 is that though all GtkTree widgets are created equal, some are more
8450 equal than others. All GtkTree widgets have their own X window, and
8451 can therefore receive events such as mouse clicks (if their
8452 GtkTreeItems or their children don't catch them first!). However, to
8453 make GTK_SELECTION_SINGLE and GTK_SELECTION_BROWSE selection types
8454 behave in a sane manner, the list of selected items is specific to the
8455 topmost GtkTree widget in a hierarchy, known as the "root tree".
8457 Thus, accessing the <tt>selection</tt>field directly in an arbitrary
8458 GtkTree widget is not a good idea unless you <em>know</em> it's the
8459 root tree. Instead, use the GTK_TREE_SELECTION (Tree) macro, which
8460 gives the root tree's selection list as a GList pointer. Of course,
8461 this list can include items that are not in the subtree in question if
8462 the selection type is GTK_SELECTION_MULTIPLE.
8464 Finally, the "select_child" (and "unselect_child", in theory) signals
8465 are emitted by all trees, but the "selection_changed" signal is only
8466 emitted by the root tree. Consequently, if you want to handle the
8467 "select_child" signal for a tree and all its subtrees, you will have
8468 to call gtk_signal_connect() for every subtree.
8470 <sect1> Tree Widget Internals
8472 The GtkTree's struct definition looks like this:
8477 GtkContainer container;
8481 GtkTree* root_tree; /* owner of selection list */
8482 GtkWidget* tree_owner;
8486 guint current_indent;
8487 guint selection_mode : 2;
8488 guint view_mode : 1;
8489 guint view_line : 1;
8493 The perils associated with accessing the <tt>selection</tt> field
8494 directly have already been mentioned. The other important fields of
8495 the struct can also be accessed with handy macros or class functions.
8496 GTK_TREE_IS_ROOT_TREE (Tree) returns a boolean value which indicates
8497 whether a tree is the root tree in a GtkTree hierarchy, while
8498 GTK_TREE_ROOT_TREE (Tree) returns the root tree, an object of type
8499 GtkTree (so, remember to cast it using GTK_WIDGET (Tree) if you want
8500 to use one of the gtk_widget_*() functions on it).
8502 Instead of directly accessing the children field of a GtkTree widget,
8503 it's probably best to cast it using GTK_CONTAINER (Tree), and pass it
8504 to the gtk_container_children() function. This creates a duplicate of
8505 the original list, so it's advisable to free it up using g_list_free()
8506 after you're done with it, or to iterate on it destructively, like
8510 children = gtk_container_children (GTK_CONTAINER (tree));
8512 do_something_nice (GTK_TREE_ITEM (children->data));
8513 children = g_list_remove_link (children, children);
8517 The <tt>tree_owner</tt> field is defined only in subtrees, where it
8518 points to the GtkTreeItem widget which holds the tree in question.
8519 The <tt>level</tt> field indicates how deeply nested a particular tree
8520 is; root trees have level 0, and each successive level of subtrees has
8521 a level one greater than the parent level. This field is set only
8522 after a GtkTree widget is actually mapped (i.e. drawn on the screen).
8524 <sect2> Signals<label id="sec_GtkTree_Signals">
8527 void selection_changed( GtkTree *tree );
8530 This signal will be emitted whenever the <tt>selection</tt> field of a
8531 GtkTree has changed. This happens when a child of the GtkTree is
8532 selected or deselected.
8535 void select_child( GtkTree *tree,
8539 This signal is emitted when a child of the GtkTree is about to get
8540 selected. This happens on calls to gtk_tree_select_item(),
8541 gtk_tree_select_child(), on <em>all</em> button presses and calls to
8542 gtk_tree_item_toggle() and gtk_item_toggle(). It may sometimes be
8543 indirectly triggered on other occasions where children get added to or
8544 removed from the GtkTree.
8547 void unselect_child (GtkTree *tree,
8551 This signal is emitted when a child of the GtkTree is about to get
8552 deselected. As of GTK+ 1.0.4, this seems to only occur on calls to
8553 gtk_tree_unselect_item() or gtk_tree_unselect_child(), and perhaps on
8554 other occasions, but <em>not</em> when a button press deselects a
8555 child, nor on emission of the "toggle" signal by gtk_item_toggle().
8557 <sect2> Functions and Macros<label id="sec_GtkTree_Functions">
8560 guint gtk_tree_get_type( void );
8563 Returns the `GtkTree' type identifier.
8566 GtkWidget* gtk_tree_new( void );
8569 Create a new GtkTree object. The new widget is returned as a pointer
8570 to a GtkWidget object. NULL is returned on failure.
8573 void gtk_tree_append( GtkTree *tree,
8574 GtkWidget *tree_item );
8577 Append a tree item to a GtkTree.
8580 void gtk_tree_prepend( GtkTree *tree,
8581 GtkWidget *tree_item );
8584 Prepend a tree item to a GtkTree.
8587 void gtk_tree_insert( GtkTree *tree,
8588 GtkWidget *tree_item,
8592 Insert a tree item into a GtkTree at the position in the list
8593 specified by <tt>position.</tt>
8596 void gtk_tree_remove_items( GtkTree *tree,
8600 Remove a list of items (in the form of a GList *) from a GtkTree.
8601 Note that removing an item from a tree dereferences (and thus usually)
8602 destroys it <em>and</em> its subtree, if it has one, <em>and</em> all
8603 subtrees in that subtree. If you want to remove only one item, you
8604 can use gtk_container_remove().
8607 void gtk_tree_clear_items( GtkTree *tree,
8612 Remove the items from position <tt>start</tt> to position <tt>end</tt>
8613 from a GtkTree. The same warning about dereferencing applies here, as
8614 gtk_tree_clear_items() simply constructs a list and passes it to
8615 gtk_tree_remove_items().
8618 void gtk_tree_select_item( GtkTree *tree,
8622 Emits the "select_item" signal for the child at position
8623 <tt>item</tt>, thus selecting the child (unless you unselect it in a
8627 void gtk_tree_unselect_item( GtkTree *tree,
8631 Emits the "unselect_item" signal for the child at position
8632 <tt>item</tt>, thus unselecting the child.
8635 void gtk_tree_select_child( GtkTree *tree,
8636 GtkWidget *tree_item );
8639 Emits the "select_item" signal for the child <tt>tree_item</tt>, thus
8643 void gtk_tree_unselect_child( GtkTree *tree,
8644 GtkWidget *tree_item );
8647 Emits the "unselect_item" signal for the child <tt>tree_item</tt>,
8648 thus unselecting it.
8651 gint gtk_tree_child_position( GtkTree *tree,
8655 Returns the position in the tree of <tt>child</tt>, unless
8656 <tt>child</tt> is not in the tree, in which case it returns -1.
8659 void gtk_tree_set_selection_mode( GtkTree *tree,
8660 GtkSelectionMode mode );
8663 Sets the selection mode, which can be one of GTK_SELECTION_SINGLE (the
8664 default), GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE, or
8665 GTK_SELECTION_EXTENDED. This is only defined for root trees, which
8666 makes sense, since the root tree "owns" the selection. Setting it for
8667 subtrees has no effect at all; the value is simply ignored.
8670 void gtk_tree_set_view_mode( GtkTree *tree,
8671 GtkTreeViewMode mode );
8674 Sets the "view mode", which can be either GTK_TREE_VIEW_LINE (the
8675 default) or GTK_TREE_VIEW_ITEM. The view mode propagates from a tree
8676 to its subtrees, and can't be set exclusively to a subtree (this is
8677 not exactly true - see the example code comments).
8679 The term "view mode" is rather ambiguous - basically, it controls the
8680 way the highlight is drawn when one of a tree's children is selected.
8681 If it's GTK_TREE_VIEW_LINE, the entire GtkTreeItem widget is
8682 highlighted, while for GTK_TREE_VIEW_ITEM, only the child widget
8683 (i.e. usually the label) is highlighted.
8686 void gtk_tree_set_view_lines( GtkTree *tree,
8690 Controls whether connecting lines between tree items are drawn.
8691 <tt>flag</tt> is either TRUE, in which case they are, or FALSE, in
8692 which case they aren't.
8695 GtkTree *GTK_TREE (gpointer obj);
8698 Cast a generic pointer to `GtkTree *'.
8701 GtkTreeClass *GTK_TREE_CLASS (gpointer class);
8704 Cast a generic pointer to `GtkTreeClass*'.
8707 gint GTK_IS_TREE (gpointer obj);
8710 Determine if a generic pointer refers to a `GtkTree' object.
8713 gint GTK_IS_ROOT_TREE (gpointer obj)
8716 Determine if a generic pointer refers to a `GtkTree' object
8717 <em>and</em> is a root tree. Though this will accept any pointer, the
8718 results of passing it a pointer that does not refer to a GtkTree are
8719 undefined and possibly harmful.
8722 GtkTree *GTK_TREE_ROOT_TREE (gpointer obj)
8725 Return the root tree of a pointer to a `GtkTree' object. The above
8729 GList *GTK_TREE_SELECTION( gpointer obj)
8732 Return the selection list of the root tree of a `GtkTree' object. The
8733 above warning applies here, too.
8735 <sect1> Tree Item Widget<label id="sec_Tree_Item_Widget">
8737 The GtkTreeItem widget, like GtkListItem, is derived from GtkItem,
8738 which in turn is derived from GtkBin. Therefore, the item itself is a
8739 generic container holding exactly one child widget, which can be of
8740 any type. The GtkTreeItem widget has a number of extra fields, but
8741 the only one we need be concerned with is the <tt>subtree</tt> field.
8743 The definition for the GtkTreeItem struct looks like this:
8751 GtkWidget *pixmaps_box;
8752 GtkWidget *plus_pix_widget, *minus_pix_widget;
8754 GList *pixmaps; /* pixmap node for this items color depth */
8760 The <tt>pixmaps_box</tt> field is a GtkEventBox which catches clicks
8761 on the plus/minus symbol which controls expansion and collapsing. The
8762 <tt>pixmaps</tt> field points to an internal data structure. Since
8763 you can always obtain the subtree of a GtkTreeItem in a (relatively)
8764 type-safe manner with the GTK_TREE_ITEM_SUBTREE (Item) macro, it's
8765 probably advisable never to touch the insides of a GtkTreeItem unless
8766 you <em>really</em> know what you're doing.
8768 Since it is directly derived from a GtkItem it can be treated as such
8769 by using the GTK_ITEM (TreeItem) macro. A GtkTreeItem usually holds a
8770 label, so the convenience function gtk_list_item_new_with_label() is
8771 provided. The same effect can be achieved using code like the
8772 following, which is actually copied verbatim from
8773 gtk_tree_item_new_with_label():
8776 tree_item = gtk_tree_item_new ();
8777 label_widget = gtk_label_new (label);
8778 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
8780 gtk_container_add (GTK_CONTAINER (tree_item), label_widget);
8781 gtk_widget_show (label_widget);
8784 As one is not forced to add a GtkLabel to a GtkTreeItem, you could
8785 also add a GtkHBox or a GtkArrow, or even a GtkNotebook (though your
8786 app will likely be quite unpopular in this case) to the GtkTreeItem.
8788 If you remove all the items from a subtree, it will be destroyed and
8789 unparented, unless you reference it beforehand, and the GtkTreeItem
8790 which owns it will be collapsed. So, if you want it to stick around,
8791 do something like the following:
8794 gtk_widget_ref (tree);
8795 owner = GTK_TREE(tree)->tree_owner;
8796 gtk_container_remove (GTK_CONTAINER(tree), item);
8797 if (tree->parent == NULL){
8798 gtk_tree_item_expand (GTK_TREE_ITEM(owner));
8799 gtk_tree_item_set_subtree (GTK_TREE_ITEM(owner), tree);
8802 gtk_widget_unref (tree);
8805 Finally, drag-n-drop <em>does</em> work with GtkTreeItems. You just
8806 have to make sure that the GtkTreeItem you want to make into a drag
8807 item or a drop site has not only been added to a GtkTree, but that
8808 each successive parent widget has a parent itself, all the way back to
8809 a toplevel or dialog window, when you call gtk_widget_dnd_drag_set()
8810 or gtk_widget_dnd_drop_set(). Otherwise, strange things will happen.
8814 GtkTreeItem inherits the "select", "deselect", and "toggle" signals
8815 from GtkItem. In addition, it adds two signals of its own, "expand"
8819 void select( GtkItem *tree_item );
8822 This signal is emitted when an item is about to be selected, either
8823 after it has been clicked on by the user, or when the program calls
8824 gtk_tree_item_select(), gtk_item_select(), or gtk_tree_select_child().
8827 void deselect( GtkItem *tree_item );
8830 This signal is emitted when an item is about to be unselected, either
8831 after it has been clicked on by the user, or when the program calls
8832 gtk_tree_item_deselect() or gtk_item_deselect(). In the case of
8833 GtkTreeItems, it is also emitted by gtk_tree_unselect_child(), and
8834 sometimes gtk_tree_select_child().
8837 void toggle( GtkItem *tree_item );
8840 This signal is emitted when the program calls gtk_item_toggle(). The
8841 effect it has when emitted on a GtkTreeItem is to call
8842 gtk_tree_select_child() (and never gtk_tree_unselect_child()) on the
8843 item's parent tree, if the item has a parent tree. If it doesn't,
8844 then the highlight is reversed on the item.
8847 void expand( GtkTreeItem *tree_item );
8850 This signal is emitted when the tree item's subtree is about to be
8851 expanded, that is, when the user clicks on the plus sign next to the
8852 item, or when the program calls gtk_tree_item_expand().
8855 void collapse( GtkTreeItem *tree_item );
8858 This signal is emitted when the tree item's subtree is about to be
8859 collapsed, that is, when the user clicks on the minus sign next to the
8860 item, or when the program calls gtk_tree_item_collapse().
8862 <sect2> Functions and Macros
8865 guint gtk_tree_item_get_type( void );
8868 Returns the `GtkTreeItem' type identifier.
8871 GtkWidget* gtk_tree_item_new( void );
8874 Create a new GtkTreeItem object. The new widget is returned as a
8875 pointer to a GtkWidget object. NULL is returned on failure.
8878 GtkWidget* gtk_tree_item_new_with_label (gchar *label);
8881 Create a new GtkTreeItem object, having a single GtkLabel as the sole
8882 child. The new widget is returned as a pointer to a GtkWidget
8883 object. NULL is returned on failure.
8886 void gtk_tree_item_select( GtkTreeItem *tree_item );
8889 This function is basically a wrapper around a call to gtk_item_select
8890 (GTK_ITEM (tree_item)) which will emit the select signal.
8893 void gtk_tree_item_deselect( GtkTreeItem *tree_item );
8896 This function is basically a wrapper around a call to
8897 gtk_item_deselect (GTK_ITEM (tree_item)) which will emit the deselect
8901 void gtk_tree_item_set_subtree( GtkTreeItem *tree_item,
8902 GtkWidget *subtree );
8905 This function adds subtree to tree_item, showing it if tree_item is
8906 expanded, or hiding it if tree_item is collapsed. Again, remember that
8907 the tree_item must have already been added to a tree for this to work.
8910 void gtk_tree_item_remove_subtree( GtkTreeItem *tree_item );
8913 This removes all of tree_item's subtree's children (thus unreferencing
8914 and destroying it, any of its children's subtrees, and so on...), then
8915 removes the subtree itself, and hides the plus/minus sign.
8918 void gtk_tree_item_expand( GtkTreeItem *tree_item );
8921 This emits the "expand" signal on tree_item, which expands it.
8924 void gtk_tree_item_collapse( GtkTreeItem *tree_item );
8927 This emits the "collapse" signal on tree_item, which collapses it.
8930 GtkTreeItem *GTK_TREE_ITEM (gpointer obj)
8933 Cast a generic pointer to `GtkTreeItem*'.
8936 GtkTreeItemClass *GTK_TREE_ITEM_CLASS (gpointer obj)
8939 Cast a generic pointer to `GtkTreeItemClass'.
8942 gint GTK_IS_TREE_ITEM (gpointer obj)
8945 Determine if a generic pointer refers to a `GtkTreeItem' object.
8948 GtkWidget GTK_TREE_ITEM_SUBTREE (gpointer obj)
8951 Returns a tree item's subtree (obj should point to a `GtkTreeItem'
8954 <sect1> Tree Example
8956 This is somewhat like the tree example in testgtk.c, but a lot less
8957 complete (although much better commented). It puts up a window with a
8958 tree, and connects all the signals for the relevant objects, so you
8959 can see when they are emitted.
8962 /* example-start tree tree.c */
8964 #include <gtk/gtk.h>
8966 /* for all the GtkItem:: and GtkTreeItem:: signals */
8967 static void cb_itemsignal (GtkWidget *item, gchar *signame)
8972 /* It's a GtkBin, so it has one child, which we know to be a
8973 label, so get that */
8974 label = GTK_LABEL (GTK_BIN (item)->child);
8975 /* Get the text of the label */
8976 gtk_label_get (label, &name);
8977 /* Get the level of the tree which the item is in */
8978 g_print ("%s called for item %s->%p, level %d\n", signame, name,
8979 item, GTK_TREE (item->parent)->level);
8982 /* Note that this is never called */
8983 static void cb_unselect_child (GtkWidget *root_tree, GtkWidget *child,
8986 g_print ("unselect_child called for root tree %p, subtree %p, child %p\n",
8987 root_tree, subtree, child);
8990 /* Note that this is called every time the user clicks on an item,
8991 whether it is already selected or not. */
8992 static void cb_select_child (GtkWidget *root_tree, GtkWidget *child,
8995 g_print ("select_child called for root tree %p, subtree %p, child %p\n",
8996 root_tree, subtree, child);
8999 static void cb_selection_changed (GtkWidget *tree)
9003 g_print ("selection_change called for tree %p\n", tree);
9004 g_print ("selected objects are:\n");
9006 i = GTK_TREE_SELECTION(tree);
9012 /* Get a GtkWidget pointer from the list node */
9013 item = GTK_WIDGET (i->data);
9014 label = GTK_LABEL (GTK_BIN (item)->child);
9015 gtk_label_get (label, &name);
9016 g_print ("\t%s on level %d\n", name, GTK_TREE
9017 (item->parent)->level);
9022 int main (int argc, char *argv[])
9024 GtkWidget *window, *scrolled_win, *tree;
9025 static gchar *itemnames[] = {"Foo", "Bar", "Baz", "Quux",
9029 gtk_init (&argc, &argv);
9031 /* a generic toplevel window */
9032 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9033 gtk_signal_connect (GTK_OBJECT(window), "delete_event",
9034 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
9035 gtk_container_set_border_width (GTK_CONTAINER(window), 5);
9037 /* A generic scrolled window */
9038 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
9039 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
9040 GTK_POLICY_AUTOMATIC,
9041 GTK_POLICY_AUTOMATIC);
9042 gtk_widget_set_usize (scrolled_win, 150, 200);
9043 gtk_container_add (GTK_CONTAINER(window), scrolled_win);
9044 gtk_widget_show (scrolled_win);
9046 /* Create the root tree */
9047 tree = gtk_tree_new();
9048 g_print ("root tree is %p\n", tree);
9049 /* connect all GtkTree:: signals */
9050 gtk_signal_connect (GTK_OBJECT(tree), "select_child",
9051 GTK_SIGNAL_FUNC(cb_select_child), tree);
9052 gtk_signal_connect (GTK_OBJECT(tree), "unselect_child",
9053 GTK_SIGNAL_FUNC(cb_unselect_child), tree);
9054 gtk_signal_connect (GTK_OBJECT(tree), "selection_changed",
9055 GTK_SIGNAL_FUNC(cb_selection_changed), tree);
9056 /* Add it to the scrolled window */
9057 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW(scrolled_win),
9059 /* Set the selection mode */
9060 gtk_tree_set_selection_mode (GTK_TREE(tree),
9061 GTK_SELECTION_MULTIPLE);
9063 gtk_widget_show (tree);
9065 for (i = 0; i < 5; i++){
9066 GtkWidget *subtree, *item;
9069 /* Create a tree item */
9070 item = gtk_tree_item_new_with_label (itemnames[i]);
9071 /* Connect all GtkItem:: and GtkTreeItem:: signals */
9072 gtk_signal_connect (GTK_OBJECT(item), "select",
9073 GTK_SIGNAL_FUNC(cb_itemsignal), "select");
9074 gtk_signal_connect (GTK_OBJECT(item), "deselect",
9075 GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
9076 gtk_signal_connect (GTK_OBJECT(item), "toggle",
9077 GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
9078 gtk_signal_connect (GTK_OBJECT(item), "expand",
9079 GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
9080 gtk_signal_connect (GTK_OBJECT(item), "collapse",
9081 GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
9082 /* Add it to the parent tree */
9083 gtk_tree_append (GTK_TREE(tree), item);
9084 /* Show it - this can be done at any time */
9085 gtk_widget_show (item);
9086 /* Create this item's subtree */
9087 subtree = gtk_tree_new();
9088 g_print ("-> item %s->%p, subtree %p\n", itemnames[i], item,
9091 /* This is still necessary if you want these signals to be called
9092 for the subtree's children. Note that selection_change will be
9093 signalled for the root tree regardless. */
9094 gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
9095 GTK_SIGNAL_FUNC(cb_select_child), subtree);
9096 gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
9097 GTK_SIGNAL_FUNC(cb_unselect_child), subtree);
9098 /* This has absolutely no effect, because it is completely ignored
9100 gtk_tree_set_selection_mode (GTK_TREE(subtree),
9101 GTK_SELECTION_SINGLE);
9102 /* Neither does this, but for a rather different reason - the
9103 view_mode and view_line values of a tree are propagated to
9104 subtrees when they are mapped. So, setting it later on would
9105 actually have a (somewhat unpredictable) effect */
9106 gtk_tree_set_view_mode (GTK_TREE(subtree), GTK_TREE_VIEW_ITEM);
9107 /* Set this item's subtree - note that you cannot do this until
9108 AFTER the item has been added to its parent tree! */
9109 gtk_tree_item_set_subtree (GTK_TREE_ITEM(item), subtree);
9111 for (j = 0; j < 5; j++){
9114 /* Create a subtree item, in much the same way */
9115 subitem = gtk_tree_item_new_with_label (itemnames[j]);
9116 /* Connect all GtkItem:: and GtkTreeItem:: signals */
9117 gtk_signal_connect (GTK_OBJECT(subitem), "select",
9118 GTK_SIGNAL_FUNC(cb_itemsignal), "select");
9119 gtk_signal_connect (GTK_OBJECT(subitem), "deselect",
9120 GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
9121 gtk_signal_connect (GTK_OBJECT(subitem), "toggle",
9122 GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
9123 gtk_signal_connect (GTK_OBJECT(subitem), "expand",
9124 GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
9125 gtk_signal_connect (GTK_OBJECT(subitem), "collapse",
9126 GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
9127 g_print ("-> -> item %s->%p\n", itemnames[j], subitem);
9128 /* Add it to its parent tree */
9129 gtk_tree_append (GTK_TREE(subtree), subitem);
9131 gtk_widget_show (subitem);
9135 /* Show the window and loop endlessly */
9136 gtk_widget_show (window);
9143 <!-- ***************************************************************** -->
9145 <!-- ***************************************************************** -->
9147 There are two ways to create menus, there's the easy way, and there's
9148 the hard way. Both have their uses, but you can usually use the
9149 itemfactory (the easy way). The "hard" way is to create all the menus
9150 using the calls directly. The easy way is to use the gtk_item_factory
9151 calls. This is much simpler, but there are advantages and
9152 disadvantages to each approach.
9154 The itemfactory is much easier to use, and to add new menus to,
9155 although writing a few wrapper functions to create menus using the
9156 manual method could go a long way towards usability. With the
9157 menufactory, it is not possible to add images or the character '/' to
9160 <!-- ----------------------------------------------------------------- -->
9161 <sect1>Manual Menu Creation
9163 In the true tradition of teaching, we'll show you the hard way
9166 There are three widgets that go into making a menubar and submenus:
9168 <item>a menu item, which is what the user wants to select, e.g. 'Save'
9169 <item>a menu, which acts as a container for the menu items, and
9170 <item>a menubar, which is a container for each of the individual
9174 This is slightly complicated by the fact that menu item widgets are
9175 used for two different things. They are both the widgets that are
9176 packed into the menu, and the widget that is packed into the menubar,
9177 which, when selected, activates the menu.
9179 Let's look at the functions that are used to create menus and
9180 menubars. This first function is used to create a new menubar.
9184 GtkWidget *gtk_menu_bar_new( void );
9188 This rather self explanatory function creates a new menubar. You use
9189 gtk_container_add to pack this into a window, or the box_pack
9190 functions to pack it into a box - the same as buttons.
9193 GtkWidget *gtk_menu_new( void );
9196 This function returns a pointer to a new menu, it is never actually
9197 shown (with gtk_widget_show), it is just a container for the menu
9198 items. Hopefully this will become more clear when you look at the
9201 The next two calls are used to create menu items that are packed into
9202 the menu (and menubar).
9205 GtkWidget *gtk_menu_item_new( void );
9211 GtkWidget *gtk_menu_item_new_with_label( const char *label );
9214 These calls are used to create the menu items that are to be
9215 displayed. Remember to differentiate between a "menu" as created with
9216 gtk_menu_new and a "menu item" as created by the gtk_menu_item_new
9217 functions. The menu item will be an actual button with an associated
9218 action, whereas a menu will be a container holding menu items.
9220 The gtk_menu_new_with_label and gtk_menu_new functions are just as
9221 you'd expect after reading about the buttons. One creates a new menu
9222 item with a label already packed into it, and the other just creates a
9225 Once you've created a menu item you have to put it into a menu. This
9226 is done using the function gtk_menu_append. In order to capture when
9227 the item is selected by the user, we need to connect to the
9228 <tt/activate/ signal in the usual way. So, if we wanted to create a
9229 standard <tt/File/ menu, with the options <tt/Open/, <tt/Save/ and
9230 <tt/Quit/ the code would look something like:
9233 file_menu = gtk_menu_new(); /* Don't need to show menus */
9235 /* Create the menu items */
9236 open_item = gtk_menu_item_new_with_label("Open");
9237 save_item = gtk_menu_item_new_with_label("Save");
9238 quit_item = gtk_menu_item_new_with_label("Quit");
9240 /* Add them to the menu */
9241 gtk_menu_append( GTK_MENU(file_menu), open_item);
9242 gtk_menu_append( GTK_MENU(file_menu), save_item);
9243 gtk_menu_append( GTK_MENU(file_menu), quit_item);
9245 /* Attach the callback functions to the activate signal */
9246 gtk_signal_connect_object( GTK_OBJECT(open_items), "activate",
9247 GTK_SIGNAL_FUNC(menuitem_response),
9248 (gpointer) "file.open");
9249 gtk_signal_connect_object( GTK_OBJECT(save_items), "activate",
9250 GTK_SIGNAL_FUNC(menuitem_response),
9251 (gpointer) "file.save");
9253 /* We can attach the Quit menu item to our exit function */
9254 gtk_signal_connect_object( GTK_OBJECT(quit_items), "activate",
9255 GTK_SIGNAL_FUNC(destroy),
9256 (gpointer) "file.quit");
9258 /* We do need to show menu items */
9259 gtk_widget_show( open_item );
9260 gtk_widget_show( save_item );
9261 gtk_widget_show( quit_item );
9264 At this point we have our menu. Now we need to create a menubar and a
9265 menu item for the <tt/File/ entry, to which we add our menu. The code
9269 menu_bar = gtk_menu_bar_new();
9270 gtk_container_add( GTK_CONTAINER(window), menu_bar);
9271 gtk_widget_show( menu_bar );
9273 file_item = gtk_menu_item_new_with_label("File");
9274 gtk_widget_show(file_item);
9277 Now we need to associate the menu with <tt/file_item/. This is done
9281 void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
9282 GtkWidget *submenu );
9285 So, our example would continue with
9288 gtk_menu_item_set_submenu( GTK_MENU_ITEM(file_item), file_menu );
9291 All that is left to do is to add the menu to the menubar, which is
9292 accomplished using the function
9295 void gtk_menu_bar_append( GtkMenuBar *menu_bar, GtkWidget *menu_item);
9298 which in our case looks like this:
9301 gtk_menu_bar_append( GTK_MENU_BAR (menu_bar), file_item );
9304 If we wanted the menu right justified on the menubar, such as help
9305 menus often are, we can use the following function (again on
9306 <tt/file_item/ in the current example) before attaching it to the
9310 void gtk_menu_item_right_justify( GtkMenuItem *menu_item );
9313 Here is a summary of the steps needed to create a menu bar with menus
9317 <item> Create a new menu using gtk_menu_new()
9318 <item> Use multiple calls to gtk_menu_item_new() for each item you
9319 wish to have on your menu. And use gtk_menu_append() to put each of
9320 these new items on to the menu.
9321 <item> Create a menu item using gtk_menu_item_new(). This will be the
9322 root of the menu, the text appearing here will be on the menubar
9324 <item>Use gtk_menu_item_set_submenu() to attach the menu to the root
9325 menu item (the one created in the above step).
9326 <item> Create a new menubar using gtk_menu_bar_new. This step only
9327 needs to be done once when creating a series of menus on one menu bar.
9328 <item> Use gtk_menu_bar_append to put the root menu onto the menubar.
9331 Creating a popup menu is nearly the same. The difference is that the
9332 menu is not posted `automatically' by a menubar, but explicitly by
9333 calling the function gtk_menu_popup() from a button-press event, for
9334 example. Take these steps:
9337 <item>Create an event handling function. It needs to have the
9340 static gint handler( GtkWidget *widget,
9343 and it will use the event to find out where to pop up the menu.
9344 <item>In the event handler, if the event is a mouse button press,
9345 treat <tt>event</tt> as a button event (which it is) and use it as
9346 shown in the sample code to pass information to gtk_menu_popup().
9347 <item>Bind that event handler to a widget with
9349 gtk_signal_connect_object(GTK_OBJECT(widget), "event",
9350 GTK_SIGNAL_FUNC (handler),
9353 where <tt>widget</tt> is the widget you are binding to,
9354 <tt>handler</tt> is the handling function, and <tt>menu</tt> is a menu
9355 created with gtk_menu_new(). This can be a menu which is also posted
9356 by a menu bar, as shown in the sample code.
9359 <!-- ----------------------------------------------------------------- -->
9360 <sect1>Manual Menu Example
9362 That should about do it. Let's take a look at an example to help clarify.
9365 /* example-start menu menu.c */
9367 #include <gtk/gtk.h>
9369 static gint button_press (GtkWidget *, GdkEvent *);
9370 static void menuitem_response (gchar *);
9372 int main (int argc, char *argv[])
9377 GtkWidget *menu_bar;
9378 GtkWidget *root_menu;
9379 GtkWidget *menu_items;
9385 gtk_init (&argc, &argv);
9387 /* create a new window */
9388 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
9389 gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
9390 gtk_window_set_title(GTK_WINDOW (window), "GTK Menu Test");
9391 gtk_signal_connect(GTK_OBJECT (window), "delete_event",
9392 (GtkSignalFunc) gtk_main_quit, NULL);
9394 /* Init the menu-widget, and remember -- never
9395 * gtk_show_widget() the menu widget!!
9396 * This is the menu that holds the menu items, the one that
9397 * will pop up when you click on the "Root Menu" in the app */
9398 menu = gtk_menu_new();
9400 /* Next we make a little loop that makes three menu-entries for "test-menu".
9401 * Notice the call to gtk_menu_append. Here we are adding a list of
9402 * menu items to our menu. Normally, we'd also catch the "clicked"
9403 * signal on each of the menu items and setup a callback for it,
9404 * but it's omitted here to save space. */
9406 for(i = 0; i < 3; i++)
9408 /* Copy the names to the buf. */
9409 sprintf(buf, "Test-undermenu - %d", i);
9411 /* Create a new menu-item with a name... */
9412 menu_items = gtk_menu_item_new_with_label(buf);
9414 /* ...and add it to the menu. */
9415 gtk_menu_append(GTK_MENU (menu), menu_items);
9417 /* Do something interesting when the menuitem is selected */
9418 gtk_signal_connect_object(GTK_OBJECT(menu_items), "activate",
9419 GTK_SIGNAL_FUNC(menuitem_response), (gpointer) g_strdup(buf));
9421 /* Show the widget */
9422 gtk_widget_show(menu_items);
9425 /* This is the root menu, and will be the label
9426 * displayed on the menu bar. There won't be a signal handler attached,
9427 * as it only pops up the rest of the menu when pressed. */
9428 root_menu = gtk_menu_item_new_with_label("Root Menu");
9430 gtk_widget_show(root_menu);
9432 /* Now we specify that we want our newly created "menu" to be the menu
9433 * for the "root menu" */
9434 gtk_menu_item_set_submenu(GTK_MENU_ITEM (root_menu), menu);
9436 /* A vbox to put a menu and a button in: */
9437 vbox = gtk_vbox_new(FALSE, 0);
9438 gtk_container_add(GTK_CONTAINER(window), vbox);
9439 gtk_widget_show(vbox);
9441 /* Create a menu-bar to hold the menus and add it to our main window */
9442 menu_bar = gtk_menu_bar_new();
9443 gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 2);
9444 gtk_widget_show(menu_bar);
9446 /* Create a button to which to attach menu as a popup */
9447 button = gtk_button_new_with_label("press me");
9448 gtk_signal_connect_object(GTK_OBJECT(button), "event",
9449 GTK_SIGNAL_FUNC (button_press), GTK_OBJECT(menu));
9450 gtk_box_pack_end(GTK_BOX(vbox), button, TRUE, TRUE, 2);
9451 gtk_widget_show(button);
9453 /* And finally we append the menu-item to the menu-bar -- this is the
9454 * "root" menu-item I have been raving about =) */
9455 gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), root_menu);
9457 /* always display the window as the last step so it all splashes on
9458 * the screen at once. */
9459 gtk_widget_show(window);
9466 /* Respond to a button-press by posting a menu passed in as widget.
9468 * Note that the "widget" argument is the menu being posted, NOT
9469 * the button that was pressed.
9472 static gint button_press (GtkWidget *widget, GdkEvent *event)
9475 if (event->type == GDK_BUTTON_PRESS) {
9476 GdkEventButton *bevent = (GdkEventButton *) event;
9477 gtk_menu_popup (GTK_MENU(widget), NULL, NULL, NULL, NULL,
9478 bevent->button, bevent->time);
9479 /* Tell calling code that we have handled this event; the buck
9484 /* Tell calling code that we have not handled this event; pass it on. */
9489 /* Print a string when a menu item is selected */
9491 static void menuitem_response (gchar *string)
9493 printf("%s\n", string);
9498 You may also set a menu item to be insensitive and, using an accelerator
9499 table, bind keys to menu functions.
9501 <!-- ----------------------------------------------------------------- -->
9502 <sect1>Using GtkItemFactory
9504 Now that we've shown you the hard way, here's how you do it using the
9505 gtk_item_factory calls.
9507 <!-- ----------------------------------------------------------------- -->
9508 <sect1>Item Factory Example
9510 Here is an example using the GTK item factory.
9513 /* example-start menu itemfactory.c */
9515 #include <gtk/gtk.h>
9516 #include <strings.h>
9518 /* Obligatory basic callback */
9519 static void print_hello(GtkWidget *w, gpointer data) {
9520 g_message("Hello, World!\n");
9523 /* This is the GtkItemFactoryEntry structure used to generate new menus.
9524 Item 1: The menu path. The letter after the underscore indicates an
9525 accelerator key once the menu is open.
9526 Item 2: The accelerator key for the entry
9527 Item 3: The callback function.
9528 Item 4: The callback action. This changes the parameters with
9529 which the function is called. The default is 0.
9530 Item 5: The item type, used to define what kind of an item it is.
9531 Here are the possible values:
9535 "<Title>" -> create a title item
9536 "<Item>" -> create a simple item
9537 "<CheckItem>" -> create a check item
9538 "<ToggleItem>" -> create a toggle item
9539 "<RadioItem>" -> create a radio item
9540 <path> -> path of a radio item to link against
9541 "<Separator>" -> create a separator
9542 "<Branch>" -> create an item to hold sub items
9543 "<LastBranch>" -> create a right justified branch
9546 static GtkItemFactoryEntry menu_items[] = {
9547 {"/_File", NULL, NULL, 0, "<Branch>"},
9548 {"/File/_New", "<control>N", print_hello, 0, NULL},
9549 {"/File/_Open", "<control>O", print_hello, 0, NULL},
9550 {"/File/_Save", "<control>S", print_hello, 0, NULL},
9551 {"/File/Save _As", NULL, NULL, 0, NULL},
9552 {"/File/sep1", NULL, NULL, 0, "<Separator>"},
9553 {"/File/Quit", "<control>Q", gtk_main_quit, 0, NULL},
9554 {"/_Options", NULL, NULL, 0, "<Branch>"},
9555 {"/Options/Test", NULL, NULL, 0, NULL},
9556 {"/_Help", NULL, NULL, 0, "<LastBranch>"},
9557 {"/_Help/About", NULL, NULL, 0, NULL},
9561 void get_main_menu(GtkWidget *window, GtkWidget ** menubar) {
9562 int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
9563 GtkItemFactory *item_factory;
9564 GtkAccelGroup *accel_group;
9566 accel_group = gtk_accel_group_new();
9568 /* This function initializes the item factory.
9569 Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
9570 or GTK_TYPE_OPTION_MENU.
9571 Param 2: The path of the menu.
9572 Param 3: A pointer to a gtk_accel_group. The item factory sets up
9573 the accelerator table while generating menus.
9576 item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>",
9579 /* This function generates the menu items. Pass the item factory,
9580 the number of items in the array, the array itself, and any
9581 callback data for the the menu items. */
9582 gtk_item_factory_create_items(item_factory, nmenu_items, menu_items, NULL);
9584 /* Attach the new accelerator group to the window. */
9585 gtk_accel_group_attach (accel_group, GTK_OBJECT (window));
9588 /* Finally, return the actual menu bar created by the item factory. */
9589 *menubar = gtk_item_factory_get_widget(item_factory, "<main>");
9592 int main(int argc, char *argv[]) {
9594 GtkWidget *main_vbox;
9597 gtk_init(&argc, &argv);
9599 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
9600 gtk_signal_connect(GTK_OBJECT(window), "destroy",
9601 GTK_SIGNAL_FUNC(gtk_main_quit),
9603 gtk_window_set_title(GTK_WINDOW(window), "Item Factory");
9604 gtk_widget_set_usize(GTK_WIDGET(window), 300, 200);
9606 main_vbox = gtk_vbox_new(FALSE, 1);
9607 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
9608 gtk_container_add(GTK_CONTAINER(window), main_vbox);
9609 gtk_widget_show(main_vbox);
9611 get_main_menu(window, &menubar);
9612 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
9613 gtk_widget_show(menubar);
9615 gtk_widget_show(window);
9624 For now, there's only this example. An explanation and lots 'o' comments
9627 <!-- ***************************************************************** -->
9629 <!-- ***************************************************************** -->
9631 The Text widget allows multiple lines of text to be displayed and
9632 edited. It supports both multi-colored and multi-font text, allowing
9633 them to be mixed in any way we wish. It also has a wide set of key
9634 based text editing commands, which are compatible with Emacs.
9636 The text widget supports full cut-and-paste facilities, including the
9637 use of double- and triple-click to select a word and a whole line,
9640 <!-- ----------------------------------------------------------------- -->
9641 <sect1>Creating and Configuring a Text box
9643 There is only one function for creating a new Text widget.
9646 GtkWidget *gtk_text_new( GtkAdjustment *hadj,
9647 GtkAdjustment *vadj );
9650 The arguments allow us to give the Text widget pointers to Adjustments
9651 that can be used to track the viewing position of the widget. Passing
9652 NULL values to either or both of these arguments will cause the
9653 gtk_text_new function to create its own.
9656 void gtk_text_set_adjustments( GtkText *text,
9657 GtkAdjustment *hadj,
9658 GtkAdjustment *vadj );
9661 The above function allows the horizontal and vertical adjustments of a
9662 text widget to be changed at any time.
9664 The text widget will not automatically create its own scrollbars when
9665 the amount of text to be displayed is too long for the display
9666 window. We therefore have to create and add them to the display layout
9670 vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
9671 gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, FALSE, 0);
9672 gtk_widget_show (vscrollbar);
9675 The above code snippet creates a new vertical scrollbar, and attaches
9676 it to the vertical adjustment of the text widget, <tt/text/. It then
9677 packs it into a box in the normal way.
9679 Note, currently the GtkText widget does not support horizontal
9682 There are two main ways in which a Text widget can be used: to allow
9683 the user to edit a body of text, or to allow us to display multiple
9684 lines of text to the user. In order for us to switch between these
9685 modes of operation, the text widget has the following function:
9688 void gtk_text_set_editable( GtkText *text,
9692 The <tt/editable/ argument is a TRUE or FALSE value that specifies
9693 whether the user is permitted to edit the contents of the Text
9694 widget. When the text widget is editable, it will display a cursor at
9695 the current insertion point.
9697 You are not, however, restricted to just using the text widget in
9698 these two modes. You can toggle the editable state of the text widget
9699 at any time, and can insert text at any time.
9701 The text widget wraps lines of text that are too long to fit onto a
9702 single line of the display window. Its default behaviour is to break
9703 words across line breaks. This can be changed using the next function:
9706 void gtk_text_set_word_wrap( GtkText *text,
9710 Using this function allows us to specify that the text widget should
9711 wrap long lines on word boundaries. The <tt/word_wrap/ argument is a
9712 TRUE or FALSE value.
9714 <!-- ----------------------------------------------------------------- -->
9715 <sect1>Text Manipulation
9717 The current insertion point of a Text widget can be set using
9719 void gtk_text_set_point( GtkText *text,
9723 where <tt/index/ is the position to set the insertion point.
9725 Analogous to this is the function for getting the current insertion
9729 guint gtk_text_get_point( GtkText *text );
9732 A function that is useful in combination with the above two functions
9736 guint gtk_text_get_length( GtkText *text );
9739 which returns the current length of the Text widget. The length is the
9740 number of characters that are within the text block of the widget,
9741 including characters such as carriage-return, which marks the end of
9744 In order to insert text at the current insertion point of a Text
9745 widget, the function gtk_text_insert is used, which also allows us to
9746 specify background and foreground colors and a font for the text.
9749 void gtk_text_insert( GtkText *text,
9757 Passing a value of <tt/NULL/ in as the value for the foreground color,
9758 background colour or font will result in the values set within the
9759 widget style to be used. Using a value of <tt/-1/ for the length
9760 parameter will result in the whole of the text string given being
9763 The text widget is one of the few within GTK that redraws itself
9764 dynamically, outside of the gtk_main function. This means that all
9765 changes to the contents of the text widget take effect
9766 immediately. This may be undesirable when performing multiple changes
9767 to the text widget. In order to allow us to perform multiple updates
9768 to the text widget without it continuously redrawing, we can freeze
9769 the widget, which temporarily stops it from automatically redrawing
9770 itself every time it is changed. We can then thaw the widget after our
9771 updates are complete.
9773 The following two functions perform this freeze and thaw action:
9776 void gtk_text_freeze( GtkText *text );
9778 void gtk_text_thaw( GtkText *text );
9781 Text is deleted from the text widget relative to the current insertion
9782 point by the following two functions. The return value is a TRUE or
9783 FALSE indicator of whether the operation was successful.
9786 gint gtk_text_backward_delete( GtkText *text,
9789 gint gtk_text_forward_delete ( GtkText *text,
9793 If you want to retrieve the contents of the text widget, then the
9794 macro <tt/GTK_TEXT_INDEX(t, index)/ allows you to retrieve the
9795 character at position <tt/index/ within the text widget <tt/t/.
9797 To retrieve larger blocks of text, we can use the function
9800 gchar *gtk_editable_get_chars( GtkEditable *editable,
9805 This is a function of the parent class of the text widget. A value of
9806 -1 as <tt/end_pos/ signifies the end of the text. The index of the
9809 The function allocates a new chunk of memory for the text block, so
9810 don't forget to free it with a call to g_free when you have finished
9813 <!-- ----------------------------------------------------------------- -->
9814 <sect1>Keyboard Shortcuts
9816 The text widget has a number of pre-installed keyboard shortcuts for
9817 common editing, motion and selection functions. These are accessed
9818 using Control and Alt key combinations.
9820 In addition to these, holding down the Control key whilst using cursor
9821 key movement will move the cursor by words rather than
9822 characters. Holding down Shift whilst using cursor movement will
9823 extend the selection.
9825 <sect2>Motion Shortcuts
9828 <item> Ctrl-A Beginning of line
9829 <item> Ctrl-E End of line
9830 <item> Ctrl-N Next Line
9831 <item> Ctrl-P Previous Line
9832 <item> Ctrl-B Backward one character
9833 <item> Ctrl-F Forward one character
9834 <item> Alt-B Backward one word
9835 <item> Alt-F Forward one word
9838 <sect2>Editing Shortcuts
9841 <item> Ctrl-H Delete Backward Character (Backspace)
9842 <item> Ctrl-D Delete Forward Character (Delete)
9843 <item> Ctrl-W Delete Backward Word
9844 <item> Alt-D Delete Forward Word
9845 <item> Ctrl-K Delete to end of line
9846 <item> Ctrl-U Delete line
9849 <sect2>Selection Shortcuts
9852 <item> Ctrl-X Cut to clipboard
9853 <item> Ctrl-C Copy to clipboard
9854 <item> Ctrl-V Paste from clipboard
9857 <!-- ----------------------------------------------------------------- -->
9858 <sect1>A GtkText Example
9861 /* example-start text text.c */
9866 #include <gtk/gtk.h>
9868 void text_toggle_editable (GtkWidget *checkbutton,
9871 gtk_text_set_editable(GTK_TEXT(text),
9872 GTK_TOGGLE_BUTTON(checkbutton)->active);
9875 void text_toggle_word_wrap (GtkWidget *checkbutton,
9878 gtk_text_set_word_wrap(GTK_TEXT(text),
9879 GTK_TOGGLE_BUTTON(checkbutton)->active);
9882 void close_application( GtkWidget *widget, gpointer data )
9887 int main (int argc, char *argv[])
9895 GtkWidget *separator;
9897 GtkWidget *vscrollbar;
9901 GdkFont *fixed_font;
9905 gtk_init (&argc, &argv);
9907 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9908 gtk_widget_set_usize (window, 600, 500);
9909 gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, FALSE);
9910 gtk_signal_connect (GTK_OBJECT (window), "destroy",
9911 GTK_SIGNAL_FUNC(close_application),
9913 gtk_window_set_title (GTK_WINDOW (window), "Text Widget Example");
9914 gtk_container_set_border_width (GTK_CONTAINER (window), 0);
9917 box1 = gtk_vbox_new (FALSE, 0);
9918 gtk_container_add (GTK_CONTAINER (window), box1);
9919 gtk_widget_show (box1);
9922 box2 = gtk_vbox_new (FALSE, 10);
9923 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
9924 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
9925 gtk_widget_show (box2);
9928 table = gtk_table_new (2, 2, FALSE);
9929 gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
9930 gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
9931 gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
9932 gtk_widget_show (table);
9934 /* Create the GtkText widget */
9935 text = gtk_text_new (NULL, NULL);
9936 gtk_text_set_editable (GTK_TEXT (text), TRUE);
9937 gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
9938 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
9939 GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
9940 gtk_widget_show (text);
9942 /* Add a vertical scrollbar to the GtkText widget */
9943 vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
9944 gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
9945 GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
9946 gtk_widget_show (vscrollbar);
9948 /* Get the system colour map and allocate the colour red */
9949 cmap = gdk_colormap_get_system();
9950 colour.red = 0xffff;
9953 if (!gdk_color_alloc(cmap, &colour)) {
9954 g_error("couldn't allocate colour");
9957 /* Load a fixed font */
9958 fixed_font = gdk_font_load ("-misc-fixed-medium-r-*-*-*-140-*-*-*-*-*-*");
9960 /* Realizing a widget creates a window for it,
9961 * ready for us to insert some text */
9962 gtk_widget_realize (text);
9964 /* Freeze the text widget, ready for multiple updates */
9965 gtk_text_freeze (GTK_TEXT (text));
9967 /* Insert some coloured text */
9968 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
9970 gtk_text_insert (GTK_TEXT (text), NULL, &colour, NULL,
9972 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
9973 "text and different ", -1);
9974 gtk_text_insert (GTK_TEXT (text), fixed_font, &text->style->black, NULL,
9977 /* Load the file text.c into the text window */
9979 infile = fopen("text.c", "r");
9987 nchars = fread(buffer, 1, 1024, infile);
9988 gtk_text_insert (GTK_TEXT (text), fixed_font, NULL,
9989 NULL, buffer, nchars);
9998 /* Thaw the text widget, allowing the updates to become visible */
9999 gtk_text_thaw (GTK_TEXT (text));
10001 hbox = gtk_hbutton_box_new ();
10002 gtk_box_pack_start (GTK_BOX (box2), hbox, FALSE, FALSE, 0);
10003 gtk_widget_show (hbox);
10005 check = gtk_check_button_new_with_label("Editable");
10006 gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, FALSE, 0);
10007 gtk_signal_connect (GTK_OBJECT(check), "toggled",
10008 GTK_SIGNAL_FUNC(text_toggle_editable), text);
10009 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);
10010 gtk_widget_show (check);
10011 check = gtk_check_button_new_with_label("Wrap Words");
10012 gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, TRUE, 0);
10013 gtk_signal_connect (GTK_OBJECT(check), "toggled",
10014 GTK_SIGNAL_FUNC(text_toggle_word_wrap), text);
10015 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), FALSE);
10016 gtk_widget_show (check);
10018 separator = gtk_hseparator_new ();
10019 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
10020 gtk_widget_show (separator);
10022 box2 = gtk_vbox_new (FALSE, 10);
10023 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
10024 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
10025 gtk_widget_show (box2);
10027 button = gtk_button_new_with_label ("close");
10028 gtk_signal_connect (GTK_OBJECT (button), "clicked",
10029 GTK_SIGNAL_FUNC(close_application),
10031 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
10032 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
10033 gtk_widget_grab_default (button);
10034 gtk_widget_show (button);
10036 gtk_widget_show (window);
10046 <!-- ***************************************************************** -->
10047 <sect> Undocumented Widgets
10048 <!-- ***************************************************************** -->
10050 These all require authors! :) Please consider contributing to our
10053 If you must use one of these widgets that are undocumented, I strongly
10054 suggest you take a look at their respective header files in the GTK
10055 distribution. GTK's function names are very descriptive. Once you
10056 have an understanding of how things work, it's not difficult to figure
10057 out how to use a widget simply by looking at its function
10058 declarations. This, along with a few examples from others' code, and
10059 it should be no problem.
10061 When you do come to understand all the functions of a new undocumented
10062 widget, please consider writing a tutorial on it so others may benefit
10065 <!-- ----------------------------------------------------------------- -->
10068 <!-- ----------------------------------------------------------------- -->
10071 <!-- ----------------------------------------------------------------- -->
10074 <!-- ----------------------------------------------------------------- -->
10075 <sect1> Drawing Area
10077 <!-- ----------------------------------------------------------------- -->
10078 <sect1> Font Selection Dialog
10080 <!-- ----------------------------------------------------------------- -->
10081 <sect1> Gamma Curve
10083 <!-- ----------------------------------------------------------------- -->
10086 <!-- ----------------------------------------------------------------- -->
10089 <!-- ----------------------------------------------------------------- -->
10090 <sect1> Plugs and Sockets
10092 <!-- ----------------------------------------------------------------- -->
10098 (This may need to be rewritten to follow the style of the rest of the tutorial)
10102 Previews serve a number of purposes in GIMP/GTK. The most important one is
10103 this. High quality images may take up to tens of megabytes of memory - easy!
10104 Any operation on an image that big is bound to take a long time. If it takes
10105 you 5-10 trial-and-errors (i.e. 10-20 steps, since you have to revert after
10106 you make an error) to choose the desired modification, it make take you
10107 literally hours to make the right one - if you don't run out of memory
10108 first. People who have spent hours in color darkrooms know the feeling.
10109 Previews to the rescue!
10111 But the annoyance of the delay is not the only issue. Oftentimes it is
10112 helpful to compare the Before and After versions side-by-side or at least
10113 back-to-back. If you're working with big images and 10 second delays,
10114 obtaining the Before and After impressions is, to say the least, difficult.
10115 For 30M images (4"x6", 600dpi, 24 bit) the side-by-side comparison is right
10116 out for most people, while back-to-back is more like back-to-1001, 1002,
10117 ..., 1010-back! Previews to the rescue!
10119 But there's more. Previews allow for side-by-side pre-previews. In other
10120 words, you write a plug-in (e.g. the filterpack simulation) which would have
10121 a number of here's-what-it-would-look-like-if-you-were-to-do-this previews.
10122 An approach like this acts as a sort of a preview palette and is very
10123 effective for subtle changes. Let's go previews!
10125 There's more. For certain plug-ins real-time image-specific human
10126 intervention maybe necessary. In the SuperNova plug-in, for example, the
10127 user is asked to enter the coordinates of the center of the future
10128 supernova. The easiest way to do this, really, is to present the user with a
10129 preview and ask him to interactively select the spot. Let's go previews!
10131 Finally, a couple of misc uses. One can use previews even when not working
10132 with big images. For example, they are useful when rendering complicated
10133 patterns. (Just check out the venerable Diffraction plug-in + many other
10134 ones!) As another example, take a look at the colormap rotation plug-in
10135 (work in progress). You can also use previews for little logos inside you
10136 plug-ins and even for an image of yourself, The Author. Let's go previews!
10138 When Not to Use Previews
10140 Don't use previews for graphs, drawing etc. GDK is much faster for that. Use
10141 previews only for rendered images!
10145 You can stick a preview into just about anything. In a vbox, an hbox, a
10146 table, a button, etc. But they look their best in tight frames around them.
10147 Previews by themselves do not have borders and look flat without them. (Of
10148 course, if the flat look is what you want...) Tight frames provide the
10153 Previews in many ways are like any other widgets in GTK (whatever that
10154 means) except they possess an additional feature: they need to be filled with
10155 some sort of an image! First, we will deal exclusively with the GTK aspect
10156 of previews and then we'll discuss how to fill them.
10158 GtkWidget *preview!
10162 /* Create a preview widget,
10163 set its size, an show it */
10164 GtkWidget *preview;
10165 preview=gtk_preview_new(GTK_PREVIEW_COLOR)
10167 GTK_PREVIEW_GRAYSCALE);*/
10168 gtk_preview_size (GTK_PREVIEW (preview), WIDTH, HEIGHT);
10169 gtk_widget_show(preview);
10170 my_preview_rendering_function(preview);
10172 Oh yeah, like I said, previews look good inside frames, so how about:
10174 GtkWidget *create_a_preview(int Width,
10178 GtkWidget *preview;
10181 frame = gtk_frame_new(NULL);
10182 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
10183 gtk_container_set_border_width (GTK_CONTAINER(frame),0);
10184 gtk_widget_show(frame);
10186 preview=gtk_preview_new (Colorfulness?GTK_PREVIEW_COLOR
10187 :GTK_PREVIEW_GRAYSCALE);
10188 gtk_preview_size (GTK_PREVIEW (preview), Width, Height);
10189 gtk_container_add(GTK_CONTAINER(frame),preview);
10190 gtk_widget_show(preview);
10192 my_preview_rendering_function(preview);
10196 That's my basic preview. This routine returns the "parent" frame so you can
10197 place it somewhere else in your interface. Of course, you can pass the
10198 parent frame to this routine as a parameter. In many situations, however,
10199 the contents of the preview are changed continually by your application. In
10200 this case you may want to pass a pointer to the preview to a
10201 "create_a_preview()" and thus have control of it later.
10203 One more important note that may one day save you a lot of time. Sometimes
10204 it is desirable to label you preview. For example, you may label the preview
10205 containing the original image as "Original" and the one containing the
10206 modified image as "Less Original". It might occur to you to pack the
10207 preview along with the appropriate label into a vbox. The unexpected caveat
10208 is that if the label is wider than the preview (which may happen for a
10209 variety of reasons unforseeable to you, from the dynamic decision on the
10210 size of the preview to the size of the font) the frame expands and no longer
10211 fits tightly over the preview. The same problem can probably arise in other
10212 situations as well.
10216 The solution is to place the preview and the label into a 2x1 table and by
10217 attaching them with the following parameters (this is one possible variations
10218 of course. The key is no GTK_FILL in the second attachment):
10220 gtk_table_attach(GTK_TABLE(table),label,0,1,0,1,
10222 GTK_EXPAND|GTK_FILL,
10224 gtk_table_attach(GTK_TABLE(table),frame,0,1,1,2,
10230 And here's the result:
10236 Making a preview clickable is achieved most easily by placing it in a
10237 button. It also adds a nice border around the preview and you may not even
10238 need to place it in a frame. See the Filter Pack Simulation plug-in for an
10241 This is pretty much it as far as GTK is concerned.
10243 Filling In a Preview
10245 In order to familiarize ourselves with the basics of filling in previews,
10246 let's create the following pattern (contrived by trial and error):
10251 my_preview_rendering_function(GtkWidget *preview)
10254 #define HALF (SIZE/2)
10256 guchar *row=(guchar *) malloc(3*SIZE); /* 3 bits per dot */
10257 gint i, j; /* Coordinates */
10258 double r, alpha, x, y;
10260 if (preview==NULL) return; /* I usually add this when I want */
10261 /* to avoid silly crashes. You */
10262 /* should probably make sure that */
10263 /* everything has been nicely */
10265 for (j=0; j < ABS(cos(2*alpha)) ) { /* Are we inside the shape? */
10266 /* glib.h contains ABS(x). */
10267 row[i*3+0] = sqrt(1-r)*255; /* Define Red */
10268 row[i*3+1] = 128; /* Define Green */
10269 row[i*3+2] = 224; /* Define Blue */
10270 } /* "+0" is for alignment! */
10272 row[i*3+0] = r*255;
10273 row[i*3+1] = ABS(sin((float)i/SIZE*2*PI))*255;
10274 row[i*3+2] = ABS(sin((float)j/SIZE*2*PI))*255;
10277 gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,j,SIZE);
10278 /* Insert "row" into "preview" starting at the point with */
10279 /* coordinates (0,j) first column, j_th row extending SIZE */
10280 /* pixels to the right */
10283 free(row); /* save some space */
10284 gtk_widget_draw(preview,NULL); /* what does this do? */
10285 gdk_flush(); /* or this? */
10288 Non-GIMP users can have probably seen enough to do a lot of things already.
10289 For the GIMP users I have a few pointers to add.
10293 It is probably wise to keep a reduced version of the image around with just
10294 enough pixels to fill the preview. This is done by selecting every n'th
10295 pixel where n is the ratio of the size of the image to the size of the
10296 preview. All further operations (including filling in the previews) are then
10297 performed on the reduced number of pixels only. The following is my
10298 implementation of reducing the image. (Keep in mind that I've had only basic
10301 (UNTESTED CODE ALERT!!!)
10313 SELECTION_IN_CONTEXT,
10317 ReducedImage *Reduce_The_Image(GDrawable *drawable,
10322 /* This function reduced the image down to the the selected preview size */
10323 /* The preview size is determine by LongerSize, i.e. the greater of the */
10324 /* two dimensions. Works for RGB images only! */
10325 gint RH, RW; /* Reduced height and reduced width */
10326 gint width, height; /* Width and Height of the area being reduced */
10327 gint bytes=drawable->bpp;
10328 ReducedImage *temp=(ReducedImage *)malloc(sizeof(ReducedImage));
10330 guchar *tempRGB, *src_row, *tempmask, *src_mask_row,R,G,B;
10331 gint i, j, whichcol, whichrow, x1, x2, y1, y2;
10332 GPixelRgn srcPR, srcMask;
10333 gint NoSelectionMade=TRUE; /* Assume that we're dealing with the entire */
10336 gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
10339 /* If there's a SELECTION, we got its bounds!)
10341 if (width != drawable->width && height != drawable->height)
10342 NoSelectionMade=FALSE;
10343 /* Become aware of whether the user has made an active selection */
10344 /* This will become important later, when creating a reduced mask. */
10346 /* If we want to preview the entire image, overrule the above! */
10347 /* Of course, if no selection has been made, this does nothing! */
10348 if (Selection==ENTIRE_IMAGE) {
10350 x2=drawable->width;
10352 y2=drawable->height;
10355 /* If we want to preview a selection with some surrounding area we */
10356 /* have to expand it a little bit. Consider it a bit of a riddle. */
10357 if (Selection==SELECTION_IN_CONTEXT) {
10358 x1=MAX(0, x1-width/2.0);
10359 x2=MIN(drawable->width, x2+width/2.0);
10360 y1=MAX(0, y1-height/2.0);
10361 y2=MIN(drawable->height, y2+height/2.0);
10364 /* How we can determine the width and the height of the area being */
10369 /* The lines below determine which dimension is to be the longer */
10370 /* side. The idea borrowed from the supernova plug-in. I suspect I */
10371 /* could've thought of it myself, but the truth must be told. */
10372 /* Plagiarism stinks! */
10373 if (width>height) {
10375 RH=(float) height * (float) LongerSize/ (float) width;
10379 RW=(float)width * (float) LongerSize/ (float) height;
10382 /* The entire image is stretched into a string! */
10383 tempRGB = (guchar *) malloc(RW*RH*bytes);
10384 tempmask = (guchar *) malloc(RW*RH);
10386 gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height,
10388 gimp_pixel_rgn_init (&srcMask, mask, x1, y1, width, height,
10391 /* Grab enough to save a row of image and a row of mask. */
10392 src_row = (guchar *) malloc (width*bytes);
10393 src_mask_row = (guchar *) malloc (width);
10395 for (i=0; i < RH; i++) {
10396 whichrow=(float)i*(float)height/(float)RH;
10397 gimp_pixel_rgn_get_row (&srcPR, src_row, x1, y1+whichrow, width);
10398 gimp_pixel_rgn_get_row (&srcMask, src_mask_row, x1, y1+whichrow, width);
10400 for (j=0; j < RW; j++) {
10401 whichcol=(float)j*(float)width/(float)RW;
10403 /* No selection made = each point is completely selected! */
10404 if (NoSelectionMade)
10405 tempmask[i*RW+j]=255;
10407 tempmask[i*RW+j]=src_mask_row[whichcol];
10409 /* Add the row to the one long string which now contains the image! */
10410 tempRGB[i*RW*bytes+j*bytes+0]=src_row[whichcol*bytes+0];
10411 tempRGB[i*RW*bytes+j*bytes+1]=src_row[whichcol*bytes+1];
10412 tempRGB[i*RW*bytes+j*bytes+2]=src_row[whichcol*bytes+2];
10414 /* Hold on to the alpha as well */
10416 tempRGB[i*RW*bytes+j*bytes+3]=src_row[whichcol*bytes+3];
10423 temp->mask=tempmask;
10427 The following is a preview function which used the same ReducedImage type!
10428 Note that it uses fakes transparency (if one is present by means of
10429 fake_transparency which is defined as follows:
10431 gint fake_transparency(gint i, gint j)
10433 if ( ((i%20)- 10) * ((j%20)- 10)>0 )
10439 Now here's the preview function:
10442 my_preview_render_function(GtkWidget *preview,
10446 gint Inten, bytes=drawable->bpp;
10449 gint RW=reduced->width;
10450 gint RH=reduced->height;
10451 guchar *row=malloc(bytes*RW);;
10454 for (i=0; i < RH; i++) {
10455 for (j=0; j < RW; j++) {
10457 row[j*3+0] = reduced->rgb[i*RW*bytes + j*bytes + 0];
10458 row[j*3+1] = reduced->rgb[i*RW*bytes + j*bytes + 1];
10459 row[j*3+2] = reduced->rgb[i*RW*bytes + j*bytes + 2];
10462 for (k=0; k<3; k++) {
10463 float transp=reduced->rgb[i*RW*bytes+j*bytes+3]/255.0;
10464 row[3*j+k]=transp*a[3*j+k]+(1-transp)*fake_transparency(i,j);
10467 gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,i,RW);
10471 gtk_widget_draw(preview,NULL);
10475 Applicable Routines
10477 guint gtk_preview_get_type (void);
10479 void gtk_preview_uninit (void);
10481 GtkWidget* gtk_preview_new (GtkPreviewType type);
10482 /* Described above */
10483 void gtk_preview_size (GtkPreview *preview,
10486 /* Allows you to resize an existing preview. */
10487 /* Apparently there's a bug in GTK which makes */
10488 /* this process messy. A way to clean up a mess */
10489 /* is to manually resize the window containing */
10490 /* the preview after resizing the preview. */
10492 void gtk_preview_put (GtkPreview *preview,
10503 void gtk_preview_put_row (GtkPreview *preview,
10511 void gtk_preview_draw_row (GtkPreview *preview,
10516 /* Described in the text */
10518 void gtk_preview_set_expand (GtkPreview *preview,
10522 /* No clue for any of the below but */
10523 /* should be standard for most widgets */
10524 void gtk_preview_set_gamma (double gamma);
10525 void gtk_preview_set_color_cube (guint nred_shades,
10526 guint ngreen_shades,
10527 guint nblue_shades,
10528 guint ngray_shades);
10529 void gtk_preview_set_install_cmap (gint install_cmap);
10530 void gtk_preview_set_reserved (gint nreserved);
10531 GdkVisual* gtk_preview_get_visual (void);
10532 GdkColormap* gtk_preview_get_cmap (void);
10533 GtkPreviewInfo* gtk_preview_get_info (void);
10541 <!-- ***************************************************************** -->
10542 <sect>Setting Widget Attributes<label id="sec_setting_widget_attributes">
10543 <!-- ***************************************************************** -->
10545 This describes the functions used to operate on widgets. These can be
10546 used to set style, padding, size etc.
10548 (Maybe I should make a whole section on accelerators.)
10551 void gtk_widget_install_accelerator( GtkWidget *widget,
10552 GtkAcceleratorTable *table,
10553 gchar *signal_name,
10555 guint8 modifiers );
10557 void gtk_widget_remove_accelerator ( GtkWidget *widget,
10558 GtkAcceleratorTable *table,
10559 gchar *signal_name);
10561 void gtk_widget_activate( GtkWidget *widget );
10563 void gtk_widget_set_name( GtkWidget *widget,
10566 gchar *gtk_widget_get_name( GtkWidget *widget );
10568 void gtk_widget_set_sensitive( GtkWidget *widget,
10571 void gtk_widget_set_style( GtkWidget *widget,
10574 GtkStyle *gtk_widget_get_style( GtkWidget *widget );
10576 GtkStyle *gtk_widget_get_default_style( void );
10578 void gtk_widget_set_uposition( GtkWidget *widget,
10582 void gtk_widget_set_usize( GtkWidget *widget,
10586 void gtk_widget_grab_focus( GtkWidget *widget );
10588 void gtk_widget_show( GtkWidget *widget );
10590 void gtk_widget_hide( GtkWidget *widget );
10593 <!-- ***************************************************************** -->
10594 <sect>Timeouts, IO and Idle Functions<label id="sec_timeouts">
10595 <!-- ***************************************************************** -->
10597 <!-- ----------------------------------------------------------------- -->
10600 You may be wondering how you make GTK do useful work when in gtk_main.
10601 Well, you have several options. Using the following functions you can
10602 create a timeout function that will be called every "interval"
10606 gint gtk_timeout_add( guint32 interval,
10607 GtkFunction function,
10611 The first argument is the number of milliseconds between calls to your
10612 function. The second argument is the function you wish to have called,
10613 and the third, the data passed to this callback function. The return
10614 value is an integer "tag" which may be used to stop the timeout by
10618 void gtk_timeout_remove( gint tag );
10621 You may also stop the timeout function by returning zero or FALSE from
10622 your callback function. Obviously this means if you want your function
10623 to continue to be called, it should return a non-zero value,
10626 The declaration of your callback should look something like this:
10629 gint timeout_callback( gpointer data );
10632 <!-- ----------------------------------------------------------------- -->
10633 <sect1>Monitoring IO
10635 A nifty feature of GDK (the library that underlies GTK), is the
10636 ability to have it check for data on a file descriptor for you (as
10637 returned by open(2) or socket(2)). This is especially useful for
10638 networking applications. The function:
10641 gint gdk_input_add( gint source,
10642 GdkInputCondition condition,
10643 GdkInputFunction function,
10647 Where the first argument is the file descriptor you wish to have
10648 watched, and the second specifies what you want GDK to look for. This
10652 <item>GDK_INPUT_READ - Call your function when there is data ready for
10653 reading on your file descriptor.
10655 <item>GDK_INPUT_WRITE - Call your function when the file descriptor is
10659 As I'm sure you've figured out already, the third argument is the
10660 function you wish to have called when the above conditions are
10661 satisfied, and the fourth is the data to pass to this function.
10663 The return value is a tag that may be used to stop GDK from monitoring
10664 this file descriptor using the following function.
10667 void gdk_input_remove( gint tag );
10670 The callback function should be declared as:
10673 void input_callback( gpointer data,
10675 GdkInputCondition condition );
10678 Where <tt/source/ and <tt/condition/ are as specified above.
10680 <!-- ----------------------------------------------------------------- -->
10681 <sect1>Idle Functions
10683 <!-- TODO: Need to check on idle priorities - TRG -->
10684 What if you have a function you want called when nothing else is
10688 gint gtk_idle_add( GtkFunction function,
10692 This causes GTK to call the specified function whenever nothing else
10696 void gtk_idle_remove( gint tag );
10699 I won't explain the meaning of the arguments as they follow very much
10700 like the ones above. The function pointed to by the first argument to
10701 gtk_idle_add will be called whenever the opportunity arises. As with
10702 the others, returning FALSE will stop the idle function from being
10705 <!-- ***************************************************************** -->
10706 <sect>Advanced Event and Signal Handling<label id="sec_Adv_Events_and_Signals">
10707 <!-- ***************************************************************** -->
10709 <!-- ----------------------------------------------------------------- -->
10710 <sect1>Signal Functions
10712 <!-- ----------------------------------------------------------------- -->
10713 <sect2>Connecting and Disconnecting Signal Handlers
10717 guint gtk_signal_connect( GtkObject *object,
10719 GtkSignalFunc func,
10720 gpointer func_data );
10722 guint gtk_signal_connect_after( GtkObject *object,
10724 GtkSignalFunc func,
10725 gpointer func_data );
10727 guint gtk_signal_connect_object( GtkObject *object,
10729 GtkSignalFunc func,
10730 GtkObject *slot_object );
10732 guint gtk_signal_connect_object_after( GtkObject *object,
10734 GtkSignalFunc func,
10735 GtkObject *slot_object );
10737 guint gtk_signal_connect_full( GtkObject *object,
10739 GtkSignalFunc func,
10740 GtkCallbackMarshal marshal,
10742 GtkDestroyNotify destroy_func,
10743 gint object_signal,
10746 guint gtk_signal_connect_interp( GtkObject *object,
10748 GtkCallbackMarshal func,
10750 GtkDestroyNotify destroy_func,
10753 void gtk_signal_connect_object_while_alive( GtkObject *object,
10754 const gchar *signal,
10755 GtkSignalFunc func,
10756 GtkObject *alive_object );
10758 void gtk_signal_connect_while_alive( GtkObject *object,
10759 const gchar *signal,
10760 GtkSignalFunc func,
10761 gpointer func_data,
10762 GtkObject *alive_object );
10764 void gtk_signal_disconnect( GtkObject *object,
10765 guint handler_id );
10767 void gtk_signal_disconnect_by_func( GtkObject *object,
10768 GtkSignalFunc func,
10772 <!-- ----------------------------------------------------------------- -->
10773 <sect2>Blocking and Unblocking Signal Handlers
10776 void gtk_signal_handler_block( GtkObject *object,
10779 void gtk_signal_handler_block_by_func( GtkObject *object,
10780 GtkSignalFunc func,
10783 void gtk_signal_handler_block_by_data( GtkObject *object,
10786 void gtk_signal_handler_unblock( GtkObject *object,
10787 guint handler_id );
10789 void gtk_signal_handler_unblock_by_func( GtkObject *object,
10790 GtkSignalFunc func,
10793 void gtk_signal_handler_unblock_by_data( GtkObject *object,
10797 <!-- ----------------------------------------------------------------- -->
10798 <sect2>Emitting and Stopping Signals
10801 void gtk_signal_emit( GtkObject *object,
10805 void gtk_signal_emit_by_name( GtkObject *object,
10809 void gtk_signal_emitv( GtkObject *object,
10813 void gtk_signal_emitv_by_name( GtkObject *object,
10817 guint gtk_signal_n_emissions( GtkObject *object,
10820 guint gtk_signal_n_emissions_by_name( GtkObject *object,
10821 const gchar *name );
10823 void gtk_signal_emit_stop( GtkObject *object,
10826 void gtk_signal_emit_stop_by_name( GtkObject *object,
10827 const gchar *name );
10830 <!-- ----------------------------------------------------------------- -->
10831 <sect1>Signal Emission and Propagation
10833 Signal emission is the process wherby GTK runs all handlers for a
10834 specific object and signal.
10836 First, note that the return value from a signal emission is the return
10837 value of the <em>last</em> handler executed. Since event signals are
10838 all of type GTK_RUN_LAST, this will be the default (GTK supplied)
10839 default handler, unless you connect with gtk_signal_connect_after().
10841 The way an event (say GTK_BUTTON_PRESS) is handled, is:
10843 <item>Start with the widget where the event occured.
10845 <item>Emit the generic "event" signal. If that signal handler returns
10846 a value of TRUE, stop all processing.
10848 <item>Otherwise, emit a specific, "button_press_event" signal. If that
10849 returns TRUE, stop all processing.
10851 <item>Otherwise, go to the widget's parent, and repeat the above steps.
10853 <item>Contimue until some signal handler returns TRUE, or until the
10854 top-level widget is reached.
10857 Some consequences of the above are:
10859 <item>Your handler's return value will have no effect if there is a
10860 default handler, unless you connect with gtk_signal_connect_after().
10862 <item>To prevent the default handler from being run, you need to
10863 connect with gtk_signal_connect() and use
10864 gtk_signal_emit_stop_by_name() - the return value only affects whether
10865 the signal is propagated, not the current emission.
10868 <!-- ***************************************************************** -->
10869 <sect>Managing Selections
10870 <!-- ***************************************************************** -->
10872 <!-- ----------------------------------------------------------------- -->
10875 One type of interprocess communication supported by GTK is
10876 <em>selections</em>. A selection identifies a chunk of data, for
10877 instance, a portion of text, selected by the user in some fashion, for
10878 instance, by dragging with the mouse. Only one application on a
10879 display, (the <em>owner</em>) can own a particular selection at one
10880 time, so when a selection is claimed by one application, the previous
10881 owner must indicate to the user that selection has been
10882 relinquished. Other applications can request the contents of a
10883 selection in different forms, called <em>targets</em>. There can be
10884 any number of selections, but most X applications only handle one, the
10885 <em>primary selection</em>.
10887 In most cases, it isn't necessary for a GTK application to deal with
10888 selections itself. The standard widgets, such as the Entry widget,
10889 already have the capability to claim the selection when appropriate
10890 (e.g., when the user drags over text), and to retrieve the contents of
10891 the selection owned by another widget, or another application (e.g.,
10892 when the user clicks the second mouse button). However, there may be
10893 cases in which you want to give other widgets the ability to supply
10894 the selection, or you wish to retrieve targets not supported by
10897 A fundamental concept needed to understand selection handling is that
10898 of the <em>atom</em>. An atom is an integer that uniquely identifies a
10899 string (on a certain display). Certain atoms are predefined by the X
10900 server, and in some cases there are constants in <tt>gtk.h</tt>
10901 corresponding to these atoms. For instance the constant
10902 <tt>GDK_PRIMARY_SELECTION</tt> corresponds to the string "PRIMARY".
10903 In other cases, you should use the functions
10904 <tt>gdk_atom_intern()</tt>, to get the atom corresponding to a string,
10905 and <tt>gdk_atom_name()</tt>, to get the name of an atom. Both
10906 selections and targets are identified by atoms.
10908 <!-- ----------------------------------------------------------------- -->
10909 <sect1> Retrieving the selection
10911 Retrieving the selection is an asynchronous process. To start the
10915 gint gtk_selection_convert( GtkWidget *widget,
10921 This <em>converts</em> the selection into the form specified by
10922 <tt/target/. If at all possible, the time field should be the time
10923 from the event that triggered the selection. This helps make sure that
10924 events occur in the order that the user requested them. However, if it
10925 is not available (for instance, if the conversion was triggered by a
10926 "clicked" signal), then you can use the constant
10927 <tt>GDK_CURRENT_TIME</tt>.
10929 When the selection owner responds to the request, a
10930 "selection_received" signal is sent to your application. The handler
10931 for this signal receives a pointer to a <tt>GtkSelectionData</tt>
10932 structure, which is defined as:
10935 struct _GtkSelectionData
10946 <tt>selection</tt> and <tt>target</tt> are the values you gave in your
10947 <tt>gtk_selection_convert()</tt> call. <tt>type</tt> is an atom that
10948 identifies the type of data returned by the selection owner. Some
10949 possible values are "STRING", a string of latin-1 characters, "ATOM",
10950 a series of atoms, "INTEGER", an integer, etc. Most targets can only
10951 return one type. <tt/format/ gives the length of the units (for
10952 instance characters) in bits. Usually, you don't care about this when
10953 receiving data. <tt>data</tt> is a pointer to the returned data, and
10954 <tt>length</tt> gives the length of the returned data, in bytes. If
10955 <tt>length</tt> is negative, then an error occurred and the selection
10956 could not be retrieved. This might happen if no application owned the
10957 selection, or if you requested a target that the application didn't
10958 support. The buffer is actually guaranteed to be one byte longer than
10959 <tt>length</tt>; the extra byte will always be zero, so it isn't
10960 necessary to make a copy of strings just to null terminate them.
10962 In the following example, we retrieve the special target "TARGETS",
10963 which is a list of all targets into which the selection can be
10967 /* example-start selection gettargets.c */
10969 #include <gtk/gtk.h>
10971 void selection_received (GtkWidget *widget,
10972 GtkSelectionData *selection_data,
10975 /* Signal handler invoked when user clicks on the "Get Targets" button */
10977 get_targets (GtkWidget *widget, gpointer data)
10979 static GdkAtom targets_atom = GDK_NONE;
10981 /* Get the atom corresponding to the string "TARGETS" */
10982 if (targets_atom == GDK_NONE)
10983 targets_atom = gdk_atom_intern ("TARGETS", FALSE);
10985 /* And request the "TARGETS" target for the primary selection */
10986 gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
10990 /* Signal handler called when the selections owner returns the data */
10992 selection_received (GtkWidget *widget, GtkSelectionData *selection_data,
10999 /* **** IMPORTANT **** Check to see if retrieval succeeded */
11000 if (selection_data->length < 0)
11002 g_print ("Selection retrieval failed\n");
11005 /* Make sure we got the data in the expected form */
11006 if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
11008 g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
11012 /* Print out the atoms we received */
11013 atoms = (GdkAtom *)selection_data->data;
11016 for (i=0; i<selection_data->length/sizeof(GdkAtom); i++)
11019 name = gdk_atom_name (atoms[i]);
11021 g_print ("%s\n",name);
11023 g_print ("(bad atom)\n");
11030 main (int argc, char *argv[])
11035 gtk_init (&argc, &argv);
11037 /* Create the toplevel window */
11039 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11040 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
11041 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
11043 gtk_signal_connect (GTK_OBJECT (window), "destroy",
11044 GTK_SIGNAL_FUNC (gtk_exit), NULL);
11046 /* Create a button the user can click to get targets */
11048 button = gtk_button_new_with_label ("Get Targets");
11049 gtk_container_add (GTK_CONTAINER (window), button);
11051 gtk_signal_connect (GTK_OBJECT(button), "clicked",
11052 GTK_SIGNAL_FUNC (get_targets), NULL);
11053 gtk_signal_connect (GTK_OBJECT(button), "selection_received",
11054 GTK_SIGNAL_FUNC (selection_received), NULL);
11056 gtk_widget_show (button);
11057 gtk_widget_show (window);
11066 <!-- ----------------------------------------------------------------- -->
11067 <sect1> Supplying the selection
11069 Supplying the selection is a bit more complicated. You must register
11070 handlers that will be called when your selection is requested. For
11071 each selection/target pair you will handle, you make a call to:
11074 void gtk_selection_add_handler( GtkWidget *widget,
11077 GtkSelectionFunction function,
11078 GtkRemoveFunction remove_func,
11082 <tt/widget/, <tt/selection/, and <tt/target/ identify the requests
11083 this handler will manage. <tt/remove_func/, if not
11084 NULL, will be called when the signal handler is removed. This is
11085 useful, for instance, for interpreted languages which need to
11086 keep track of a reference count for <tt/data/.
11088 The callback function has the signature:
11091 typedef void (*GtkSelectionFunction)( GtkWidget *widget,
11092 GtkSelectionData *selection_data,
11097 The GtkSelectionData is the same as above, but this time, we're
11098 responsible for filling in the fields <tt/type/, <tt/format/,
11099 <tt/data/, and <tt/length/. (The <tt/format/ field is actually
11100 important here - the X server uses it to figure out whether the data
11101 needs to be byte-swapped or not. Usually it will be 8 - <em/i.e./ a
11102 character - or 32 - <em/i.e./ a. integer.) This is done by calling the
11106 void gtk_selection_data_set( GtkSelectionData *selection_data,
11113 This function takes care of properly making a copy of the data so that
11114 you don't have to worry about keeping it around. (You should not fill
11115 in the fields of the GtkSelectionData structure by hand.)
11117 When prompted by the user, you claim ownership of the selection by
11121 gint gtk_selection_owner_set( GtkWidget *widget,
11126 If another application claims ownership of the selection, you will
11127 receive a "selection_clear_event".
11129 As an example of supplying the selection, the following program adds
11130 selection functionality to a toggle button. When the toggle button is
11131 depressed, the program claims the primary selection. The only target
11132 supported (aside from certain targets like "TARGETS" supplied by GTK
11133 itself), is the "STRING" target. When this target is requested, a
11134 string representation of the time is returned.
11137 /* example-start selection setselection.c */
11139 #include <gtk/gtk.h>
11142 /* Callback when the user toggles the selection */
11144 selection_toggled (GtkWidget *widget, gint *have_selection)
11146 if (GTK_TOGGLE_BUTTON(widget)->active)
11148 *have_selection = gtk_selection_owner_set (widget,
11149 GDK_SELECTION_PRIMARY,
11151 /* if claiming the selection failed, we return the button to
11153 if (!*have_selection)
11154 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), FALSE);
11158 if (*have_selection)
11160 /* Before clearing the selection by setting the owner to NULL,
11161 we check if we are the actual owner */
11162 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
11163 gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
11165 *have_selection = FALSE;
11170 /* Called when another application claims the selection */
11172 selection_clear (GtkWidget *widget, GdkEventSelection *event,
11173 gint *have_selection)
11175 *have_selection = FALSE;
11176 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), FALSE);
11181 /* Supplies the current time as the selection. */
11183 selection_handle (GtkWidget *widget,
11184 GtkSelectionData *selection_data,
11188 time_t current_time;
11190 current_time = time (NULL);
11191 timestr = asctime (localtime(&current_time));
11192 /* When we return a single string, it should not be null terminated.
11193 That will be done for us */
11195 gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
11196 8, timestr, strlen(timestr));
11200 main (int argc, char *argv[])
11204 GtkWidget *selection_button;
11206 static int have_selection = FALSE;
11208 gtk_init (&argc, &argv);
11210 /* Create the toplevel window */
11212 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11213 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
11214 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
11216 gtk_signal_connect (GTK_OBJECT (window), "destroy",
11217 GTK_SIGNAL_FUNC (gtk_exit), NULL);
11219 /* Create a toggle button to act as the selection */
11221 selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
11222 gtk_container_add (GTK_CONTAINER (window), selection_button);
11223 gtk_widget_show (selection_button);
11225 gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
11226 GTK_SIGNAL_FUNC (selection_toggled), &have_selection);
11227 gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
11228 GTK_SIGNAL_FUNC (selection_clear), &have_selection);
11230 gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
11231 GDK_SELECTION_TYPE_STRING,
11232 selection_handle, NULL);
11234 gtk_widget_show (selection_button);
11235 gtk_widget_show (window);
11245 <!-- ***************************************************************** -->
11246 <sect>glib<label id="sec_glib">
11247 <!-- ***************************************************************** -->
11249 glib is a lower-level library that provides many useful definitions
11250 and functions available for use when creating GDK and GTK
11251 applications. These include definitions for basic types and their
11252 limits, standard macros, type conversions, byte order, memory
11253 allocation, warnings and assertions, message logging, timers, string
11254 utilities, hook functions, a lexical scanner, dynamic loading of
11255 modules, and automatic string completion. A number of data structures
11256 (and their related operations) are also defined, including memory
11257 chunks, doubly-linked lists, singly-linked lists, hash tables, strings
11258 (which can grow dynamically), string chunks (groups of strings),
11259 arrays (which can grow in size as elements are added), balanced binary
11260 trees, N-ary trees, quarks (a two-way association of a string and a
11261 unique integer identifier), keyed data lists (lists of data elements
11262 accessible by a string or integer id), relations and tuples (tables of
11263 data which can be indexed on any number of fields), and caches.
11265 A summary of some of glib's capabilities follows; not every function,
11266 data structure, or operation is covered here. For more complete
11267 information about the glib routines, see the glib documentation. One
11268 source of glib documentation is http://www.gtk.org/ <htmlurl
11269 url="http://www.gtk.org/" name="http://www.gtk.org/">.
11271 If you are using a language other than C, you should consult your
11272 language's binding documentation. In some cases your language may
11273 have equivalent functionality built-in, while in other cases it may
11276 <!-- ----------------------------------------------------------------- -->
11279 Definitions for the extremes of many of the standard types are:
11294 Also, the following typedefs. The ones left unspecified are dynamically set
11295 depending on the architecture. Remember to avoid counting on the size of a
11296 pointer if you want to be portable! E.g., a pointer on an Alpha is 8
11297 bytes, but 4 on Intel 80x86 family CPUs.
11306 unsigned char guchar;
11307 unsigned short gushort;
11308 unsigned long gulong;
11309 unsigned int guint;
11313 long double gldouble;
11325 <!-- ----------------------------------------------------------------- -->
11326 <sect1>Doubly Linked Lists
11328 The following functions are used to create, manage, and destroy
11329 standard doubly linked lists. Each element in the list contains a
11330 piece of data, together with pointers which link to the previous and
11331 next elements in the list. This enables easy movement in either
11332 direction through the list. The data item is of type "gpointer",
11333 which means the data can be a pointer to your real data or (through
11334 casting) a numeric value (but do not assume that int and gpointer have
11335 the same size!). These routines internally allocate list elements in
11336 blocks, which is more efficient than allocating elements individually.
11338 There is no function to specifically create a list. Instead, simply
11339 create a variable of type GList* and set its value to NULL; NULL is
11340 considered to be the empty list.
11342 To add elements to a list, use the g_list_append(), g_list_prepend(),
11343 g_list_insert(), or g_list_insert_sorted() routines. In all cases
11344 they accept a pointer to the beginning of the list, and return the
11345 (possibly changed) pointer to the beginning of the list. Thus, for
11346 all of the operations that add or remove elements, be sure to save the
11350 GList *g_list_append( GList *list,
11354 This adds a new element (with value <tt/data/) onto the end of the
11358 GList *g_list_prepend( GList *list,
11362 This adds a new element (with value <tt/data/) to the beginning of the
11366 GList *g_list_insert( GList *list,
11372 This inserts a new element (with value data) into the list at the
11373 given position. If position is 0, this is just like g_list_prepend();
11374 if position is less than 0, this is just like g_list_append().
11377 GList *g_list_remove( GList *list,
11381 This removes the element in the list with the value <tt/data/;
11382 if the element isn't there, the list is unchanged.
11385 void g_list_free( GList *list );
11388 This frees all of the memory used by a GList. If the list elements
11389 refer to dynamically-allocated memory, then they should be freed
11392 There are many other glib functions that support doubly linked lists;
11393 see the glib documentation for more information. Here are a few of
11394 the more useful functions' signatures:
11397 GList *g_list_remove_link( GList *list,
11400 GList *g_list_reverse( GList *list );
11402 GList *g_list_nth( GList *list,
11405 GList *g_list_find( GList *list,
11408 GList *g_list_last( GList *list );
11410 GList *g_list_first( GList *list );
11412 gint g_list_length( GList *list );
11414 void g_list_foreach( GList *list,
11416 gpointer user_data );
11419 <!-- ----------------------------------------------------------------- -->
11420 <sect1>Singly Linked Lists
11422 Many of the above functions for singly linked lists are identical to the
11423 above. Here is a list of some of their operations:
11426 GSList *g_slist_append( GSList *list,
11429 GSList *g_slist_prepend( GSList *list,
11432 GSList *g_slist_insert( GSList *list,
11436 GSList *g_slist_remove( GSList *list,
11439 GSList *g_slist_remove_link( GSList *list,
11442 GSList *g_slist_reverse( GSList *list );
11444 GSList *g_slist_nth( GSList *list,
11447 GSList *g_slist_find( GSList *list,
11450 GSList *g_slist_last( GSList *list );
11452 gint g_slist_length( GSList *list );
11454 void g_slist_foreach( GSList *list,
11456 gpointer user_data );
11460 <!-- ----------------------------------------------------------------- -->
11461 <sect1>Memory Management
11464 gpointer g_malloc( gulong size );
11467 This is a replacement for malloc(). You do not need to check the return
11468 value as it is done for you in this function. If the memory allocation
11469 fails for whatever reasons, your applications will be terminated.
11472 gpointer g_malloc0( gulong size );
11475 Same as above, but zeroes the memory before returning a pointer to it.
11478 gpointer g_realloc( gpointer mem,
11482 Relocates "size" bytes of memory starting at "mem". Obviously, the
11483 memory should have been previously allocated.
11486 void g_free( gpointer mem );
11489 Frees memory. Easy one. If <tt/mem/ is NULL it simply returns.
11492 void g_mem_profile( void );
11495 Dumps a profile of used memory, but requires that you add #define
11496 MEM_PROFILE to the top of glib/gmem.c and re-make and make install.
11499 void g_mem_check( gpointer mem );
11502 Checks that a memory location is valid. Requires you add #define
11503 MEM_CHECK to the top of gmem.c and re-make and make install.
11505 <!-- ----------------------------------------------------------------- -->
11508 Timer functions can be used to time operations (e.g. to see how much
11509 time has elapsed). First, you create a new timer with g_timer_new().
11510 You can then use g_timer_start() to start timing an operation,
11511 g_timer_stop() to stop timing an operation, and g_timer_elapsed() to
11512 determine the elapsed time.
11515 GTimer *g_timer_new( void );
11517 void g_timer_destroy( GTimer *timer );
11519 void g_timer_start( GTimer *timer );
11521 void g_timer_stop( GTimer *timer );
11523 void g_timer_reset( GTimer *timer );
11525 gdouble g_timer_elapsed( GTimer *timer,
11526 gulong *microseconds );
11529 <!-- ----------------------------------------------------------------- -->
11530 <sect1>String Handling
11532 glib defines a new type called a GString, which is similar to a
11533 standard C string but one that grows automatically. Its string data
11534 is null-terminated. What this gives you is protection from buffer
11535 overflow programming errors within your program. This is a very
11536 important feature, and hence I recommend that you make use of
11537 GStrings. GString itself has a simple public definition:
11542 gchar *str; /* Points to the string's current \0-terminated value. */
11543 gint len; /* Current length */
11547 As you might expect, there are a number of operations you can do with
11551 GString *g_string_new( gchar *init );
11554 This constructs a GString, copying the string value of <tt/init/
11555 into the GString and returning a pointer to it. NULL may be given as
11556 the argument for an initially empty GString.
11560 void g_string_free( GString *string,
11561 gint free_segment );
11564 This frees the memory for the given GString. If <tt/free_segment/ is
11565 TRUE, then this also frees its character data.
11569 GString *g_string_assign( GString *lval,
11570 const gchar *rval );
11573 This copies the characters from rval into lval, destroying the
11574 previous contents of lval. Note that lval will be lengthened as
11575 necessary to hold the string's contents, unlike the standard strcpy()
11578 The rest of these functions should be relatively obvious (the _c
11579 versions accept a character instead of a string):
11582 GString *g_string_truncate( GString *string,
11585 GString *g_string_append( GString *string,
11588 GString *g_string_append_c( GString *string,
11591 GString *g_string_prepend( GString *string,
11594 GString *g_string_prepend_c( GString *string,
11597 void g_string_sprintf( GString *string,
11601 void g_string_sprintfa ( GString *string,
11606 <!-- ----------------------------------------------------------------- -->
11607 <sect1>Utility and Error Functions
11610 gchar *g_strdup( const gchar *str );
11613 Replacement strdup function. Copies the original strings contents to
11614 newly allocated memory, and returns a pointer to it.
11617 gchar *g_strerror( gint errnum );
11620 I recommend using this for all error messages. It's much nicer, and more
11621 portable than perror() or others. The output is usually of the form:
11624 program name:function that failed:file or further description:strerror
11627 Here's an example of one such call used in our hello_world program:
11630 g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
11634 void g_error( gchar *format, ... );
11637 Prints an error message. The format is just like printf, but it
11638 prepends "** ERROR **: " to your message, and exits the program.
11639 Use only for fatal errors.
11642 void g_warning( gchar *format, ... );
11645 Same as above, but prepends "** WARNING **: ", and does not exit the
11649 void g_message( gchar *format, ... );
11652 Prints "message: " prepended to the string you pass in.
11655 void g_print( gchar *format, ... );
11658 Replacement for printf().
11660 And our last function:
11663 gchar *g_strsignal( gint signum );
11666 Prints out the name of the Unix system signal given the signal number.
11667 Useful in generic signal handling functions.
11669 All of the above are more or less just stolen from glib.h. If anyone cares
11670 to document any function, just send me an email!
11672 <!-- ***************************************************************** -->
11673 <sect>GTK's rc Files
11674 <!-- ***************************************************************** -->
11676 GTK has its own way of dealing with application defaults, by using rc
11677 files. These can be used to set the colors of just about any widget, and
11678 can also be used to tile pixmaps onto the background of some widgets.
11680 <!-- ----------------------------------------------------------------- -->
11681 <sect1>Functions For rc Files
11683 When your application starts, you should include a call to:
11686 void gtk_rc_parse( char *filename );
11689 Passing in the filename of your rc file. This will cause GTK to parse
11690 this file, and use the style settings for the widget types defined
11693 If you wish to have a special set of widgets that can take on a
11694 different style from others, or any other logical division of widgets,
11698 void gtk_widget_set_name( GtkWidget *widget,
11702 Passing your newly created widget as the first argument, and the name
11703 you wish to give it as the second. This will allow you to change the
11704 attributes of this widget by name through the rc file.
11706 If we use a call something like this:
11709 button = gtk_button_new_with_label ("Special Button");
11710 gtk_widget_set_name (button, "special button");
11713 Then this button is given the name "special button" and may be addressed by
11714 name in the rc file as "special button.GtkButton". [<--- Verify ME!]
11716 The example rc file below, sets the properties of the main window, and lets
11717 all children of that main window inherit the style described by the "main
11718 button" style. The code used in the application is:
11721 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11722 gtk_widget_set_name (window, "main window");
11725 And then the style is defined in the rc file using:
11728 widget "main window.*GtkButton*" style "main_button"
11731 Which sets all the GtkButton widgets in the "main window" to the
11732 "main_buttons" style as defined in the rc file.
11734 As you can see, this is a fairly powerful and flexible system. Use your
11735 imagination as to how best to take advantage of this.
11737 <!-- ----------------------------------------------------------------- -->
11738 <sect1>GTK's rc File Format
11740 The format of the GTK file is illustrated in the example below. This is
11741 the testgtkrc file from the GTK distribution, but I've added a
11742 few comments and things. You may wish to include this explanation
11743 your application to allow the user to fine tune his application.
11745 There are several directives to change the attributes of a widget.
11748 <item>fg - Sets the foreground color of a widget.
11749 <item>bg - Sets the background color of a widget.
11750 <item>bg_pixmap - Sets the background of a widget to a tiled pixmap.
11751 <item>font - Sets the font to be used with the given widget.
11754 In addition to this, there are several states a widget can be in, and you
11755 can set different colors, pixmaps and fonts for each state. These states are:
11758 <item>NORMAL - The normal state of a widget, without the mouse over top of
11759 it, and not being pressed etc.
11760 <item>PRELIGHT - When the mouse is over top of the widget, colors defined
11761 using this state will be in effect.
11762 <item>ACTIVE - When the widget is pressed or clicked it will be active, and
11763 the attributes assigned by this tag will be in effect.
11764 <item>INSENSITIVE - When a widget is set insensitive, and cannot be
11765 activated, it will take these attributes.
11766 <item>SELECTED - When an object is selected, it takes these attributes.
11769 When using the "fg" and "bg" keywords to set the colors of widgets, the
11773 fg[<STATE>] = { Red, Green, Blue }
11776 Where STATE is one of the above states (PRELIGHT, ACTIVE etc), and the Red,
11777 Green and Blue are values in the range of 0 - 1.0, { 1.0, 1.0, 1.0 } being
11778 white. They must be in float form, or they will register as 0, so a straight
11779 "1" will not work, it must be "1.0". A straight "0" is fine because it
11780 doesn't matter if it's not recognized. Unrecognized values are set to 0.
11782 bg_pixmap is very similar to the above, except the colors are replaced by a
11785 pixmap_path is a list of paths separated by ":"'s. These paths will be
11786 searched for any pixmap you specify.
11788 The font directive is simply:
11790 font = "<font name>"
11793 Where the only hard part is figuring out the font string. Using xfontsel or
11794 similar utility should help.
11796 The "widget_class" sets the style of a class of widgets. These classes are
11797 listed in the widget overview on the class hierarchy.
11799 The "widget" directive sets a specifically named set of widgets to a
11800 given style, overriding any style set for the given widget class.
11801 These widgets are registered inside the application using the
11802 gtk_widget_set_name() call. This allows you to specify the attributes of a
11803 widget on a per widget basis, rather than setting the attributes of an
11804 entire widget class. I urge you to document any of these special widgets so
11805 users may customize them.
11807 When the keyword <tt>parent</> is used as an attribute, the widget will take on
11808 the attributes of its parent in the application.
11810 When defining a style, you may assign the attributes of a previously defined
11811 style to this new one.
11814 style "main_button" = "button"
11816 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
11817 bg[PRELIGHT] = { 0.75, 0, 0 }
11821 This example takes the "button" style, and creates a new "main_button" style
11822 simply by changing the font and prelight background color of the "button"
11825 Of course, many of these attributes don't apply to all widgets. It's a
11826 simple matter of common sense really. Anything that could apply, should.
11828 <!-- ----------------------------------------------------------------- -->
11829 <sect1>Example rc file
11833 # pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
11835 pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
11837 # style <name> [= <name>]
11842 # widget <widget_set> style <style_name>
11843 # widget_class <widget_class_set> style <style_name>
11846 # Here is a list of all the possible states. Note that some do not apply to
11849 # NORMAL - The normal state of a widget, without the mouse over top of
11850 # it, and not being pressed etc.
11852 # PRELIGHT - When the mouse is over top of the widget, colors defined
11853 # using this state will be in effect.
11855 # ACTIVE - When the widget is pressed or clicked it will be active, and
11856 # the attributes assigned by this tag will be in effect.
11858 # INSENSITIVE - When a widget is set insensitive, and cannot be
11859 # activated, it will take these attributes.
11861 # SELECTED - When an object is selected, it takes these attributes.
11863 # Given these states, we can set the attributes of the widgets in each of
11864 # these states using the following directives.
11866 # fg - Sets the foreground color of a widget.
11867 # fg - Sets the background color of a widget.
11868 # bg_pixmap - Sets the background of a widget to a tiled pixmap.
11869 # font - Sets the font to be used with the given widget.
11872 # This sets a style called "button". The name is not really important, as
11873 # it is assigned to the actual widgets at the bottom of the file.
11877 #This sets the padding around the window to the pixmap specified.
11878 #bg_pixmap[<STATE>] = "<pixmap filename>"
11879 bg_pixmap[NORMAL] = "warning.xpm"
11884 #Sets the foreground color (font color) to red when in the "NORMAL"
11887 fg[NORMAL] = { 1.0, 0, 0 }
11889 #Sets the background pixmap of this widget to that of its parent.
11890 bg_pixmap[NORMAL] = "<parent>"
11895 # This shows all the possible states for a button. The only one that
11896 # doesn't apply is the SELECTED state.
11898 fg[PRELIGHT] = { 0, 1.0, 1.0 }
11899 bg[PRELIGHT] = { 0, 0, 1.0 }
11900 bg[ACTIVE] = { 1.0, 0, 0 }
11901 fg[ACTIVE] = { 0, 1.0, 0 }
11902 bg[NORMAL] = { 1.0, 1.0, 0 }
11903 fg[NORMAL] = { .99, 0, .99 }
11904 bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
11905 fg[INSENSITIVE] = { 1.0, 0, 1.0 }
11908 # In this example, we inherit the attributes of the "button" style and then
11909 # override the font and background color when prelit to create a new
11910 # "main_button" style.
11912 style "main_button" = "button"
11914 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
11915 bg[PRELIGHT] = { 0.75, 0, 0 }
11918 style "toggle_button" = "button"
11920 fg[NORMAL] = { 1.0, 0, 0 }
11921 fg[ACTIVE] = { 1.0, 0, 0 }
11923 # This sets the background pixmap of the toggle_button to that of its
11924 # parent widget (as defined in the application).
11925 bg_pixmap[NORMAL] = "<parent>"
11930 bg_pixmap[NORMAL] = "marble.xpm"
11931 fg[NORMAL] = { 1.0, 1.0, 1.0 }
11936 font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
11939 # pixmap_path "~/.pixmaps"
11941 # These set the widget types to use the styles defined above.
11942 # The widget types are listed in the class hierarchy, but could probably be
11943 # just listed in this document for the users reference.
11945 widget_class "GtkWindow" style "window"
11946 widget_class "GtkDialog" style "window"
11947 widget_class "GtkFileSelection" style "window"
11948 widget_class "*Gtk*Scale" style "scale"
11949 widget_class "*GtkCheckButton*" style "toggle_button"
11950 widget_class "*GtkRadioButton*" style "toggle_button"
11951 widget_class "*GtkButton*" style "button"
11952 widget_class "*Ruler" style "ruler"
11953 widget_class "*GtkText" style "text"
11955 # This sets all the buttons that are children of the "main window" to
11956 # the main_button style. These must be documented to be taken advantage of.
11957 widget "main window.*GtkButton*" style "main_button"
11960 <!-- ***************************************************************** -->
11961 <sect>Writing Your Own Widgets
11962 <!-- ***************************************************************** -->
11964 <!-- ----------------------------------------------------------------- -->
11967 Although the GTK distribution comes with many types of widgets that
11968 should cover most basic needs, there may come a time when you need to
11969 create your own new widget type. Since GTK uses widget inheritance
11970 extensively, and there is already a widget that is close to what you want,
11971 it is often possible to make a useful new widget type in
11972 just a few lines of code. But before starting work on a new widget, check
11973 around first to make sure that someone has not already written
11974 it. This will prevent duplication of effort and keep the number of
11975 GTK widgets out there to a minimum, which will help keep both the code
11976 and the interface of different applications consistent. As a flip side
11977 to this, once you finish your widget, announce it to the world so
11978 other people can benefit. The best place to do this is probably the
11981 Complete sources for the example widgets are available at the place you
11982 got this tutorial, or from:
11984 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
11985 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
11988 <!-- ----------------------------------------------------------------- -->
11989 <sect1> The Anatomy Of A Widget
11991 In order to create a new widget, it is important to have an
11992 understanding of how GTK objects work. This section is just meant as a
11993 brief overview. See the reference documentation for the details.
11995 GTK widgets are implemented in an object oriented fashion. However,
11996 they are implemented in standard C. This greatly improves portability
11997 and stability over using current generation C++ compilers; however,
11998 it does mean that the widget writer has to pay attention to some of
11999 the implementation details. The information common to all instances of
12000 one class of widgets (e.g., to all Button widgets) is stored in the
12001 <em>class structure</em>. There is only one copy of this in
12002 which is stored information about the class's signals
12003 (which act like virtual functions in C). To support inheritance, the
12004 first field in the class structure must be a copy of the parent's
12005 class structure. The declaration of the class structure of GtkButtton
12009 struct _GtkButtonClass
12011 GtkContainerClass parent_class;
12013 void (* pressed) (GtkButton *button);
12014 void (* released) (GtkButton *button);
12015 void (* clicked) (GtkButton *button);
12016 void (* enter) (GtkButton *button);
12017 void (* leave) (GtkButton *button);
12021 When a button is treated as a container (for instance, when it is
12022 resized), its class structure can be cast to GtkContainerClass, and
12023 the relevant fields used to handle the signals.
12025 There is also a structure for each widget that is created on a
12026 per-instance basis. This structure has fields to store information that
12027 is different for each instance of the widget. We'll call this
12028 structure the <em>object structure</em>. For the Button class, it looks
12034 GtkContainer container;
12038 guint in_button : 1;
12039 guint button_down : 1;
12043 Note that, similar to the class structure, the first field is the
12044 object structure of the parent class, so that this structure can be
12045 cast to the parent class's object structure as needed.
12047 <!-- ----------------------------------------------------------------- -->
12048 <sect1> Creating a Composite widget
12050 <!-- ----------------------------------------------------------------- -->
12051 <sect2> Introduction
12053 One type of widget that you may be interested in creating is a
12054 widget that is merely an aggregate of other GTK widgets. This type of
12055 widget does nothing that couldn't be done without creating new
12056 widgets, but provides a convenient way of packaging user interface
12057 elements for reuse. The FileSelection and ColorSelection widgets in
12058 the standard distribution are examples of this type of widget.
12060 The example widget that we'll create in this section is the Tictactoe
12061 widget, a 3x3 array of toggle buttons which triggers a signal when all
12062 three buttons in a row, column, or on one of the diagonals are
12065 <!-- ----------------------------------------------------------------- -->
12066 <sect2> Choosing a parent class
12068 The parent class for a composite widget is typically the container
12069 class that holds all of the elements of the composite widget. For
12070 example, the parent class of the FileSelection widget is the
12071 Dialog class. Since our buttons will be arranged in a table, it
12072 might seem natural to make our parent class the GtkTable
12073 class. Unfortunately, this turns out not to work. The creation of a
12074 widget is divided among two functions - a <tt/WIDGETNAME_new()/
12075 function that the user calls, and a <tt/WIDGETNAME_init()/ function
12076 which does the basic work of initializing the widget which is
12077 independent of the arguments passed to the <tt/_new()/
12078 function. Descendent widgets only call the <tt/_init/ function of
12079 their parent widget. But this division of labor doesn't work well for
12080 tables, which when created, need to know the number of rows and
12081 columns in the table. Unless we want to duplicate most of the
12082 functionality of <tt/gtk_table_new()/ in our Tictactoe widget, we had
12083 best avoid deriving it from GtkTable. For that reason, we derive it
12084 from GtkVBox instead, and stick our table inside the VBox.
12086 <!-- ----------------------------------------------------------------- -->
12087 <sect2> The header file
12089 Each widget class has a header file which declares the object and
12090 class structures for that widget, along with public functions.
12091 A couple of features are worth pointing out. To prevent duplicate
12092 definitions, we wrap the entire header file in:
12095 #ifndef __TICTACTOE_H__
12096 #define __TICTACTOE_H__
12100 #endif /* __TICTACTOE_H__ */
12103 And to keep C++ programs that include the header file happy, in:
12108 #endif /* __cplusplus */
12114 #endif /* __cplusplus */
12117 Along with the functions and structures, we declare three standard
12118 macros in our header file, <tt/TICTACTOE(obj)/,
12119 <tt/TICTACTOE_CLASS(klass)/, and <tt/IS_TICTACTOE(obj)/, which cast a
12120 pointer into a pointer to the object or class structure, and check
12121 if an object is a Tictactoe widget respectively.
12123 Here is the complete header file:
12128 #ifndef __TICTACTOE_H__
12129 #define __TICTACTOE_H__
12131 #include <gdk/gdk.h>
12132 #include <gtk/gtkvbox.h>
12136 #endif /* __cplusplus */
12138 #define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
12139 #define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
12140 #define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
12143 typedef struct _Tictactoe Tictactoe;
12144 typedef struct _TictactoeClass TictactoeClass;
12150 GtkWidget *buttons[3][3];
12153 struct _TictactoeClass
12155 GtkVBoxClass parent_class;
12157 void (* tictactoe) (Tictactoe *ttt);
12160 guint tictactoe_get_type (void);
12161 GtkWidget* tictactoe_new (void);
12162 void tictactoe_clear (Tictactoe *ttt);
12166 #endif /* __cplusplus */
12168 #endif /* __TICTACTOE_H__ */
12172 <!-- ----------------------------------------------------------------- -->
12173 <sect2> The <tt/_get_type()/ function.
12175 We now continue on to the implementation of our widget. A core
12176 function for every widget is the function
12177 <tt/WIDGETNAME_get_type()/. This function, when first called, tells
12178 GTK about the widget class, and gets an ID that uniquely identifies
12179 the widget class. Upon subsequent calls, it just returns the ID.
12183 tictactoe_get_type ()
12185 static guint ttt_type = 0;
12189 GtkTypeInfo ttt_info =
12192 sizeof (Tictactoe),
12193 sizeof (TictactoeClass),
12194 (GtkClassInitFunc) tictactoe_class_init,
12195 (GtkObjectInitFunc) tictactoe_init,
12196 (GtkArgSetFunc) NULL,
12197 (GtkArgGetFunc) NULL
12200 ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
12207 The GtkTypeInfo structure has the following definition:
12210 struct _GtkTypeInfo
12215 GtkClassInitFunc class_init_func;
12216 GtkObjectInitFunc object_init_func;
12217 GtkArgSetFunc arg_set_func;
12218 GtkArgGetFunc arg_get_func;
12222 The fields of this structure are pretty self-explanatory. We'll ignore
12223 the <tt/arg_set_func/ and <tt/arg_get_func/ fields here: they have an important,
12225 unimplemented, role in allowing widget options to be conveniently set
12226 from interpreted languages. Once GTK has a correctly filled in copy of
12227 this structure, it knows how to create objects of a particular widget
12230 <!-- ----------------------------------------------------------------- -->
12231 <sect2> The <tt/_class_init()/ function
12233 The <tt/WIDGETNAME_class_init()/ function initializes the fields of
12234 the widget's class structure, and sets up any signals for the
12235 class. For our Tictactoe widget it looks like:
12244 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
12247 tictactoe_class_init (TictactoeClass *class)
12249 GtkObjectClass *object_class;
12251 object_class = (GtkObjectClass*) class;
12253 tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
12255 object_class->type,
12256 GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
12257 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
12260 gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
12262 class->tictactoe = NULL;
12266 Our widget has just one signal, the <tt/tictactoe/ signal that is
12267 invoked when a row, column, or diagonal is completely filled in. Not
12268 every composite widget needs signals, so if you are reading this for
12269 the first time, you may want to skip to the next section now, as
12270 things are going to get a bit complicated.
12275 gint gtk_signal_new( const gchar *name,
12276 GtkSignalRunType run_type,
12277 GtkType object_type,
12278 gint function_offset,
12279 GtkSignalMarshaller marshaller,
12280 GtkType return_val,
12285 Creates a new signal. The parameters are:
12288 <item> <tt/name/: The name of the signal.
12289 <item> <tt/run_type/: Whether the default handler runs before or after
12290 user handlers. Usually this will be <tt/GTK_RUN_FIRST/, or <tt/GTK_RUN_LAST/,
12291 although there are other possibilities.
12292 <item> <tt/object_type/: The ID of the object that this signal applies
12293 to. (It will also apply to that objects descendents)
12294 <item> <tt/function_offset/: The offset within the class structure of
12295 a pointer to the default handler.
12296 <item> <tt/marshaller/: A function that is used to invoke the signal
12297 handler. For signal handlers that have no arguments other than the
12298 object that emitted the signal and user data, we can use the
12299 pre-supplied marshaller function <tt/gtk_signal_default_marshaller/.
12300 <item> <tt/return_val/: The type of the return val.
12301 <item> <tt/nparams/: The number of parameters of the signal handler
12302 (other than the two default ones mentioned above)
12303 <item> <tt/.../: The types of the parameters.
12306 When specifying types, the <tt/GtkType/ enumeration is used:
12331 /* it'd be great if the next two could be removed eventually */
12333 GTK_TYPE_C_CALLBACK,
12337 } GtkFundamentalType;
12340 <tt/gtk_signal_new()/ returns a unique integer identifier for the
12341 signal, that we store in the <tt/tictactoe_signals/ array, which we
12342 index using an enumeration. (Conventionally, the enumeration elements
12343 are the signal name, uppercased, but here there would be a conflict
12344 with the <tt/TICTACTOE()/ macro, so we called it <tt/TICTACTOE_SIGNAL/
12347 After creating our signals, we need to tell GTK to associate our
12348 signals with the Tictactoe class. We do that by calling
12349 <tt/gtk_object_class_add_signals()/. We then set the pointer which
12350 points to the default handler for the `tictactoe' signal to NULL,
12351 indicating that there is no default action.
12353 <!-- ----------------------------------------------------------------- -->
12354 <sect2> The <tt/_init()/ function.
12356 Each widget class also needs a function to initialize the object
12357 structure. Usually, this function has the fairly limited role of
12358 setting the fields of the structure to default values. For composite
12359 widgets, however, this function also creates the component widgets.
12363 tictactoe_init (Tictactoe *ttt)
12368 table = gtk_table_new (3, 3, TRUE);
12369 gtk_container_add (GTK_CONTAINER(ttt), table);
12370 gtk_widget_show (table);
12375 ttt->buttons[i][j] = gtk_toggle_button_new ();
12376 gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
12378 gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
12379 GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
12380 gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
12381 gtk_widget_show (ttt->buttons[i][j]);
12386 <!-- ----------------------------------------------------------------- -->
12387 <sect2> And the rest...
12389 There is one more function that every widget (except for base widget
12390 types like GtkBin that cannot be instantiated) needs to have - the
12391 function that the user calls to create an object of that type. This is
12392 conventionally called <tt/WIDGETNAME_new()/. In some
12393 widgets, though not for the Tictactoe widgets, this function takes
12394 arguments, and does some setup based on the arguments. The other two
12395 functions are specific to the Tictactoe widget.
12397 <tt/tictactoe_clear()/ is a public function that resets all the
12398 buttons in the widget to the up position. Note the use of
12399 <tt/gtk_signal_handler_block_by_data()/ to keep our signal handler for
12400 button toggles from being triggered unnecessarily.
12402 <tt/tictactoe_toggle()/ is the signal handler that is invoked when the
12403 user clicks on a button. It checks to see if there are any winning
12404 combinations that involve the toggled button, and if so, emits
12405 the "tictactoe" signal.
12411 return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
12415 tictactoe_clear (Tictactoe *ttt)
12422 gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
12423 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
12425 gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
12430 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
12434 static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
12435 { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
12436 { 0, 1, 2 }, { 0, 1, 2 } };
12437 static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
12438 { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
12439 { 0, 1, 2 }, { 2, 1, 0 } };
12441 int success, found;
12443 for (k=0; k<8; k++)
12450 success = success &&
12451 GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
12453 ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
12456 if (success && found)
12458 gtk_signal_emit (GTK_OBJECT (ttt),
12459 tictactoe_signals[TICTACTOE_SIGNAL]);
12466 And finally, an example program using our Tictactoe widget:
12469 #include <gtk/gtk.h>
12470 #include "tictactoe.h"
12472 /* Invoked when a row, column or diagonal is completed */
12474 win (GtkWidget *widget, gpointer data)
12476 g_print ("Yay!\n");
12477 tictactoe_clear (TICTACTOE (widget));
12481 main (int argc, char *argv[])
12486 gtk_init (&argc, &argv);
12488 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
12490 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
12492 gtk_signal_connect (GTK_OBJECT (window), "destroy",
12493 GTK_SIGNAL_FUNC (gtk_exit), NULL);
12495 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
12497 /* Create a new Tictactoe widget */
12498 ttt = tictactoe_new ();
12499 gtk_container_add (GTK_CONTAINER (window), ttt);
12500 gtk_widget_show (ttt);
12502 /* And attach to its "tictactoe" signal */
12503 gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
12504 GTK_SIGNAL_FUNC (win), NULL);
12506 gtk_widget_show (window);
12515 <!-- ----------------------------------------------------------------- -->
12516 <sect1> Creating a widget from scratch.
12518 <!-- ----------------------------------------------------------------- -->
12519 <sect2> Introduction
12521 In this section, we'll learn more about how widgets display themselves
12522 on the screen and interact with events. As an example of this, we'll
12523 create an analog dial widget with a pointer that the user can drag to
12526 <!-- ----------------------------------------------------------------- -->
12527 <sect2> Displaying a widget on the screen
12529 There are several steps that are involved in displaying on the screen.
12530 After the widget is created with a call to <tt/WIDGETNAME_new()/,
12531 several more functions are needed:
12534 <item> <tt/WIDGETNAME_realize()/ is responsible for creating an X
12535 window for the widget if it has one.
12536 <item> <tt/WIDGETNAME_map()/ is invoked after the user calls
12537 <tt/gtk_widget_show()/. It is responsible for making sure the widget
12538 is actually drawn on the screen (<em/mapped/). For a container class,
12539 it must also make calls to <tt/map()/> functions of any child widgets.
12540 <item> <tt/WIDGETNAME_draw()/ is invoked when <tt/gtk_widget_draw()/
12541 is called for the widget or one of its ancestors. It makes the actual
12542 calls to the drawing functions to draw the widget on the screen. For
12543 container widgets, this function must make calls to
12544 <tt/gtk_widget_draw()/ for its child widgets.
12545 <item> <tt/WIDGETNAME_expose()/ is a handler for expose events for the
12546 widget. It makes the necessary calls to the drawing functions to draw
12547 the exposed portion on the screen. For container widgets, this
12548 function must generate expose events for its child widgets which don't
12549 have their own windows. (If they have their own windows, then X will
12550 generate the necessary expose events)
12553 You might notice that the last two functions are quite similar - each
12554 is responsible for drawing the widget on the screen. In fact many
12555 types of widgets don't really care about the difference between the
12556 two. The default <tt/draw()/ function in the widget class simply
12557 generates a synthetic expose event for the redrawn area. However, some
12558 types of widgets can save work by distinguishing between the two
12559 functions. For instance, if a widget has multiple X windows, then
12560 since expose events identify the exposed window, it can redraw only
12561 the affected window, which is not possible for calls to <tt/draw()/.
12563 Container widgets, even if they don't care about the difference for
12564 themselves, can't simply use the default <tt/draw()/ function because
12565 their child widgets might care about the difference. However,
12566 it would be wasteful to duplicate the drawing code between the two
12567 functions. The convention is that such widgets have a function called
12568 <tt/WIDGETNAME_paint()/ that does the actual work of drawing the
12569 widget, that is then called by the <tt/draw()/ and <tt/expose()/
12572 In our example approach, since the dial widget is not a container
12573 widget, and only has a single window, we can take the simplest
12574 approach and use the default <tt/draw()/ function and only implement
12575 an <tt/expose()/ function.
12577 <!-- ----------------------------------------------------------------- -->
12578 <sect2> The origins of the Dial Widget
12580 Just as all land animals are just variants on the first amphibian that
12581 crawled up out of the mud, Gtk widgets tend to start off as variants
12582 of some other, previously written widget. Thus, although this section
12583 is entitled `Creating a Widget from Scratch', the Dial widget really
12584 began with the source code for the Range widget. This was picked as a
12585 starting point because it would be nice if our Dial had the same
12586 interface as the Scale widgets which are just specialized descendents
12587 of the Range widget. So, though the source code is presented below in
12588 finished form, it should not be implied that it was written, <em>deus
12589 ex machina</em> in this fashion. Also, if you aren't yet familiar with
12590 how scale widgets work from the application writer's point of view, it
12591 would be a good idea to look them over before continuing.
12593 <!-- ----------------------------------------------------------------- -->
12596 Quite a bit of our widget should look pretty familiar from the
12597 Tictactoe widget. First, we have a header file:
12600 /* GTK - The GIMP Toolkit
12601 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
12603 * This library is free software; you can redistribute it and/or
12604 * modify it under the terms of the GNU Library General Public
12605 * License as published by the Free Software Foundation; either
12606 * version 2 of the License, or (at your option) any later version.
12608 * This library is distributed in the hope that it will be useful,
12609 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12610 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12611 * Library General Public License for more details.
12613 * You should have received a copy of the GNU Library General Public
12614 * License along with this library; if not, write to the Free
12615 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
12618 #ifndef __GTK_DIAL_H__
12619 #define __GTK_DIAL_H__
12621 #include <gdk/gdk.h>
12622 #include <gtk/gtkadjustment.h>
12623 #include <gtk/gtkwidget.h>
12628 #endif /* __cplusplus */
12631 #define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
12632 #define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
12633 #define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
12636 typedef struct _GtkDial GtkDial;
12637 typedef struct _GtkDialClass GtkDialClass;
12643 /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
12646 /* Button currently pressed or 0 if none */
12649 /* Dimensions of dial components */
12651 gint pointer_width;
12653 /* ID of update timer, or 0 if none */
12656 /* Current angle */
12659 /* Old values from adjustment stored so we know when something changes */
12664 /* The adjustment object that stores the data for this dial */
12665 GtkAdjustment *adjustment;
12668 struct _GtkDialClass
12670 GtkWidgetClass parent_class;
12674 GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
12675 guint gtk_dial_get_type (void);
12676 GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
12677 void gtk_dial_set_update_policy (GtkDial *dial,
12678 GtkUpdateType policy);
12680 void gtk_dial_set_adjustment (GtkDial *dial,
12681 GtkAdjustment *adjustment);
12684 #endif /* __cplusplus */
12687 #endif /* __GTK_DIAL_H__ */
12690 Since there is quite a bit more going on in this widget, than the last
12691 one, we have more fields in the data structure, but otherwise things
12692 are pretty similar.
12694 Next, after including header files, and declaring a few constants,
12695 we have some functions to provide information about the widget
12701 #include <gtk/gtkmain.h>
12702 #include <gtk/gtksignal.h>
12704 #include "gtkdial.h"
12706 #define SCROLL_DELAY_LENGTH 300
12707 #define DIAL_DEFAULT_SIZE 100
12709 /* Forward declarations */
12711 [ omitted to save space ]
12715 static GtkWidgetClass *parent_class = NULL;
12718 gtk_dial_get_type ()
12720 static guint dial_type = 0;
12724 GtkTypeInfo dial_info =
12728 sizeof (GtkDialClass),
12729 (GtkClassInitFunc) gtk_dial_class_init,
12730 (GtkObjectInitFunc) gtk_dial_init,
12731 (GtkArgSetFunc) NULL,
12732 (GtkArgGetFunc) NULL,
12735 dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info);
12742 gtk_dial_class_init (GtkDialClass *class)
12744 GtkObjectClass *object_class;
12745 GtkWidgetClass *widget_class;
12747 object_class = (GtkObjectClass*) class;
12748 widget_class = (GtkWidgetClass*) class;
12750 parent_class = gtk_type_class (gtk_widget_get_type ());
12752 object_class->destroy = gtk_dial_destroy;
12754 widget_class->realize = gtk_dial_realize;
12755 widget_class->expose_event = gtk_dial_expose;
12756 widget_class->size_request = gtk_dial_size_request;
12757 widget_class->size_allocate = gtk_dial_size_allocate;
12758 widget_class->button_press_event = gtk_dial_button_press;
12759 widget_class->button_release_event = gtk_dial_button_release;
12760 widget_class->motion_notify_event = gtk_dial_motion_notify;
12764 gtk_dial_init (GtkDial *dial)
12767 dial->policy = GTK_UPDATE_CONTINUOUS;
12770 dial->pointer_width = 0;
12772 dial->old_value = 0.0;
12773 dial->old_lower = 0.0;
12774 dial->old_upper = 0.0;
12775 dial->adjustment = NULL;
12779 gtk_dial_new (GtkAdjustment *adjustment)
12783 dial = gtk_type_new (gtk_dial_get_type ());
12786 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
12788 gtk_dial_set_adjustment (dial, adjustment);
12790 return GTK_WIDGET (dial);
12794 gtk_dial_destroy (GtkObject *object)
12798 g_return_if_fail (object != NULL);
12799 g_return_if_fail (GTK_IS_DIAL (object));
12801 dial = GTK_DIAL (object);
12803 if (dial->adjustment)
12804 gtk_object_unref (GTK_OBJECT (dial->adjustment));
12806 if (GTK_OBJECT_CLASS (parent_class)->destroy)
12807 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
12811 Note that this <tt/init()/ function does less than for the Tictactoe
12812 widget, since this is not a composite widget, and the <tt/new()/
12813 function does more, since it now has an argument. Also, note that when
12814 we store a pointer to the Adjustment object, we increment its
12815 reference count, (and correspondingly decrement when we no longer use
12816 it) so that GTK can keep track of when it can be safely destroyed.
12819 Also, there are a few function to manipulate the widget's options:
12823 gtk_dial_get_adjustment (GtkDial *dial)
12825 g_return_val_if_fail (dial != NULL, NULL);
12826 g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
12828 return dial->adjustment;
12832 gtk_dial_set_update_policy (GtkDial *dial,
12833 GtkUpdateType policy)
12835 g_return_if_fail (dial != NULL);
12836 g_return_if_fail (GTK_IS_DIAL (dial));
12838 dial->policy = policy;
12842 gtk_dial_set_adjustment (GtkDial *dial,
12843 GtkAdjustment *adjustment)
12845 g_return_if_fail (dial != NULL);
12846 g_return_if_fail (GTK_IS_DIAL (dial));
12848 if (dial->adjustment)
12850 gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
12851 gtk_object_unref (GTK_OBJECT (dial->adjustment));
12854 dial->adjustment = adjustment;
12855 gtk_object_ref (GTK_OBJECT (dial->adjustment));
12857 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
12858 (GtkSignalFunc) gtk_dial_adjustment_changed,
12860 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
12861 (GtkSignalFunc) gtk_dial_adjustment_value_changed,
12864 dial->old_value = adjustment->value;
12865 dial->old_lower = adjustment->lower;
12866 dial->old_upper = adjustment->upper;
12868 gtk_dial_update (dial);
12872 <sect2> <tt/gtk_dial_realize()/
12875 Now we come to some new types of functions. First, we have a function
12876 that does the work of creating the X window. Notice that a mask is
12877 passed to the function <tt/gdk_window_new()/ which specifies which fields of
12878 the GdkWindowAttr structure actually have data in them (the remaining
12879 fields will be given default values). Also worth noting is the way the
12880 event mask of the widget is created. We call
12881 <tt/gtk_widget_get_events()/ to retrieve the event mask that the user
12882 has specified for this widget (with <tt/gtk_widget_set_events()/, and
12883 add the events that we are interested in ourselves.
12886 After creating the window, we set its style and background, and put a
12887 pointer to the widget in the user data field of the GdkWindow. This
12888 last step allows GTK to dispatch events for this window to the correct
12893 gtk_dial_realize (GtkWidget *widget)
12896 GdkWindowAttr attributes;
12897 gint attributes_mask;
12899 g_return_if_fail (widget != NULL);
12900 g_return_if_fail (GTK_IS_DIAL (widget));
12902 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
12903 dial = GTK_DIAL (widget);
12905 attributes.x = widget->allocation.x;
12906 attributes.y = widget->allocation.y;
12907 attributes.width = widget->allocation.width;
12908 attributes.height = widget->allocation.height;
12909 attributes.wclass = GDK_INPUT_OUTPUT;
12910 attributes.window_type = GDK_WINDOW_CHILD;
12911 attributes.event_mask = gtk_widget_get_events (widget) |
12912 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
12913 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
12914 GDK_POINTER_MOTION_HINT_MASK;
12915 attributes.visual = gtk_widget_get_visual (widget);
12916 attributes.colormap = gtk_widget_get_colormap (widget);
12918 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
12919 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
12921 widget->style = gtk_style_attach (widget->style, widget->window);
12923 gdk_window_set_user_data (widget->window, widget);
12925 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
12929 <sect2> Size negotiation
12932 Before the first time that the window containing a widget is
12933 displayed, and whenever the layout of the window changes, GTK asks
12934 each child widget for its desired size. This request is handled by the
12935 function, <tt/gtk_dial_size_request()/. Since our widget isn't a
12936 container widget, and has no real constraints on its size, we just
12937 return a reasonable default value.
12941 gtk_dial_size_request (GtkWidget *widget,
12942 GtkRequisition *requisition)
12944 requisition->width = DIAL_DEFAULT_SIZE;
12945 requisition->height = DIAL_DEFAULT_SIZE;
12950 After all the widgets have requested an ideal size, the layout of the
12951 window is computed and each child widget is notified of its actual
12952 size. Usually, this will at least as large as the requested size, but
12953 if for instance, the user has resized the window, it may occasionally
12954 be smaller than the requested size. The size notification is handled
12955 by the function <tt/gtk_dial_size_allocate()/. Notice that as well as
12956 computing the sizes of some component pieces for future use, this
12957 routine also does the grunt work of moving the widgets X window into
12958 the new position and size.
12962 gtk_dial_size_allocate (GtkWidget *widget,
12963 GtkAllocation *allocation)
12967 g_return_if_fail (widget != NULL);
12968 g_return_if_fail (GTK_IS_DIAL (widget));
12969 g_return_if_fail (allocation != NULL);
12971 widget->allocation = *allocation;
12972 if (GTK_WIDGET_REALIZED (widget))
12974 dial = GTK_DIAL (widget);
12976 gdk_window_move_resize (widget->window,
12977 allocation->x, allocation->y,
12978 allocation->width, allocation->height);
12980 dial->radius = MAX(allocation->width,allocation->height) * 0.45;
12981 dial->pointer_width = dial->radius / 5;
12986 <!-- ----------------------------------------------------------------- -->
12987 <sect2> <tt/gtk_dial_expose()/
12990 As mentioned above, all the drawing of this widget is done in the
12991 handler for expose events. There's not much to remark on here except
12992 the use of the function <tt/gtk_draw_polygon/ to draw the pointer with
12993 three dimensional shading according to the colors stored in the
12998 gtk_dial_expose (GtkWidget *widget,
12999 GdkEventExpose *event)
13002 GdkPoint points[3];
13009 g_return_val_if_fail (widget != NULL, FALSE);
13010 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13011 g_return_val_if_fail (event != NULL, FALSE);
13013 if (event->count > 0)
13016 dial = GTK_DIAL (widget);
13018 gdk_window_clear_area (widget->window,
13020 widget->allocation.width,
13021 widget->allocation.height);
13023 xc = widget->allocation.width/2;
13024 yc = widget->allocation.height/2;
13028 for (i=0; i<25; i++)
13030 theta = (i*M_PI/18. - M_PI/6.);
13034 tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
13036 gdk_draw_line (widget->window,
13037 widget->style->fg_gc[widget->state],
13038 xc + c*(dial->radius - tick_length),
13039 yc - s*(dial->radius - tick_length),
13040 xc + c*dial->radius,
13041 yc - s*dial->radius);
13046 s = sin(dial->angle);
13047 c = cos(dial->angle);
13050 points[0].x = xc + s*dial->pointer_width/2;
13051 points[0].y = yc + c*dial->pointer_width/2;
13052 points[1].x = xc + c*dial->radius;
13053 points[1].y = yc - s*dial->radius;
13054 points[2].x = xc - s*dial->pointer_width/2;
13055 points[2].y = yc - c*dial->pointer_width/2;
13057 gtk_draw_polygon (widget->style,
13068 <!-- ----------------------------------------------------------------- -->
13069 <sect2> Event handling
13071 The rest of the widget's code handles various types of events, and
13072 isn't too different from what would be found in many GTK
13073 applications. Two types of events can occur - either the user can
13074 click on the widget with the mouse and drag to move the pointer, or
13075 the value of the Adjustment object can change due to some external
13078 When the user clicks on the widget, we check to see if the click was
13079 appropriately near the pointer, and if so, store then button that the
13080 user clicked with in the <tt/button/ field of the widget
13081 structure, and grab all mouse events with a call to
13082 <tt/gtk_grab_add()/. Subsequent motion of the mouse causes the
13083 value of the control to be recomputed (by the function
13084 <tt/gtk_dial_update_mouse/). Depending on the policy that has been
13085 set, "value_changed" events are either generated instantly
13086 (<tt/GTK_UPDATE_CONTINUOUS/), after a delay in a timer added with
13087 <tt/gtk_timeout_add()/ (<tt/GTK_UPDATE_DELAYED/), or only when the
13088 button is released (<tt/GTK_UPDATE_DISCONTINUOUS/).
13092 gtk_dial_button_press (GtkWidget *widget,
13093 GdkEventButton *event)
13099 double d_perpendicular;
13101 g_return_val_if_fail (widget != NULL, FALSE);
13102 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13103 g_return_val_if_fail (event != NULL, FALSE);
13105 dial = GTK_DIAL (widget);
13107 /* Determine if button press was within pointer region - we
13108 do this by computing the parallel and perpendicular distance of
13109 the point where the mouse was pressed from the line passing through
13112 dx = event->x - widget->allocation.width / 2;
13113 dy = widget->allocation.height / 2 - event->y;
13115 s = sin(dial->angle);
13116 c = cos(dial->angle);
13118 d_parallel = s*dy + c*dx;
13119 d_perpendicular = fabs(s*dx - c*dy);
13121 if (!dial->button &&
13122 (d_perpendicular < dial->pointer_width/2) &&
13123 (d_parallel > - dial->pointer_width))
13125 gtk_grab_add (widget);
13127 dial->button = event->button;
13129 gtk_dial_update_mouse (dial, event->x, event->y);
13136 gtk_dial_button_release (GtkWidget *widget,
13137 GdkEventButton *event)
13141 g_return_val_if_fail (widget != NULL, FALSE);
13142 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13143 g_return_val_if_fail (event != NULL, FALSE);
13145 dial = GTK_DIAL (widget);
13147 if (dial->button == event->button)
13149 gtk_grab_remove (widget);
13153 if (dial->policy == GTK_UPDATE_DELAYED)
13154 gtk_timeout_remove (dial->timer);
13156 if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
13157 (dial->old_value != dial->adjustment->value))
13158 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13165 gtk_dial_motion_notify (GtkWidget *widget,
13166 GdkEventMotion *event)
13169 GdkModifierType mods;
13172 g_return_val_if_fail (widget != NULL, FALSE);
13173 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13174 g_return_val_if_fail (event != NULL, FALSE);
13176 dial = GTK_DIAL (widget);
13178 if (dial->button != 0)
13183 if (event->is_hint || (event->window != widget->window))
13184 gdk_window_get_pointer (widget->window, &x, &y, &mods);
13186 switch (dial->button)
13189 mask = GDK_BUTTON1_MASK;
13192 mask = GDK_BUTTON2_MASK;
13195 mask = GDK_BUTTON3_MASK;
13203 gtk_dial_update_mouse (dial, x,y);
13210 gtk_dial_timer (GtkDial *dial)
13212 g_return_val_if_fail (dial != NULL, FALSE);
13213 g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
13215 if (dial->policy == GTK_UPDATE_DELAYED)
13216 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13222 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
13227 g_return_if_fail (dial != NULL);
13228 g_return_if_fail (GTK_IS_DIAL (dial));
13230 xc = GTK_WIDGET(dial)->allocation.width / 2;
13231 yc = GTK_WIDGET(dial)->allocation.height / 2;
13233 old_value = dial->adjustment->value;
13234 dial->angle = atan2(yc-y, x-xc);
13236 if (dial->angle < -M_PI/2.)
13237 dial->angle += 2*M_PI;
13239 if (dial->angle < -M_PI/6)
13240 dial->angle = -M_PI/6;
13242 if (dial->angle > 7.*M_PI/6.)
13243 dial->angle = 7.*M_PI/6.;
13245 dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
13246 (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
13248 if (dial->adjustment->value != old_value)
13250 if (dial->policy == GTK_UPDATE_CONTINUOUS)
13252 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13256 gtk_widget_draw (GTK_WIDGET(dial), NULL);
13258 if (dial->policy == GTK_UPDATE_DELAYED)
13261 gtk_timeout_remove (dial->timer);
13263 dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
13264 (GtkFunction) gtk_dial_timer,
13272 Changes to the Adjustment by external means are communicated to our
13273 widget by the `changed' and `value_changed' signals. The handlers
13274 for these functions call <tt/gtk_dial_update()/ to validate the
13275 arguments, compute the new pointer angle, and redraw the widget (by
13276 calling <tt/gtk_widget_draw()/).
13280 gtk_dial_update (GtkDial *dial)
13284 g_return_if_fail (dial != NULL);
13285 g_return_if_fail (GTK_IS_DIAL (dial));
13287 new_value = dial->adjustment->value;
13289 if (new_value < dial->adjustment->lower)
13290 new_value = dial->adjustment->lower;
13292 if (new_value > dial->adjustment->upper)
13293 new_value = dial->adjustment->upper;
13295 if (new_value != dial->adjustment->value)
13297 dial->adjustment->value = new_value;
13298 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13301 dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
13302 (dial->adjustment->upper - dial->adjustment->lower);
13304 gtk_widget_draw (GTK_WIDGET(dial), NULL);
13308 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
13313 g_return_if_fail (adjustment != NULL);
13314 g_return_if_fail (data != NULL);
13316 dial = GTK_DIAL (data);
13318 if ((dial->old_value != adjustment->value) ||
13319 (dial->old_lower != adjustment->lower) ||
13320 (dial->old_upper != adjustment->upper))
13322 gtk_dial_update (dial);
13324 dial->old_value = adjustment->value;
13325 dial->old_lower = adjustment->lower;
13326 dial->old_upper = adjustment->upper;
13331 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
13336 g_return_if_fail (adjustment != NULL);
13337 g_return_if_fail (data != NULL);
13339 dial = GTK_DIAL (data);
13341 if (dial->old_value != adjustment->value)
13343 gtk_dial_update (dial);
13345 dial->old_value = adjustment->value;
13350 <!-- ----------------------------------------------------------------- -->
13351 <sect2> Possible Enhancements
13353 The Dial widget as we've described it so far runs about 670 lines of
13354 code. Although that might sound like a fair bit, we've really
13355 accomplished quite a bit with that much code, especially since much of
13356 that length is headers and boilerplate. However, there are quite a few
13357 more enhancements that could be made to this widget:
13360 <item> If you try this widget out, you'll find that there is some
13361 flashing as the pointer is dragged around. This is because the entire
13362 widget is erased every time the pointer is moved before being
13363 redrawn. Often, the best way to handle this problem is to draw to an
13364 offscreen pixmap, then copy the final results onto the screen in one
13365 step. (The ProgressBar widget draws itself in this fashion.)
13367 <item> The user should be able to use the up and down arrow keys to
13368 increase and decrease the value.
13370 <item> It would be nice if the widget had buttons to increase and
13371 decrease the value in small or large steps. Although it would be
13372 possible to use embedded Button widgets for this, we would also like
13373 the buttons to auto-repeat when held down, as the arrows on a
13374 scrollbar do. Most of the code to implement this type of behavior can
13375 be found in the GtkRange widget.
13377 <item> The Dial widget could be made into a container widget with a
13378 single child widget positioned at the bottom between the buttons
13379 mentioned above. The user could then add their choice of a label or
13380 entry widget to display the current value of the dial.
13384 <!-- ----------------------------------------------------------------- -->
13385 <sect1> Learning More
13388 Only a small part of the many details involved in creating widgets
13389 could be described above. If you want to write your own widgets, the
13390 best source of examples is the GTK source itself. Ask yourself some
13391 questions about the widget you want to write: is it a Container
13392 widget? does it have its own window? is it a modification of an
13393 existing widget? Then find a similar widget, and start making changes.
13396 <!-- ***************************************************************** -->
13397 <sect>Scribble, A Simple Example Drawing Program
13398 <!-- ***************************************************************** -->
13400 <!-- ----------------------------------------------------------------- -->
13403 In this section, we will build a simple drawing program. In the
13404 process, we will examine how to handle mouse events, how to draw in a
13405 window, and how to do drawing better by using a backing pixmap. After
13406 creating the simple drawing program, we will extend it by adding
13407 support for XInput devices, such as drawing tablets. GTK provides
13408 support routines which makes getting extended information, such as
13409 pressure and tilt, from such devices quite easy.
13411 <!-- ----------------------------------------------------------------- -->
13412 <sect1> Event Handling
13414 The GTK signals we have already discussed are for high-level actions,
13415 such as a menu item being selected. However, sometimes it is useful to
13416 learn about lower-level occurrences, such as the mouse being moved, or
13417 a key being pressed. There are also GTK signals corresponding to these
13418 low-level <em>events</em>. The handlers for these signals have an
13419 extra parameter which is a pointer to a structure containing
13420 information about the event. For instance, motion events handlers are
13421 passed a pointer to a GdkEventMotion structure which looks (in part)
13425 struct _GdkEventMotion
13438 <tt/type/ will be set to the event type, in this case
13439 <tt/GDK_MOTION_NOTIFY/, window is the window in which the event
13440 occurred. <tt/x/ and <tt/y/ give the coordinates of the event,
13441 and <tt/state/ specifies the modifier state when the event
13442 occurred (that is, it specifies which modifier keys and mouse buttons
13443 were pressed.) It is the bitwise OR of some of the following:
13461 As for other signals, to determine what happens when an event occurs
13462 we call <tt>gtk_signal_connect()</tt>. But we also need let GTK
13463 know which events we want to be notified about. To do this, we call
13467 void gtk_widget_set_events (GtkWidget *widget,
13471 The second field specifies the events we are interested in. It
13472 is the bitwise OR of constants that specify different types
13473 of events. For future reference the event types are:
13477 GDK_POINTER_MOTION_MASK
13478 GDK_POINTER_MOTION_HINT_MASK
13479 GDK_BUTTON_MOTION_MASK
13480 GDK_BUTTON1_MOTION_MASK
13481 GDK_BUTTON2_MOTION_MASK
13482 GDK_BUTTON3_MOTION_MASK
13483 GDK_BUTTON_PRESS_MASK
13484 GDK_BUTTON_RELEASE_MASK
13486 GDK_KEY_RELEASE_MASK
13487 GDK_ENTER_NOTIFY_MASK
13488 GDK_LEAVE_NOTIFY_MASK
13489 GDK_FOCUS_CHANGE_MASK
13491 GDK_PROPERTY_CHANGE_MASK
13492 GDK_PROXIMITY_IN_MASK
13493 GDK_PROXIMITY_OUT_MASK
13496 There are a few subtle points that have to be observed when calling
13497 <tt/gtk_widget_set_events()/. First, it must be called before the X window
13498 for a GTK widget is created. In practical terms, this means you
13499 should call it immediately after creating the widget. Second, the
13500 widget must have an associated X window. For efficiency, many widget
13501 types do not have their own window, but draw in their parent's window.
13524 To capture events for these widgets, you need to use an EventBox
13525 widget. See the section on the <ref id="sec_EventBox"
13526 name="EventBox"> widget for details.
13528 For our drawing program, we want to know when the mouse button is
13529 pressed and when the mouse is moved, so we specify
13530 <tt/GDK_POINTER_MOTION_MASK/ and <tt/GDK_BUTTON_PRESS_MASK/. We also
13531 want to know when we need to redraw our window, so we specify
13532 <tt/GDK_EXPOSURE_MASK/. Although we want to be notified via a
13533 Configure event when our window size changes, we don't have to specify
13534 the corresponding <tt/GDK_STRUCTURE_MASK/ flag, because it is
13535 automatically specified for all windows.
13537 It turns out, however, that there is a problem with just specifying
13538 <tt/GDK_POINTER_MOTION_MASK/. This will cause the server to add a new
13539 motion event to the event queue every time the user moves the mouse.
13540 Imagine that it takes us 0.1 seconds to handle a motion event, but the
13541 X server queues a new motion event every 0.05 seconds. We will soon
13542 get way behind the users drawing. If the user draws for 5 seconds,
13543 it will take us another 5 seconds to catch up after they release
13544 the mouse button! What we would like is to only get one motion
13545 event for each event we process. The way to do this is to
13546 specify <tt/GDK_POINTER_MOTION_HINT_MASK/.
13548 When we specify <tt/GDK_POINTER_MOTION_HINT_MASK/, the server sends
13549 us a motion event the first time the pointer moves after entering
13550 our window, or after a button press or release event. Subsequent
13551 motion events will be suppressed until we explicitly ask for
13552 the position of the pointer using the function:
13555 GdkWindow* gdk_window_get_pointer (GdkWindow *window,
13558 GdkModifierType *mask);
13561 (There is another function, <tt>gtk_widget_get_pointer()</tt> which
13562 has a simpler interface, but turns out not to be very useful, since
13563 it only retrieves the position of the mouse, not whether the buttons
13566 The code to set the events for our window then looks like:
13569 gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
13570 (GtkSignalFunc) expose_event, NULL);
13571 gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
13572 (GtkSignalFunc) configure_event, NULL);
13573 gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
13574 (GtkSignalFunc) motion_notify_event, NULL);
13575 gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
13576 (GtkSignalFunc) button_press_event, NULL);
13578 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
13579 | GDK_LEAVE_NOTIFY_MASK
13580 | GDK_BUTTON_PRESS_MASK
13581 | GDK_POINTER_MOTION_MASK
13582 | GDK_POINTER_MOTION_HINT_MASK);
13585 We'll save the "expose_event" and "configure_event" handlers for
13586 later. The "motion_notify_event" and "button_press_event" handlers
13591 button_press_event (GtkWidget *widget, GdkEventButton *event)
13593 if (event->button == 1 && pixmap != NULL)
13594 draw_brush (widget, event->x, event->y);
13600 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
13603 GdkModifierType state;
13605 if (event->is_hint)
13606 gdk_window_get_pointer (event->window, &x, &y, &state);
13611 state = event->state;
13614 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
13615 draw_brush (widget, x, y);
13621 <!-- ----------------------------------------------------------------- -->
13622 <sect1> The DrawingArea Widget, And Drawing
13624 We know turn to the process of drawing on the screen. The
13625 widget we use for this is the DrawingArea widget. A drawing area
13626 widget is essentially an X window and nothing more. It is a blank
13627 canvas in which we can draw whatever we like. A drawing area
13628 is created using the call:
13631 GtkWidget* gtk_drawing_area_new (void);
13634 A default size for the widget can be specified by calling:
13637 void gtk_drawing_area_size (GtkDrawingArea *darea,
13642 This default size can be overridden, as is true for all widgets,
13643 by calling <tt>gtk_widget_set_usize()</tt>, and that, in turn, can
13644 be overridden if the user manually resizes the the window containing
13647 It should be noted that when we create a DrawingArea widget, we are,
13648 <em>completely</em> responsible for drawing the contents. If our
13649 window is obscured then uncovered, we get an exposure event and must
13650 redraw what was previously hidden.
13652 Having to remember everything that was drawn on the screen so we
13653 can properly redraw it can, to say the least, be a nuisance. In
13654 addition, it can be visually distracting if portions of the
13655 window are cleared, then redrawn step by step. The solution to
13656 this problem is to use an offscreen <em>backing pixmap</em>.
13657 Instead of drawing directly to the screen, we draw to an image
13658 stored in server memory but not displayed, then when the image
13659 changes or new portions of the image are displayed, we copy the
13660 relevant portions onto the screen.
13662 To create an offscreen pixmap, we call the function:
13665 GdkPixmap* gdk_pixmap_new (GdkWindow *window,
13671 The <tt>window</tt> parameter specifies a GDK window that this pixmap
13672 takes some of its properties from. <tt>width</tt> and <tt>height</tt>
13673 specify the size of the pixmap. <tt>depth</tt> specifies the <em>color
13674 depth</em>, that is the number of bits per pixel, for the new window.
13675 If the depth is specified as <tt>-1</tt>, it will match the depth
13676 of <tt>window</tt>.
13678 We create the pixmap in our "configure_event" handler. This event
13679 is generated whenever the window changes size, including when it
13680 is originally created.
13683 /* Backing pixmap for drawing area */
13684 static GdkPixmap *pixmap = NULL;
13686 /* Create a new backing pixmap of the appropriate size */
13688 configure_event (GtkWidget *widget, GdkEventConfigure *event)
13691 gdk_pixmap_unref(pixmap);
13693 pixmap = gdk_pixmap_new(widget->window,
13694 widget->allocation.width,
13695 widget->allocation.height,
13697 gdk_draw_rectangle (pixmap,
13698 widget->style->white_gc,
13701 widget->allocation.width,
13702 widget->allocation.height);
13708 The call to <tt>gdk_draw_rectangle()</tt> clears the pixmap
13709 initially to white. We'll say more about that in a moment.
13711 Our exposure event handler then simply copies the relevant portion
13712 of the pixmap onto the screen (we determine the area we need
13713 to redraw by using the event->area field of the exposure event):
13716 /* Redraw the screen from the backing pixmap */
13718 expose_event (GtkWidget *widget, GdkEventExpose *event)
13720 gdk_draw_pixmap(widget->window,
13721 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
13723 event->area.x, event->area.y,
13724 event->area.x, event->area.y,
13725 event->area.width, event->area.height);
13731 We've now seen how to keep the screen up to date with our pixmap, but
13732 how do we actually draw interesting stuff on our pixmap? There are a
13733 large number of calls in GTK's GDK library for drawing on
13734 <em>drawables</em>. A drawable is simply something that can be drawn
13735 upon. It can be a window, a pixmap, or a bitmap (a black and white
13736 image). We've already seen two such calls above,
13737 <tt>gdk_draw_rectangle()</tt> and <tt>gdk_draw_pixmap()</tt>. The
13742 gdk_draw_rectangle ()
13744 gdk_draw_polygon ()
13751 gdk_draw_segments ()
13754 See the reference documentation or the header file
13755 <tt><gdk/gdk.h></tt> for further details on these functions.
13756 These functions all share the same first two arguments. The first
13757 argument is the drawable to draw upon, the second argument is a
13758 <em>graphics context</em> (GC).
13760 A graphics context encapsulates information about things such as
13761 foreground and background color and line width. GDK has a full set of
13762 functions for creating and modifying graphics contexts, but to keep
13763 things simple we'll just use predefined graphics contexts. Each widget
13764 has an associated style. (Which can be modified in a gtkrc file, see
13765 the section GTK's rc file.) This, among other things, stores a number
13766 of graphics contexts. Some examples of accessing these graphics
13770 widget->style->white_gc
13771 widget->style->black_gc
13772 widget->style->fg_gc[GTK_STATE_NORMAL]
13773 widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
13776 The fields <tt>fg_gc</tt>, <tt>bg_gc</tt>, <tt>dark_gc</tt>, and
13777 <tt>light_gc</tt> are indexed by a parameter of type
13778 <tt>GtkStateType</tt> which can take on the values:
13783 GTK_STATE_PRELIGHT,
13784 GTK_STATE_SELECTED,
13785 GTK_STATE_INSENSITIVE
13788 For instance, the for <tt/GTK_STATE_SELECTED/ the default foreground
13789 color is white and the default background color, dark blue.
13791 Our function <tt>draw_brush()</tt>, which does the actual drawing
13792 on the screen, is then:
13795 /* Draw a rectangle on the screen */
13797 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
13799 GdkRectangle update_rect;
13801 update_rect.x = x - 5;
13802 update_rect.y = y - 5;
13803 update_rect.width = 10;
13804 update_rect.height = 10;
13805 gdk_draw_rectangle (pixmap,
13806 widget->style->black_gc,
13808 update_rect.x, update_rect.y,
13809 update_rect.width, update_rect.height);
13810 gtk_widget_draw (widget, &update_rect);
13814 After we draw the rectangle representing the brush onto the pixmap,
13815 we call the function:
13818 void gtk_widget_draw (GtkWidget *widget,
13819 GdkRectangle *area);
13822 which notifies X that the area given by the <tt>area</tt> parameter
13823 needs to be updated. X will eventually generate an expose event
13824 (possibly combining the areas passed in several calls to
13825 <tt>gtk_widget_draw()</tt>) which will cause our expose event handler
13826 to copy the relevant portions to the screen.
13828 We have now covered the entire drawing program except for a few
13829 mundane details like creating the main window. The complete
13830 source code is available from the location from which you got
13831 this tutorial, or from:
13833 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
13834 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
13837 <!-- ----------------------------------------------------------------- -->
13838 <sect1> Adding XInput support
13840 It is now possible to buy quite inexpensive input devices such
13841 as drawing tablets, which allow drawing with a much greater
13842 ease of artistic expression than does a mouse. The simplest way
13843 to use such devices is simply as a replacement for the mouse,
13844 but that misses out many of the advantages of these devices,
13848 <item> Pressure sensitivity
13849 <item> Tilt reporting
13850 <item> Sub-pixel positioning
13851 <item> Multiple inputs (for example, a stylus with a point and eraser)
13854 For information about the XInput extension, see the <htmlurl
13855 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
13856 name="XInput-HOWTO">.
13858 If we examine the full definition of, for example, the GdkEventMotion
13859 structure, we see that it has fields to support extended device
13863 struct _GdkEventMotion
13875 GdkInputSource source;
13880 <tt/pressure/ gives the pressure as a floating point number between
13881 0 and 1. <tt/xtilt/ and <tt/ytilt/ can take on values between
13882 -1 and 1, corresponding to the degree of tilt in each direction.
13883 <tt/source/ and <tt/deviceid/ specify the device for which the
13884 event occurred in two different ways. <tt/source/ gives some simple
13885 information about the type of device. It can take the enumeration
13895 <tt/deviceid/ specifies a unique numeric ID for the device. This can
13896 be used to find out further information about the device using the
13897 <tt/gdk_input_list_devices()/ call (see below). The special value
13898 <tt/GDK_CORE_POINTER/ is used for the core pointer device. (Usually
13901 <sect2> Enabling extended device information
13903 To let GTK know about our interest in the extended device information,
13904 we merely have to add a single line to our program:
13907 gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
13910 By giving the value <tt/GDK_EXTENSION_EVENTS_CURSOR/ we say that
13911 we are interested in extension events, but only if we don't have
13912 to draw our own cursor. See the section <ref
13913 id="sec_Further_Sophistications" name="Further Sophistications"> below
13914 for more information about drawing the cursor. We could also
13915 give the values <tt/GDK_EXTENSION_EVENTS_ALL/ if we were willing
13916 to draw our own cursor, or <tt/GDK_EXTENSION_EVENTS_NONE/ to revert
13917 back to the default condition.
13919 This is not completely the end of the story however. By default,
13920 no extension devices are enabled. We need a mechanism to allow
13921 users to enable and configure their extension devices. GTK provides
13922 the InputDialog widget to automate this process. The following
13923 procedure manages an InputDialog widget. It creates the dialog if
13924 it isn't present, and raises it to the top otherwise.
13928 input_dialog_destroy (GtkWidget *w, gpointer data)
13930 *((GtkWidget **)data) = NULL;
13934 create_input_dialog ()
13936 static GtkWidget *inputd = NULL;
13940 inputd = gtk_input_dialog_new();
13942 gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
13943 (GtkSignalFunc)input_dialog_destroy, &inputd);
13944 gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
13946 (GtkSignalFunc)gtk_widget_hide,
13947 GTK_OBJECT(inputd));
13948 gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
13950 gtk_widget_show (inputd);
13954 if (!GTK_WIDGET_MAPPED(inputd))
13955 gtk_widget_show(inputd);
13957 gdk_window_raise(inputd->window);
13962 (You might want to take note of the way we handle this dialog. By
13963 connecting to the "destroy" signal, we make sure that we don't keep a
13964 pointer to dialog around after it is destroyed - that could lead to a
13967 The InputDialog has two buttons "Close" and "Save", which by default
13968 have no actions assigned to them. In the above function we make
13969 "Close" hide the dialog, hide the "Save" button, since we don't
13970 implement saving of XInput options in this program.
13972 <sect2> Using extended device information
13974 Once we've enabled the device, we can just use the extended
13975 device information in the extra fields of the event structures.
13976 In fact, it is always safe to use this information since these
13977 fields will have reasonable default values even when extended
13978 events are not enabled.
13980 Once change we do have to make is to call
13981 <tt/gdk_input_window_get_pointer()/ instead of
13982 <tt/gdk_window_get_pointer/. This is necessary because
13983 <tt/gdk_window_get_pointer/ doesn't return the extended device
13987 void gdk_input_window_get_pointer( GdkWindow *window,
13994 GdkModifierType *mask);
13997 When calling this function, we need to specify the device ID as
13998 well as the window. Usually, we'll get the device ID from the
13999 <tt/deviceid/ field of an event structure. Again, this function
14000 will return reasonable values when extension events are not
14001 enabled. (In this case, <tt/event->deviceid/ will have the value
14002 <tt/GDK_CORE_POINTER/).
14004 So the basic structure of our button-press and motion event handlers,
14005 doesn't change much - we just need to add code to deal with the
14006 extended information.
14010 button_press_event (GtkWidget *widget, GdkEventButton *event)
14012 print_button_press (event->deviceid);
14014 if (event->button == 1 && pixmap != NULL)
14015 draw_brush (widget, event->source, event->x, event->y, event->pressure);
14021 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
14025 GdkModifierType state;
14027 if (event->is_hint)
14028 gdk_input_window_get_pointer (event->window, event->deviceid,
14029 &x, &y, &pressure, NULL, NULL, &state);
14034 pressure = event->pressure;
14035 state = event->state;
14038 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
14039 draw_brush (widget, event->source, x, y, pressure);
14045 We also need to do something with the new information. Our new
14046 <tt/draw_brush()/ function draws with a different color for
14047 each <tt/event->source/ and changes the brush size depending
14051 /* Draw a rectangle on the screen, size depending on pressure,
14052 and color on the type of device */
14054 draw_brush (GtkWidget *widget, GdkInputSource source,
14055 gdouble x, gdouble y, gdouble pressure)
14058 GdkRectangle update_rect;
14062 case GDK_SOURCE_MOUSE:
14063 gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
14065 case GDK_SOURCE_PEN:
14066 gc = widget->style->black_gc;
14068 case GDK_SOURCE_ERASER:
14069 gc = widget->style->white_gc;
14072 gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
14075 update_rect.x = x - 10 * pressure;
14076 update_rect.y = y - 10 * pressure;
14077 update_rect.width = 20 * pressure;
14078 update_rect.height = 20 * pressure;
14079 gdk_draw_rectangle (pixmap, gc, TRUE,
14080 update_rect.x, update_rect.y,
14081 update_rect.width, update_rect.height);
14082 gtk_widget_draw (widget, &update_rect);
14086 <sect2> Finding out more about a device
14088 As an example of how to find out more about a device, our program
14089 will print the name of the device that generates each button
14090 press. To find out the name of a device, we call the function:
14093 GList *gdk_input_list_devices (void);
14096 which returns a GList (a linked list type from the glib library)
14097 of GdkDeviceInfo structures. The GdkDeviceInfo structure is defined
14101 struct _GdkDeviceInfo
14105 GdkInputSource source;
14111 GdkDeviceKey *keys;
14115 Most of these fields are configuration information that you
14116 can ignore unless you are implemented XInput configuration
14117 saving. The we are interested in here is <tt/name/ which is
14118 simply the name that X assigns to the device. The other field
14119 that isn't configuration information is <tt/has_cursor/. If
14120 <tt/has_cursor/ is false, then we we need to draw our own
14121 cursor. But since we've specified <tt/GDK_EXTENSION_EVENTS_CURSOR/,
14122 we don't have to worry about this.
14124 Our <tt/print_button_press()/ function simply iterates through
14125 the returned list until it finds a match, then prints out
14126 the name of the device.
14130 print_button_press (guint32 deviceid)
14134 /* gdk_input_list_devices returns an internal list, so we shouldn't
14135 free it afterwards */
14136 tmp_list = gdk_input_list_devices();
14140 GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
14142 if (info->deviceid == deviceid)
14144 printf("Button press on device '%s'\n", info->name);
14148 tmp_list = tmp_list->next;
14153 That completes the changes to `XInputize' our program. As with
14154 the first version, the complete source is available at the location
14155 from which you got this tutorial, or from:
14157 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
14158 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
14161 <sect2> Further sophistications <label id="sec_Further_Sophistications">
14163 Although our program now supports XInput quite well, it lacks some
14164 features we would want in a full-featured application. First, the user
14165 probably doesn't want to have to configure their device each time they
14166 run the program, so we should allow them to save the device
14167 configuration. This is done by iterating through the return of
14168 <tt/gdk_input_list_devices()/ and writing out the configuration to a
14171 To restore the state next time the program is run, GDK provides
14172 functions to change device configuration:
14175 gdk_input_set_extension_events()
14176 gdk_input_set_source()
14177 gdk_input_set_mode()
14178 gdk_input_set_axes()
14179 gdk_input_set_key()
14182 (The list returned from <tt/gdk_input_list_devices()/ should not be
14183 modified directly.) An example of doing this can be found in the
14184 drawing program gsumi. (Available from <htmlurl
14185 url="http://www.msc.cornell.edu/~otaylor/gsumi/"
14186 name="http://www.msc.cornell.edu/~otaylor/gsumi/">) Eventually, it
14187 would be nice to have a standard way of doing this for all
14188 applications. This probably belongs at a slightly higher level than
14189 GTK, perhaps in the GNOME library.
14191 Another major omission that we have mentioned above is the lack of
14192 cursor drawing. Platforms other than XFree86 currently do not allow
14193 simultaneously using a device as both the core pointer and directly by
14194 an application. See the <url
14195 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
14196 name="XInput-HOWTO"> for more information about this. This means that
14197 applications that want to support the widest audience need to draw
14200 An application that draws its own cursor needs to do two things:
14201 determine if the current device needs a cursor drawn or not, and
14202 determine if the current device is in proximity. (If the current
14203 device is a drawing tablet, it's a nice touch to make the cursor
14204 disappear when the stylus is lifted from the tablet. When the
14205 device is touching the stylus, that is called "in proximity.")
14206 The first is done by searching the device list, as we did
14207 to find out the device name. The second is achieved by selecting
14208 "proximity_out" events. An example of drawing one's own cursor is
14209 found in the 'testinput' program found in the GTK distribution.
14211 <!-- ***************************************************************** -->
14212 <sect>Tips For Writing GTK Applications
14213 <!-- ***************************************************************** -->
14215 This section is simply a gathering of wisdom, general style guidelines
14216 and hints to creating good GTK applications. Currently this section
14217 is very short, but hopefully it will get longer in future editions of
14220 Use GNU autoconf and automake! They are your friends :) Automake
14221 examines C files, determines how they depend on each other, and
14222 generates a Makefile so the files can be compiled in the correct
14223 order. Autoconf permits automatic configuration of software
14224 installation, handling a large number of system quirks to increase
14225 portability. I am planning to make a quick intro on them here.
14227 When writing C code, use only C comments (beginning with "/*" and
14228 ending with "*/"), and don't use C++-style comments ("//"). Although
14229 many C compilers understand C++ comments, others don't, and the ANSI C
14230 standard does not require that C++-style comments be processed as
14233 <!-- ***************************************************************** -->
14234 <sect>Contributing <label id="sec_Contributing">
14235 <!-- ***************************************************************** -->
14237 This document, like so much other great software out there, was
14238 created for free by volunteers. If you are at all knowledgeable about
14239 any aspect of GTK that does not already have documentation, please
14240 consider contributing to this document.
14242 If you do decide to contribute, please mail your text to Tony Gale,
14243 <tt><htmlurl url="mailto:gale@gtk.org"
14244 name="gale@gtk.org"></tt>. Also, be aware that the entirety of this
14245 document is free, and any addition by you provide must also be
14246 free. That is, people may use any portion of your examples in their
14247 programs, and copies of this document may be distributed at will etc.
14251 <!-- ***************************************************************** -->
14253 <!-- ***************************************************************** -->
14255 I would like to thank the following for their contributions to this text.
14258 <item>Bawer Dagdeviren, <tt><htmlurl url="mailto:chamele0n@geocities.com"
14259 name="chamele0n@geocities.com"></tt> for the menus tutorial.
14261 <item>Raph Levien, <tt><htmlurl url="mailto:raph@acm.org"
14262 name="raph@acm.org"></tt>
14263 for hello world ala GTK, widget packing, and general all around wisdom.
14264 He's also generously donated a home for this tutorial.
14266 <item>Peter Mattis, <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
14267 name="petm@xcf.berkeley.edu"></tt> for the simplest GTK program..
14268 and the ability to make it :)
14270 <item>Werner Koch <tt><htmlurl url="mailto:werner.koch@guug.de"
14271 name="werner.koch@guug.de"></tt> for converting the original plain text to
14272 SGML, and the widget class hierarchy.
14274 <item>Mark Crichton <tt><htmlurl
14275 url="mailto:crichton@expert.cc.purdue.edu"
14276 name="crichton@expert.cc.purdue.edu"></tt> for the menu factory code,
14277 and the table packing tutorial.
14279 <item>Owen Taylor <tt><htmlurl url="mailto:owt1@cornell.edu"
14280 name="owt1@cornell.edu"></tt> for the EventBox widget section (and the
14281 patch to the distro). He's also responsible for the selections code
14282 and tutorial, as well as the sections on writing your own GTK widgets,
14283 and the example application. Thanks a lot Owen for all you help!
14285 <item>Mark VanderBoom <tt><htmlurl url="mailto:mvboom42@calvin.edu"
14286 name="mvboom42@calvin.edu"></tt> for his wonderful work on the
14287 Notebook, Progress Bar, Dialogs, and File selection widgets. Thanks a
14288 lot Mark! You've been a great help.
14290 <item>Tim Janik <tt><htmlurl url="mailto:timj@gtk.org"
14291 name="timj@psynet.net"></tt> for his great job on the Lists
14292 Widget. His excellent work on automatically extracting the widget tree
14293 and signal information from GTK. Thanks Tim :)
14295 <item>Rajat Datta <tt><htmlurl url="mailto:rajat@ix.netcom.com"
14296 name="rajat@ix.netcom.com"</tt> for the excellent job on the Pixmap
14299 <item>Michael K. Johnson <tt><htmlurl url="mailto:johnsonm@redhat.com"
14300 name="johnsonm@redhat.com"></tt> for info and code for popup menus.
14302 <item>David Huggins-Daines <tt><htmlurl
14303 url="mailto:bn711@freenet.carleton.ca"
14304 name="bn711@freenet.carleton.ca"></tt> for the Range Widgets and Tree
14307 <item>Stefan Mars <tt><htmlurl url="mailto:mars@lysator.liu.se"
14308 name="mars@lysator.liu.se"></tt> for the GtkCList section.
14310 <item>David A. Wheeler <tt><htmlurl url="mailto:dwheeler@ida.org"
14311 name="dwheeler@ida.org"></tt> for portions of the text on glib
14312 and various tutorial fixups and improvements.
14313 The glib text was in turn based on material developed by Damon Chaplin
14314 <tt><htmlurl url="mailto:DAChaplin@msn.com" name="DAChaplin@msn.com"></tt>
14317 And to all of you who commented and helped refine this document.
14321 <!-- ***************************************************************** -->
14322 <sect> Tutorial Copyright and Permissions Notice
14323 <!-- ***************************************************************** -->
14326 The GTK Tutorial is Copyright (C) 1997 Ian Main.
14328 Copyright (C) 1998-1999 Tony Gale.
14330 Permission is granted to make and distribute verbatim copies of this
14331 manual provided the copyright notice and this permission notice are
14332 preserved on all copies.
14334 Permission is granted to copy and distribute modified versions of
14335 this document under the conditions for verbatim copying, provided that
14336 this copyright notice is included exactly as in the original,
14337 and that the entire resulting derived work is distributed under
14338 the terms of a permission notice identical to this one.
14339 <P>Permission is granted to copy and distribute translations of this
14340 document into another language, under the above conditions for modified
14343 If you are intending to incorporate this document into a published
14344 work, please contact the maintainer, and we will make an effort
14345 to ensure that you have the most up to date information available.
14347 There is no guarantee that this document lives up to its intended
14348 purpose. This is simply provided as a free resource. As such,
14349 the authors and maintainers of the information provided within can
14350 not make any guarantee that the information is even accurate.
14352 <!-- ***************************************************************** -->
14354 <!-- ***************************************************************** -->
14356 <!-- ***************************************************************** -->
14357 <sect> GTK Signals <label id="sec_GTK_Signals">
14358 <!-- ***************************************************************** -->
14360 As GTK is an object oriented widget set, it has a hierarchy of
14361 inheritance. This inheritance mechanism applies for
14362 signals. Therefore, you should refer to the widget hierarchy tree when
14363 using the signals listed in this section.
14365 <!-- ----------------------------------------------------------------- -->
14367 <!-- ----------------------------------------------------------------- -->
14370 void GtkObject::destroy (GtkObject *,
14374 <!-- ----------------------------------------------------------------- -->
14376 <!-- ----------------------------------------------------------------- -->
14380 void GtkWidget::show (GtkWidget *,
14382 void GtkWidget::hide (GtkWidget *,
14384 void GtkWidget::map (GtkWidget *,
14386 void GtkWidget::unmap (GtkWidget *,
14388 void GtkWidget::realize (GtkWidget *,
14390 void GtkWidget::unrealize (GtkWidget *,
14392 void GtkWidget::draw (GtkWidget *,
14395 void GtkWidget::draw-focus (GtkWidget *,
14397 void GtkWidget::draw-default (GtkWidget *,
14399 void GtkWidget::size-request (GtkWidget *,
14402 void GtkWidget::size-allocate (GtkWidget *,
14405 void GtkWidget::state-changed (GtkWidget *,
14408 void GtkWidget::parent-set (GtkWidget *,
14411 void GtkWidget::style-set (GtkWidget *,
14414 void GtkWidget::add-accelerator (GtkWidget *,
14421 void GtkWidget::remove-accelerator (GtkWidget *,
14426 gboolean GtkWidget::event (GtkWidget *,
14429 gboolean GtkWidget::button-press-event (GtkWidget *,
14432 gboolean GtkWidget::button-release-event (GtkWidget *,
14435 gboolean GtkWidget::motion-notify-event (GtkWidget *,
14438 gboolean GtkWidget::delete-event (GtkWidget *,
14441 gboolean GtkWidget::destroy-event (GtkWidget *,
14444 gboolean GtkWidget::expose-event (GtkWidget *,
14447 gboolean GtkWidget::key-press-event (GtkWidget *,
14450 gboolean GtkWidget::key-release-event (GtkWidget *,
14453 gboolean GtkWidget::enter-notify-event (GtkWidget *,
14456 gboolean GtkWidget::leave-notify-event (GtkWidget *,
14459 gboolean GtkWidget::configure-event (GtkWidget *,
14462 gboolean GtkWidget::focus-in-event (GtkWidget *,
14465 gboolean GtkWidget::focus-out-event (GtkWidget *,
14468 gboolean GtkWidget::map-event (GtkWidget *,
14471 gboolean GtkWidget::unmap-event (GtkWidget *,
14474 gboolean GtkWidget::property-notify-event (GtkWidget *,
14477 gboolean GtkWidget::selection-clear-event (GtkWidget *,
14480 gboolean GtkWidget::selection-request-event (GtkWidget *,
14483 gboolean GtkWidget::selection-notify-event (GtkWidget *,
14486 void GtkWidget::selection-get (GtkWidget *,
14487 GtkSelectionData *,
14490 void GtkWidget::selection-received (GtkWidget *,
14491 GtkSelectionData *,
14494 gboolean GtkWidget::proximity-in-event (GtkWidget *,
14497 gboolean GtkWidget::proximity-out-event (GtkWidget *,
14500 void GtkWidget::drag-begin (GtkWidget *,
14503 void GtkWidget::drag-end (GtkWidget *,
14506 void GtkWidget::drag-data-delete (GtkWidget *,
14509 void GtkWidget::drag-leave (GtkWidget *,
14513 gboolean GtkWidget::drag-motion (GtkWidget *,
14519 gboolean GtkWidget::drag-drop (GtkWidget *,
14525 void GtkWidget::drag-data-get (GtkWidget *,
14527 GtkSelectionData *,
14531 void GtkWidget::drag-data-received (GtkWidget *,
14535 GtkSelectionData *,
14539 gboolean GtkWidget::client-event (GtkWidget *,
14542 gboolean GtkWidget::no-expose-event (GtkWidget *,
14545 gboolean GtkWidget::visibility-notify-event (GtkWidget *,
14548 void GtkWidget::debug-msg (GtkWidget *,
14553 <!-- ----------------------------------------------------------------- -->
14555 <!-- ----------------------------------------------------------------- -->
14558 void GtkData::disconnect (GtkData *,
14562 <!-- ----------------------------------------------------------------- -->
14563 <sect1>GtkContainer
14564 <!-- ----------------------------------------------------------------- -->
14567 void GtkContainer::add (GtkContainer *,
14570 void GtkContainer::remove (GtkContainer *,
14573 void GtkContainer::check-resize (GtkContainer *,
14575 GtkDirectionType GtkContainer::focus (GtkContainer *,
14578 void GtkContainer::set-focus-child (GtkContainer *,
14583 <!-- ----------------------------------------------------------------- -->
14585 <!-- ----------------------------------------------------------------- -->
14588 void GtkCalendar::month-changed (GtkCalendar *,
14590 void GtkCalendar::day-selected (GtkCalendar *,
14592 void GtkCalendar::day-selected-double-click (GtkCalendar *,
14594 void GtkCalendar::prev-month (GtkCalendar *,
14596 void GtkCalendar::next-month (GtkCalendar *,
14598 void GtkCalendar::prev-year (GtkCalendar *,
14600 void GtkCalendar::next-year (GtkCalendar *,
14604 <!-- ----------------------------------------------------------------- -->
14606 <!-- ----------------------------------------------------------------- -->
14609 void GtkEditable::changed (GtkEditable *,
14611 void GtkEditable::insert-text (GtkEditable *,
14616 void GtkEditable::delete-text (GtkEditable *,
14620 void GtkEditable::activate (GtkEditable *,
14622 void GtkEditable::set-editable (GtkEditable *,
14625 void GtkEditable::move-cursor (GtkEditable *,
14629 void GtkEditable::move-word (GtkEditable *,
14632 void GtkEditable::move-page (GtkEditable *,
14636 void GtkEditable::move-to-row (GtkEditable *,
14639 void GtkEditable::move-to-column (GtkEditable *,
14642 void GtkEditable::kill-char (GtkEditable *,
14645 void GtkEditable::kill-word (GtkEditable *,
14648 void GtkEditable::kill-line (GtkEditable *,
14651 void GtkEditable::cut-clipboard (GtkEditable *,
14653 void GtkEditable::copy-clipboard (GtkEditable *,
14655 void GtkEditable::paste-clipboard (GtkEditable *,
14659 <!-- ----------------------------------------------------------------- -->
14660 <sect1>GtkTipsQuery
14661 <!-- ----------------------------------------------------------------- -->
14664 void GtkTipsQuery::start-query (GtkTipsQuery *,
14666 void GtkTipsQuery::stop-query (GtkTipsQuery *,
14668 void GtkTipsQuery::widget-entered (GtkTipsQuery *,
14673 gboolean GtkTipsQuery::widget-selected (GtkTipsQuery *,
14681 <!-- ----------------------------------------------------------------- -->
14683 <!-- ----------------------------------------------------------------- -->
14686 void GtkCList::select-row (GtkCList *,
14691 void GtkCList::unselect-row (GtkCList *,
14696 void GtkCList::row-move (GtkCList *,
14700 void GtkCList::click-column (GtkCList *,
14703 void GtkCList::resize-column (GtkCList *,
14707 void GtkCList::toggle-focus-row (GtkCList *,
14709 void GtkCList::select-all (GtkCList *,
14711 void GtkCList::unselect-all (GtkCList *,
14713 void GtkCList::undo-selection (GtkCList *,
14715 void GtkCList::start-selection (GtkCList *,
14717 void GtkCList::end-selection (GtkCList *,
14719 void GtkCList::toggle-add-mode (GtkCList *,
14721 void GtkCList::extend-selection (GtkCList *,
14726 void GtkCList::scroll-vertical (GtkCList *,
14730 void GtkCList::scroll-horizontal (GtkCList *,
14734 void GtkCList::abort-column-resize (GtkCList *,
14738 <!-- ----------------------------------------------------------------- -->
14740 <!-- ----------------------------------------------------------------- -->
14743 void GtkNotebook::switch-page (GtkNotebook *,
14750 <!-- ----------------------------------------------------------------- -->
14752 <!-- ----------------------------------------------------------------- -->
14755 void GtkList::selection-changed (GtkList *,
14757 void GtkList::select-child (GtkList *,
14760 void GtkList::unselect-child (GtkList *,
14765 <!-- ----------------------------------------------------------------- -->
14766 <sect1>GtkMenuShell
14767 <!-- ----------------------------------------------------------------- -->
14770 void GtkMenuShell::deactivate (GtkMenuShell *,
14772 void GtkMenuShell::selection-done (GtkMenuShell *,
14774 void GtkMenuShell::move-current (GtkMenuShell *,
14775 GtkMenuDirectionType,
14777 void GtkMenuShell::activate-current (GtkMenuShell *,
14780 void GtkMenuShell::cancel (GtkMenuShell *,
14784 <!-- ----------------------------------------------------------------- -->
14786 <!-- ----------------------------------------------------------------- -->
14789 void GtkToolbar::orientation-changed (GtkToolbar *,
14792 void GtkToolbar::style-changed (GtkToolbar *,
14797 <!-- ----------------------------------------------------------------- -->
14799 <!-- ----------------------------------------------------------------- -->
14802 void GtkTree::selection-changed (GtkTree *,
14804 void GtkTree::select-child (GtkTree *,
14807 void GtkTree::unselect-child (GtkTree *,
14812 <!-- ----------------------------------------------------------------- -->
14814 <!-- ----------------------------------------------------------------- -->
14817 void GtkButton::pressed (GtkButton *,
14819 void GtkButton::released (GtkButton *,
14821 void GtkButton::clicked (GtkButton *,
14823 void GtkButton::enter (GtkButton *,
14825 void GtkButton::leave (GtkButton *,
14829 <!-- ----------------------------------------------------------------- -->
14831 <!-- ----------------------------------------------------------------- -->
14834 void GtkItem::select (GtkItem *,
14836 void GtkItem::deselect (GtkItem *,
14838 void GtkItem::toggle (GtkItem *,
14842 <!-- ----------------------------------------------------------------- -->
14844 <!-- ----------------------------------------------------------------- -->
14847 void GtkWindow::set-focus (GtkWindow *,
14852 <!-- ----------------------------------------------------------------- -->
14853 <sect1>GtkHandleBox
14854 <!-- ----------------------------------------------------------------- -->
14857 void GtkHandleBox::child-attached (GtkHandleBox *,
14860 void GtkHandleBox::child-detached (GtkHandleBox *,
14865 <!-- ----------------------------------------------------------------- -->
14866 <sect1>GtkToggleButton
14867 <!-- ----------------------------------------------------------------- -->
14870 void GtkToggleButton::toggled (GtkToggleButton *,
14875 <!-- ----------------------------------------------------------------- -->
14877 <!-- ----------------------------------------------------------------- -->
14880 void GtkMenuItem::activate (GtkMenuItem *,
14882 void GtkMenuItem::activate-item (GtkMenuItem *,
14886 <!-- ----------------------------------------------------------------- -->
14888 <!-- ----------------------------------------------------------------- -->
14891 void GtkListItem::toggle-focus-row (GtkListItem *,
14893 void GtkListItem::select-all (GtkListItem *,
14895 void GtkListItem::unselect-all (GtkListItem *,
14897 void GtkListItem::undo-selection (GtkListItem *,
14899 void GtkListItem::start-selection (GtkListItem *,
14901 void GtkListItem::end-selection (GtkListItem *,
14903 void GtkListItem::toggle-add-mode (GtkListItem *,
14905 void GtkListItem::extend-selection (GtkListItem *,
14910 void GtkListItem::scroll-vertical (GtkListItem *,
14914 void GtkListItem::scroll-horizontal (GtkListItem *,
14920 <!-- ----------------------------------------------------------------- -->
14922 <!-- ----------------------------------------------------------------- -->
14925 void GtkTreeItem::collapse (GtkTreeItem *,
14927 void GtkTreeItem::expand (GtkTreeItem *,
14931 <!-- ----------------------------------------------------------------- -->
14932 <sect1>GtkCheckMenuItem
14933 <!-- ----------------------------------------------------------------- -->
14936 void GtkCheckMenuItem::toggled (GtkCheckMenuItem *,
14940 <!-- ----------------------------------------------------------------- -->
14941 <sect1>GtkInputDialog
14942 <!-- ----------------------------------------------------------------- -->
14945 void GtkInputDialog::enable-device (GtkInputDialog *,
14948 void GtkInputDialog::disable-device (GtkInputDialog *,
14953 <!-- ----------------------------------------------------------------- -->
14954 <sect1>GtkColorSelection
14955 <!-- ----------------------------------------------------------------- -->
14958 void GtkColorSelection::color-changed (GtkColorSelection *,
14962 <!-- ----------------------------------------------------------------- -->
14963 <sect1>GtkStatusBar
14964 <!-- ----------------------------------------------------------------- -->
14967 void GtkStatusbar::text-pushed (GtkStatusbar *,
14971 void GtkStatusbar::text-popped (GtkStatusbar *,
14977 <!-- ----------------------------------------------------------------- -->
14979 <!-- ----------------------------------------------------------------- -->
14982 void GtkCTree::tree-select-row (GtkCTree *,
14986 void GtkCTree::tree-unselect-row (GtkCTree *,
14990 void GtkCTree::tree-expand (GtkCTree *,
14993 void GtkCTree::tree-collapse (GtkCTree *,
14996 void GtkCTree::tree-move (GtkCTree *,
15001 void GtkCTree::change-focus-row-expansion (GtkCTree *,
15002 GtkCTreeExpansionType,
15006 <!-- ----------------------------------------------------------------- -->
15008 <!-- ----------------------------------------------------------------- -->
15011 void GtkCurve::curve-type-changed (GtkCurve *,
15015 <!-- ----------------------------------------------------------------- -->
15016 <sect1>GtkAdjustment
15017 <!-- ----------------------------------------------------------------- -->
15020 void GtkAdjustment::changed (GtkAdjustment *,
15022 void GtkAdjustment::value-changed (GtkAdjustment *,
15026 <!-- ***************************************************************** -->
15027 <sect> GDK Event Types<label id="sec_GDK_Event_Types">
15028 <!-- ***************************************************************** -->
15030 The follwing data types are passed into event handlers by GTK+. For
15031 each data type listed, the signals that use this data type are listed.
15036 <item>drag_end_event
15039 <item> GdkEventType
15044 <item>destroy_event
15047 <item>no_expose_event
15050 <item> GdkEventExpose
15055 <item> GdkEventNoExpose
15057 <item> GdkEventVisibility
15059 <item> GdkEventMotion
15061 <item>motion_notify_event
15064 <item> GdkEventButton
15066 <item>button_press_event
15067 <item>button_release_event
15072 <item>key_press_event
15073 <item>key_release_event
15076 <item> GdkEventCrossing
15078 <item>enter_notify_event
15079 <item>leave_notify_event
15082 <item> GdkEventFocus
15084 <item>focus_in_event
15085 <item>focus_out_event
15088 <item> GdkEventConfigure
15090 <item>configure_event
15093 <item> GdkEventProperty
15095 <item>property_notify_event
15098 <item> GdkEventSelection
15100 <item>selection_clear_event
15101 <item>selection_request_event
15102 <item>selection_notify_event
15105 <item> GdkEventProximity
15107 <item>proximity_in_event
15108 <item>proximity_out_event
15111 <item> GdkEventDragBegin
15113 <item>drag_begin_event
15116 <item> GdkEventDragRequest
15118 <item>drag_request_event
15121 <item> GdkEventDropEnter
15123 <item>drop_enter_event
15126 <item> GdkEventDropLeave
15128 <item>drop_leave_event
15131 <item> GdkEventDropDataAvailable
15133 <item>drop_data_available_event
15136 <item> GdkEventClient
15141 <item> GdkEventOther
15147 The data type <tt/GdkEventType/ is a special data type that is used by
15148 all the other data types as an indicator of the data type being passed
15149 to the signal handler. As you will see below, each of the event data
15150 structures has a member of this type. It is defined as an enumeration
15160 GDK_MOTION_NOTIFY = 3,
15161 GDK_BUTTON_PRESS = 4,
15162 GDK_2BUTTON_PRESS = 5,
15163 GDK_3BUTTON_PRESS = 6,
15164 GDK_BUTTON_RELEASE = 7,
15166 GDK_KEY_RELEASE = 9,
15167 GDK_ENTER_NOTIFY = 10,
15168 GDK_LEAVE_NOTIFY = 11,
15169 GDK_FOCUS_CHANGE = 12,
15170 GDK_CONFIGURE = 13,
15173 GDK_PROPERTY_NOTIFY = 16,
15174 GDK_SELECTION_CLEAR = 17,
15175 GDK_SELECTION_REQUEST = 18,
15176 GDK_SELECTION_NOTIFY = 19,
15177 GDK_PROXIMITY_IN = 20,
15178 GDK_PROXIMITY_OUT = 21,
15179 GDK_DRAG_BEGIN = 22,
15180 GDK_DRAG_REQUEST = 23,
15181 GDK_DROP_ENTER = 24,
15182 GDK_DROP_LEAVE = 25,
15183 GDK_DROP_DATA_AVAIL = 26,
15184 GDK_CLIENT_EVENT = 27,
15185 GDK_VISIBILITY_NOTIFY = 28,
15186 GDK_NO_EXPOSE = 29,
15187 GDK_OTHER_EVENT = 9999 /* Deprecated, use filters instead */
15191 The other event type that is different from the others is
15192 <tt/GdkEvent/ itself. This is a union of all the other
15193 data types, which allows it to be cast to a specific
15194 event data type within a signal handler.
15196 <!-- Just a big list for now, needs expanding upon - TRG -->
15197 So, the event data types are defined as follows:
15200 struct _GdkEventAny
15207 struct _GdkEventExpose
15213 gint count; /* If non-zero, how many more events follow. */
15216 struct _GdkEventNoExpose
15221 /* XXX: does anyone need the X major_code or minor_code fields? */
15224 struct _GdkEventVisibility
15229 GdkVisibilityState state;
15232 struct _GdkEventMotion
15245 GdkInputSource source;
15247 gdouble x_root, y_root;
15250 struct _GdkEventButton
15263 GdkInputSource source;
15265 gdouble x_root, y_root;
15268 struct _GdkEventKey
15280 struct _GdkEventCrossing
15285 GdkWindow *subwindow;
15286 GdkNotifyType detail;
15289 struct _GdkEventFocus
15297 struct _GdkEventConfigure
15307 struct _GdkEventProperty
15317 struct _GdkEventSelection
15329 /* This event type will be used pretty rarely. It only is important
15330 for XInput aware programs that are drawing their own cursor */
15332 struct _GdkEventProximity
15338 GdkInputSource source;
15342 struct _GdkEventDragRequest
15350 guint protocol_version:4;
15352 guint willaccept:1;
15353 guint delete_data:1; /* Do *not* delete if link is sent, only
15360 guint8 isdrop; /* This gdk event can be generated by a couple of
15361 X events - this lets the app know whether the
15362 drop really occurred or we just set the data */
15364 GdkPoint drop_coords;
15369 struct _GdkEventDragBegin
15376 guint protocol_version:4;
15383 struct _GdkEventDropEnter
15391 guint protocol_version:4;
15393 guint extended_typelist:1;
15400 struct _GdkEventDropLeave
15408 guint protocol_version:4;
15415 struct _GdkEventDropDataAvailable
15423 guint protocol_version:4;
15429 gchar *data_type; /* MIME type */
15430 gulong data_numbytes;
15436 struct _GdkEventClient
15441 GdkAtom message_type;
15442 gushort data_format;
15450 struct _GdkEventOther
15459 <!-- ***************************************************************** -->
15460 <sect> Code Examples
15461 <!-- ***************************************************************** -->
15463 Below are the code examples that are used in the above text
15464 which are not included in complete form elsewhere.
15466 <!-- ----------------------------------------------------------------- -->
15468 <!-- ----------------------------------------------------------------- -->
15472 /* example-start tictactoe tictactoe.h */
15474 /* GTK - The GIMP Toolkit
15475 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15477 * This library is free software; you can redistribute it and/or
15478 * modify it under the terms of the GNU Library General Public
15479 * License as published by the Free Software Foundation; either
15480 * version 2 of the License, or (at your option) any later version.
15482 * This library is distributed in the hope that it will be useful,
15483 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15484 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15485 * Library General Public License for more details.
15487 * You should have received a copy of the GNU Library General Public
15488 * License along with this library; if not, write to the
15489 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15490 * Boston, MA 02111-1307, USA.
15492 #ifndef __TICTACTOE_H__
15493 #define __TICTACTOE_H__
15496 #include <gdk/gdk.h>
15497 #include <gtk/gtkvbox.h>
15502 #endif /* __cplusplus */
15504 #define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
15505 #define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
15506 #define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
15509 typedef struct _Tictactoe Tictactoe;
15510 typedef struct _TictactoeClass TictactoeClass;
15516 GtkWidget *buttons[3][3];
15519 struct _TictactoeClass
15521 GtkVBoxClass parent_class;
15523 void (* tictactoe) (Tictactoe *ttt);
15526 guint tictactoe_get_type (void);
15527 GtkWidget* tictactoe_new (void);
15528 void tictactoe_clear (Tictactoe *ttt);
15532 #endif /* __cplusplus */
15534 #endif /* __TICTACTOE_H__ */
15539 <!-- ----------------------------------------------------------------- -->
15543 /* example-start tictactoe tictactoe.c */
15545 /* GTK - The GIMP Toolkit
15546 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15548 * This library is free software; you can redistribute it and/or
15549 * modify it under the terms of the GNU Library General Public
15550 * License as published by the Free Software Foundation; either
15551 * version 2 of the License, or (at your option) any later version.
15553 * This library is distributed in the hope that it will be useful,
15554 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15555 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15556 * Library General Public License for more details.
15558 * You should have received a copy of the GNU Library General Public
15559 * License along with this library; if not, write to the
15560 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15561 * Boston, MA 02111-1307, USA.
15563 #include "gtk/gtksignal.h"
15564 #include "gtk/gtktable.h"
15565 #include "gtk/gtktogglebutton.h"
15566 #include "tictactoe.h"
15573 static void tictactoe_class_init (TictactoeClass *klass);
15574 static void tictactoe_init (Tictactoe *ttt);
15575 static void tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt);
15577 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
15580 tictactoe_get_type ()
15582 static guint ttt_type = 0;
15586 GtkTypeInfo ttt_info =
15589 sizeof (Tictactoe),
15590 sizeof (TictactoeClass),
15591 (GtkClassInitFunc) tictactoe_class_init,
15592 (GtkObjectInitFunc) tictactoe_init,
15593 (GtkArgSetFunc) NULL,
15594 (GtkArgGetFunc) NULL
15597 ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
15604 tictactoe_class_init (TictactoeClass *class)
15606 GtkObjectClass *object_class;
15608 object_class = (GtkObjectClass*) class;
15610 tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
15612 object_class->type,
15613 GTK_SIGNAL_OFFSET (TictactoeClass,
15615 gtk_signal_default_marshaller,
15619 gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
15621 class->tictactoe = NULL;
15625 tictactoe_init (Tictactoe *ttt)
15630 table = gtk_table_new (3, 3, TRUE);
15631 gtk_container_add (GTK_CONTAINER(ttt), table);
15632 gtk_widget_show (table);
15637 ttt->buttons[i][j] = gtk_toggle_button_new ();
15638 gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
15640 gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
15641 GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
15642 gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
15643 gtk_widget_show (ttt->buttons[i][j]);
15650 return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
15654 tictactoe_clear (Tictactoe *ttt)
15661 gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
15662 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
15664 gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
15669 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
15673 static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
15674 { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
15675 { 0, 1, 2 }, { 0, 1, 2 } };
15676 static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
15677 { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
15678 { 0, 1, 2 }, { 2, 1, 0 } };
15680 int success, found;
15682 for (k=0; k<8; k++)
15689 success = success &&
15690 GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
15692 ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
15695 if (success && found)
15697 gtk_signal_emit (GTK_OBJECT (ttt),
15698 tictactoe_signals[TICTACTOE_SIGNAL]);
15707 <!-- ----------------------------------------------------------------- -->
15711 /* example-start tictactoe ttt_test.c */
15713 #include <gtk/gtk.h>
15714 #include "tictactoe.h"
15717 win (GtkWidget *widget, gpointer data)
15719 g_print ("Yay!\n");
15720 tictactoe_clear (TICTACTOE (widget));
15724 main (int argc, char *argv[])
15729 gtk_init (&argc, &argv);
15731 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
15733 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
15735 gtk_signal_connect (GTK_OBJECT (window), "destroy",
15736 GTK_SIGNAL_FUNC (gtk_exit), NULL);
15738 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
15740 ttt = tictactoe_new ();
15742 gtk_container_add (GTK_CONTAINER (window), ttt);
15743 gtk_widget_show (ttt);
15745 gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
15746 GTK_SIGNAL_FUNC (win), NULL);
15748 gtk_widget_show (window);
15758 <!-- ----------------------------------------------------------------- -->
15761 <!-- ----------------------------------------------------------------- -->
15765 /* example-start gtkdial gtkdial.h */
15767 /* GTK - The GIMP Toolkit
15768 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15770 * This library is free software; you can redistribute it and/or
15771 * modify it under the terms of the GNU Library General Public
15772 * License as published by the Free Software Foundation; either
15773 * version 2 of the License, or (at your option) any later version.
15775 * This library is distributed in the hope that it will be useful,
15776 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15777 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15778 * Library General Public License for more details.
15780 * You should have received a copy of the GNU Library General Public
15781 * License along with this library; if not, write to the
15782 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15783 * Boston, MA 02111-1307, USA.
15785 #ifndef __GTK_DIAL_H__
15786 #define __GTK_DIAL_H__
15789 #include <gdk/gdk.h>
15790 #include <gtk/gtkadjustment.h>
15791 #include <gtk/gtkwidget.h>
15796 #endif /* __cplusplus */
15799 #define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
15800 #define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
15801 #define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
15804 typedef struct _GtkDial GtkDial;
15805 typedef struct _GtkDialClass GtkDialClass;
15811 /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
15814 /* Button currently pressed or 0 if none */
15817 /* Dimensions of dial components */
15819 gint pointer_width;
15821 /* ID of update timer, or 0 if none */
15824 /* Current angle */
15827 /* Old values from adjustment stored so we know when something changes */
15832 /* The adjustment object that stores the data for this dial */
15833 GtkAdjustment *adjustment;
15836 struct _GtkDialClass
15838 GtkWidgetClass parent_class;
15842 GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
15843 guint gtk_dial_get_type (void);
15844 GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
15845 void gtk_dial_set_update_policy (GtkDial *dial,
15846 GtkUpdateType policy);
15848 void gtk_dial_set_adjustment (GtkDial *dial,
15849 GtkAdjustment *adjustment);
15852 #endif /* __cplusplus */
15855 #endif /* __GTK_DIAL_H__ */
15859 <!-- ----------------------------------------------------------------- -->
15863 /* example-start gtkdial gtkdial.c */
15865 /* GTK - The GIMP Toolkit
15866 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15868 * This library is free software; you can redistribute it and/or
15869 * modify it under the terms of the GNU Library General Public
15870 * License as published by the Free Software Foundation; either
15871 * version 2 of the License, or (at your option) any later version.
15873 * This library is distributed in the hope that it will be useful,
15874 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15875 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15876 * Library General Public License for more details.
15878 * You should have received a copy of the GNU Library General Public
15879 * License along with this library; if not, write to the
15880 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15881 * Boston, MA 02111-1307, USA.
15885 #include <gtk/gtkmain.h>
15886 #include <gtk/gtksignal.h>
15888 #include "gtkdial.h"
15890 #define SCROLL_DELAY_LENGTH 300
15891 #define DIAL_DEFAULT_SIZE 100
15893 /* Forward declarations */
15895 static void gtk_dial_class_init (GtkDialClass *klass);
15896 static void gtk_dial_init (GtkDial *dial);
15897 static void gtk_dial_destroy (GtkObject *object);
15898 static void gtk_dial_realize (GtkWidget *widget);
15899 static void gtk_dial_size_request (GtkWidget *widget,
15900 GtkRequisition *requisition);
15901 static void gtk_dial_size_allocate (GtkWidget *widget,
15902 GtkAllocation *allocation);
15903 static gint gtk_dial_expose (GtkWidget *widget,
15904 GdkEventExpose *event);
15905 static gint gtk_dial_button_press (GtkWidget *widget,
15906 GdkEventButton *event);
15907 static gint gtk_dial_button_release (GtkWidget *widget,
15908 GdkEventButton *event);
15909 static gint gtk_dial_motion_notify (GtkWidget *widget,
15910 GdkEventMotion *event);
15911 static gint gtk_dial_timer (GtkDial *dial);
15913 static void gtk_dial_update_mouse (GtkDial *dial, gint x, gint y);
15914 static void gtk_dial_update (GtkDial *dial);
15915 static void gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
15917 static void gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
15922 static GtkWidgetClass *parent_class = NULL;
15925 gtk_dial_get_type ()
15927 static guint dial_type = 0;
15931 GtkTypeInfo dial_info =
15935 sizeof (GtkDialClass),
15936 (GtkClassInitFunc) gtk_dial_class_init,
15937 (GtkObjectInitFunc) gtk_dial_init,
15938 (GtkArgSetFunc) NULL,
15939 (GtkArgGetFunc) NULL,
15942 dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info);
15949 gtk_dial_class_init (GtkDialClass *class)
15951 GtkObjectClass *object_class;
15952 GtkWidgetClass *widget_class;
15954 object_class = (GtkObjectClass*) class;
15955 widget_class = (GtkWidgetClass*) class;
15957 parent_class = gtk_type_class (gtk_widget_get_type ());
15959 object_class->destroy = gtk_dial_destroy;
15961 widget_class->realize = gtk_dial_realize;
15962 widget_class->expose_event = gtk_dial_expose;
15963 widget_class->size_request = gtk_dial_size_request;
15964 widget_class->size_allocate = gtk_dial_size_allocate;
15965 widget_class->button_press_event = gtk_dial_button_press;
15966 widget_class->button_release_event = gtk_dial_button_release;
15967 widget_class->motion_notify_event = gtk_dial_motion_notify;
15971 gtk_dial_init (GtkDial *dial)
15974 dial->policy = GTK_UPDATE_CONTINUOUS;
15977 dial->pointer_width = 0;
15979 dial->old_value = 0.0;
15980 dial->old_lower = 0.0;
15981 dial->old_upper = 0.0;
15982 dial->adjustment = NULL;
15986 gtk_dial_new (GtkAdjustment *adjustment)
15990 dial = gtk_type_new (gtk_dial_get_type ());
15993 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0,
15996 gtk_dial_set_adjustment (dial, adjustment);
15998 return GTK_WIDGET (dial);
16002 gtk_dial_destroy (GtkObject *object)
16006 g_return_if_fail (object != NULL);
16007 g_return_if_fail (GTK_IS_DIAL (object));
16009 dial = GTK_DIAL (object);
16011 if (dial->adjustment)
16012 gtk_object_unref (GTK_OBJECT (dial->adjustment));
16014 if (GTK_OBJECT_CLASS (parent_class)->destroy)
16015 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
16019 gtk_dial_get_adjustment (GtkDial *dial)
16021 g_return_val_if_fail (dial != NULL, NULL);
16022 g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
16024 return dial->adjustment;
16028 gtk_dial_set_update_policy (GtkDial *dial,
16029 GtkUpdateType policy)
16031 g_return_if_fail (dial != NULL);
16032 g_return_if_fail (GTK_IS_DIAL (dial));
16034 dial->policy = policy;
16038 gtk_dial_set_adjustment (GtkDial *dial,
16039 GtkAdjustment *adjustment)
16041 g_return_if_fail (dial != NULL);
16042 g_return_if_fail (GTK_IS_DIAL (dial));
16044 if (dial->adjustment)
16046 gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment),
16048 gtk_object_unref (GTK_OBJECT (dial->adjustment));
16051 dial->adjustment = adjustment;
16052 gtk_object_ref (GTK_OBJECT (dial->adjustment));
16054 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
16055 (GtkSignalFunc) gtk_dial_adjustment_changed,
16057 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
16058 (GtkSignalFunc) gtk_dial_adjustment_value_changed,
16061 dial->old_value = adjustment->value;
16062 dial->old_lower = adjustment->lower;
16063 dial->old_upper = adjustment->upper;
16065 gtk_dial_update (dial);
16069 gtk_dial_realize (GtkWidget *widget)
16072 GdkWindowAttr attributes;
16073 gint attributes_mask;
16075 g_return_if_fail (widget != NULL);
16076 g_return_if_fail (GTK_IS_DIAL (widget));
16078 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
16079 dial = GTK_DIAL (widget);
16081 attributes.x = widget->allocation.x;
16082 attributes.y = widget->allocation.y;
16083 attributes.width = widget->allocation.width;
16084 attributes.height = widget->allocation.height;
16085 attributes.wclass = GDK_INPUT_OUTPUT;
16086 attributes.window_type = GDK_WINDOW_CHILD;
16087 attributes.event_mask = gtk_widget_get_events (widget) |
16088 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
16089 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
16090 GDK_POINTER_MOTION_HINT_MASK;
16091 attributes.visual = gtk_widget_get_visual (widget);
16092 attributes.colormap = gtk_widget_get_colormap (widget);
16094 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
16095 widget->window = gdk_window_new (widget->parent->window,
16099 widget->style = gtk_style_attach (widget->style, widget->window);
16101 gdk_window_set_user_data (widget->window, widget);
16103 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
16107 gtk_dial_size_request (GtkWidget *widget,
16108 GtkRequisition *requisition)
16110 requisition->width = DIAL_DEFAULT_SIZE;
16111 requisition->height = DIAL_DEFAULT_SIZE;
16115 gtk_dial_size_allocate (GtkWidget *widget,
16116 GtkAllocation *allocation)
16120 g_return_if_fail (widget != NULL);
16121 g_return_if_fail (GTK_IS_DIAL (widget));
16122 g_return_if_fail (allocation != NULL);
16124 widget->allocation = *allocation;
16125 dial = GTK_DIAL (widget);
16127 if (GTK_WIDGET_REALIZED (widget))
16130 gdk_window_move_resize (widget->window,
16131 allocation->x, allocation->y,
16132 allocation->width, allocation->height);
16135 dial->radius = MIN(allocation->width,allocation->height) * 0.45;
16136 dial->pointer_width = dial->radius / 5;
16140 gtk_dial_expose (GtkWidget *widget,
16141 GdkEventExpose *event)
16144 GdkPoint points[3];
16151 g_return_val_if_fail (widget != NULL, FALSE);
16152 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16153 g_return_val_if_fail (event != NULL, FALSE);
16155 if (event->count > 0)
16158 dial = GTK_DIAL (widget);
16160 gdk_window_clear_area (widget->window,
16162 widget->allocation.width,
16163 widget->allocation.height);
16165 xc = widget->allocation.width/2;
16166 yc = widget->allocation.height/2;
16170 for (i=0; i<25; i++)
16172 theta = (i*M_PI/18. - M_PI/6.);
16176 tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
16178 gdk_draw_line (widget->window,
16179 widget->style->fg_gc[widget->state],
16180 xc + c*(dial->radius - tick_length),
16181 yc - s*(dial->radius - tick_length),
16182 xc + c*dial->radius,
16183 yc - s*dial->radius);
16188 s = sin(dial->angle);
16189 c = cos(dial->angle);
16192 points[0].x = xc + s*dial->pointer_width/2;
16193 points[0].y = yc + c*dial->pointer_width/2;
16194 points[1].x = xc + c*dial->radius;
16195 points[1].y = yc - s*dial->radius;
16196 points[2].x = xc - s*dial->pointer_width/2;
16197 points[2].y = yc - c*dial->pointer_width/2;
16199 gtk_draw_polygon (widget->style,
16210 gtk_dial_button_press (GtkWidget *widget,
16211 GdkEventButton *event)
16217 double d_perpendicular;
16219 g_return_val_if_fail (widget != NULL, FALSE);
16220 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16221 g_return_val_if_fail (event != NULL, FALSE);
16223 dial = GTK_DIAL (widget);
16225 /* Determine if button press was within pointer region - we
16226 do this by computing the parallel and perpendicular distance of
16227 the point where the mouse was pressed from the line passing through
16230 dx = event->x - widget->allocation.width / 2;
16231 dy = widget->allocation.height / 2 - event->y;
16233 s = sin(dial->angle);
16234 c = cos(dial->angle);
16236 d_parallel = s*dy + c*dx;
16237 d_perpendicular = fabs(s*dx - c*dy);
16239 if (!dial->button &&
16240 (d_perpendicular < dial->pointer_width/2) &&
16241 (d_parallel > - dial->pointer_width))
16243 gtk_grab_add (widget);
16245 dial->button = event->button;
16247 gtk_dial_update_mouse (dial, event->x, event->y);
16254 gtk_dial_button_release (GtkWidget *widget,
16255 GdkEventButton *event)
16259 g_return_val_if_fail (widget != NULL, FALSE);
16260 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16261 g_return_val_if_fail (event != NULL, FALSE);
16263 dial = GTK_DIAL (widget);
16265 if (dial->button == event->button)
16267 gtk_grab_remove (widget);
16271 if (dial->policy == GTK_UPDATE_DELAYED)
16272 gtk_timeout_remove (dial->timer);
16274 if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
16275 (dial->old_value != dial->adjustment->value))
16276 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment),
16284 gtk_dial_motion_notify (GtkWidget *widget,
16285 GdkEventMotion *event)
16288 GdkModifierType mods;
16291 g_return_val_if_fail (widget != NULL, FALSE);
16292 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16293 g_return_val_if_fail (event != NULL, FALSE);
16295 dial = GTK_DIAL (widget);
16297 if (dial->button != 0)
16302 if (event->is_hint || (event->window != widget->window))
16303 gdk_window_get_pointer (widget->window, &x, &y, &mods);
16305 switch (dial->button)
16308 mask = GDK_BUTTON1_MASK;
16311 mask = GDK_BUTTON2_MASK;
16314 mask = GDK_BUTTON3_MASK;
16321 if (mods & mask)
16322 gtk_dial_update_mouse (dial, x,y);
16329 gtk_dial_timer (GtkDial *dial)
16331 g_return_val_if_fail (dial != NULL, FALSE);
16332 g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
16334 if (dial->policy == GTK_UPDATE_DELAYED)
16335 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment),
16342 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
16347 g_return_if_fail (dial != NULL);
16348 g_return_if_fail (GTK_IS_DIAL (dial));
16350 xc = GTK_WIDGET(dial)->allocation.width / 2;
16351 yc = GTK_WIDGET(dial)->allocation.height / 2;
16353 old_value = dial->adjustment->value;
16354 dial->angle = atan2(yc-y, x-xc);
16356 if (dial->angle < -M_PI/2.)
16357 dial->angle += 2*M_PI;
16359 if (dial->angle < -M_PI/6)
16360 dial->angle = -M_PI/6;
16362 if (dial->angle > 7.*M_PI/6.)
16363 dial->angle = 7.*M_PI/6.;
16365 dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
16366 (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
16368 if (dial->adjustment->value != old_value)
16370 if (dial->policy == GTK_UPDATE_CONTINUOUS)
16372 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment),
16377 gtk_widget_draw (GTK_WIDGET(dial), NULL);
16379 if (dial->policy == GTK_UPDATE_DELAYED)
16382 gtk_timeout_remove (dial->timer);
16384 dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
16385 (GtkFunction) gtk_dial_timer,
16393 gtk_dial_update (GtkDial *dial)
16397 g_return_if_fail (dial != NULL);
16398 g_return_if_fail (GTK_IS_DIAL (dial));
16400 new_value = dial->adjustment->value;
16402 if (new_value < dial->adjustment->lower)
16403 new_value = dial->adjustment->lower;
16405 if (new_value > dial->adjustment->upper)
16406 new_value = dial->adjustment->upper;
16408 if (new_value != dial->adjustment->value)
16410 dial->adjustment->value = new_value;
16411 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
16414 dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) *
16416 (dial->adjustment->upper - dial->adjustment->lower);
16418 gtk_widget_draw (GTK_WIDGET(dial), NULL);
16422 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
16427 g_return_if_fail (adjustment != NULL);
16428 g_return_if_fail (data != NULL);
16430 dial = GTK_DIAL (data);
16432 if ((dial->old_value != adjustment->value) ||
16433 (dial->old_lower != adjustment->lower) ||
16434 (dial->old_upper != adjustment->upper))
16436 gtk_dial_update (dial);
16438 dial->old_value = adjustment->value;
16439 dial->old_lower = adjustment->lower;
16440 dial->old_upper = adjustment->upper;
16445 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
16450 g_return_if_fail (adjustment != NULL);
16451 g_return_if_fail (data != NULL);
16453 dial = GTK_DIAL (data);
16455 if (dial->old_value != adjustment->value)
16457 gtk_dial_update (dial);
16459 dial->old_value = adjustment->value;
16465 <!-- ----------------------------------------------------------------- -->
16469 /* example-start scribble-simple scribble-simple.c */
16471 /* GTK - The GIMP Toolkit
16472 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
16474 * This library is free software; you can redistribute it and/or
16475 * modify it under the terms of the GNU Library General Public
16476 * License as published by the Free Software Foundation; either
16477 * version 2 of the License, or (at your option) any later version.
16479 * This library is distributed in the hope that it will be useful,
16480 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16481 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16482 * Library General Public License for more details.
16484 * You should have received a copy of the GNU Library General Public
16485 * License along with this library; if not, write to the
16486 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16487 * Boston, MA 02111-1307, USA.
16490 #include <gtk/gtk.h>
16492 /* Backing pixmap for drawing area */
16493 static GdkPixmap *pixmap = NULL;
16495 /* Create a new backing pixmap of the appropriate size */
16497 configure_event (GtkWidget *widget, GdkEventConfigure *event)
16500 gdk_pixmap_unref(pixmap);
16502 pixmap = gdk_pixmap_new(widget->window,
16503 widget->allocation.width,
16504 widget->allocation.height,
16506 gdk_draw_rectangle (pixmap,
16507 widget->style->white_gc,
16510 widget->allocation.width,
16511 widget->allocation.height);
16516 /* Redraw the screen from the backing pixmap */
16518 expose_event (GtkWidget *widget, GdkEventExpose *event)
16520 gdk_draw_pixmap(widget->window,
16521 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
16523 event->area.x, event->area.y,
16524 event->area.x, event->area.y,
16525 event->area.width, event->area.height);
16530 /* Draw a rectangle on the screen */
16532 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
16534 GdkRectangle update_rect;
16536 update_rect.x = x - 5;
16537 update_rect.y = y - 5;
16538 update_rect.width = 10;
16539 update_rect.height = 10;
16540 gdk_draw_rectangle (pixmap,
16541 widget->style->black_gc,
16543 update_rect.x, update_rect.y,
16544 update_rect.width, update_rect.height);
16545 gtk_widget_draw (widget, &update_rect);
16549 button_press_event (GtkWidget *widget, GdkEventButton *event)
16551 if (event->button == 1 && pixmap != NULL)
16552 draw_brush (widget, event->x, event->y);
16558 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
16561 GdkModifierType state;
16563 if (event->is_hint)
16564 gdk_window_get_pointer (event->window, &x, &y, &state);
16569 state = event->state;
16572 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
16573 draw_brush (widget, x, y);
16585 main (int argc, char *argv[])
16588 GtkWidget *drawing_area;
16593 gtk_init (&argc, &argv);
16595 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
16596 gtk_widget_set_name (window, "Test Input");
16598 vbox = gtk_vbox_new (FALSE, 0);
16599 gtk_container_add (GTK_CONTAINER (window), vbox);
16600 gtk_widget_show (vbox);
16602 gtk_signal_connect (GTK_OBJECT (window), "destroy",
16603 GTK_SIGNAL_FUNC (quit), NULL);
16605 /* Create the drawing area */
16607 drawing_area = gtk_drawing_area_new ();
16608 gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200);
16609 gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
16611 gtk_widget_show (drawing_area);
16613 /* Signals used to handle backing pixmap */
16615 gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
16616 (GtkSignalFunc) expose_event, NULL);
16617 gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
16618 (GtkSignalFunc) configure_event, NULL);
16620 /* Event signals */
16622 gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
16623 (GtkSignalFunc) motion_notify_event, NULL);
16624 gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
16625 (GtkSignalFunc) button_press_event, NULL);
16627 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
16628 | GDK_LEAVE_NOTIFY_MASK
16629 | GDK_BUTTON_PRESS_MASK
16630 | GDK_POINTER_MOTION_MASK
16631 | GDK_POINTER_MOTION_HINT_MASK);
16633 /* .. And a quit button */
16634 button = gtk_button_new_with_label ("Quit");
16635 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
16637 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
16638 GTK_SIGNAL_FUNC (gtk_widget_destroy),
16639 GTK_OBJECT (window));
16640 gtk_widget_show (button);
16642 gtk_widget_show (window);
16651 <!-- ***************************************************************** -->
16653 <!-- ***************************************************************** -->
16655 NOTE: The GtkList widget has been superseded by the GtkCList
16656 widget. It is detailed here just for completeness.
16658 The GtkList widget is designed to act as a vertical container for
16659 widgets that should be of the type GtkListItem.
16661 A GtkList widget has its own window to receive events and its own
16662 background color which is usually white. As it is directly derived
16663 from a GtkContainer it can be treated as such by using the
16664 GTK_CONTAINER(List) macro, see the GtkContainer widget for more on
16665 this. One should already be familiar with the usage of a GList and
16666 its related functions g_list_*() to be able to use the GtkList widget
16669 There is one field inside the structure definition of the GtkList
16670 widget that will be of greater interest to us, this is:
16677 guint selection_mode;
16682 The selection field of a GtkList points to a linked list of all items
16683 that are currently selected, or NULL if the selection is empty. So to
16684 learn about the current selection we read the GTK_LIST()->selection
16685 field, but do not modify it since the internal fields are maintained
16686 by the gtk_list_*() functions.
16688 The selection_mode of the GtkList determines the selection facilities
16689 of a GtkList and therefore the contents of the GTK_LIST()->selection
16690 field. The selection_mode may be one of the following:
16693 <item> GTK_SELECTION_SINGLE - The selection is either NULL
16694 or contains a GList pointer
16695 for a single selected item.
16697 <item> GTK_SELECTION_BROWSE - The selection is NULL if the list
16698 contains no widgets or insensitive
16699 ones only, otherwise it contains
16700 a GList pointer for one GList
16701 structure, and therefore exactly
16704 <item> GTK_SELECTION_MULTIPLE - The selection is NULL if no list
16705 items are selected or a GList pointer
16706 for the first selected item. That
16707 in turn points to a GList structure
16708 for the second selected item and so
16711 <item> GTK_SELECTION_EXTENDED - The selection is always NULL.
16714 The default is GTK_SELECTION_MULTIPLE.
16716 <!-- ----------------------------------------------------------------- -->
16720 void selection_changed( GtkList *list );
16723 This signal will be invoked whenever the selection field of a GtkList
16724 has changed. This happens when a child of the GtkList got selected or
16728 void select_child( GtkList *list,
16732 This signal is invoked when a child of the GtkList is about to get
16733 selected. This happens mainly on calls to gtk_list_select_item(),
16734 gtk_list_select_child(), button presses and sometimes indirectly
16735 triggered on some else occasions where children get added to or
16736 removed from the GtkList.
16739 void unselect_child( GtkList *list,
16740 GtkWidget *child );
16743 This signal is invoked when a child of the GtkList is about to get
16744 deselected. This happens mainly on calls to gtk_list_unselect_item(),
16745 gtk_list_unselect_child(), button presses and sometimes indirectly
16746 triggered on some else occasions where children get added to or
16747 removed from the GtkList.
16749 <!-- ----------------------------------------------------------------- -->
16753 guint gtk_list_get_type( void );
16756 Returns the `GtkList' type identifier.
16759 GtkWidget *gtk_list_new( void );
16762 Create a new GtkList object. The new widget is returned as a pointer
16763 to a GtkWidget object. NULL is returned on failure.
16766 void gtk_list_insert_items( GtkList *list,
16771 Insert list items into the list, starting at <tt/position/.
16772 <tt/items/ is a doubly linked list where each nodes data pointer is
16773 expected to point to a newly created GtkListItem. The GList nodes of
16774 <tt/items/ are taken over by the list.
16777 void gtk_list_append_items( GtkList *list,
16781 Insert list items just like gtk_list_insert_items() at the end of the
16782 list. The GList nodes of <tt/items/ are taken over by the list.
16785 void gtk_list_prepend_items( GtkList *list,
16789 Insert list items just like gtk_list_insert_items() at the very
16790 beginning of the list. The GList nodes of <tt/items/ are taken over by
16794 void gtk_list_remove_items( GtkList *list,
16798 Remove list items from the list. <tt/items/ is a doubly linked list
16799 where each nodes data pointer is expected to point to a direct child
16800 of list. It is the callers responsibility to make a call to
16801 g_list_free(items) afterwards. Also the caller has to destroy the list
16805 void gtk_list_clear_items( GtkList *list,
16810 Remove and destroy list items from the list. A widget is affected if
16811 its current position within the list is in the range specified by
16812 <tt/start/ and <tt/end/.
16815 void gtk_list_select_item( GtkList *list,
16819 Invoke the select_child signal for a list item specified through its
16820 current position within the list.
16823 void gtk_list_unselect_item( GtkList *list,
16827 Invoke the unselect_child signal for a list item specified through its
16828 current position within the list.
16831 void gtk_list_select_child( GtkList *list,
16835 Invoke the select_child signal for the specified child.
16838 void gtk_list_unselect_child( GtkList *list,
16842 Invoke the unselect_child signal for the specified child.
16845 gint gtk_list_child_position( GtkList *list,
16849 Return the position of <tt/child/ within the list. "-1" is returned on
16853 void gtk_list_set_selection_mode( GtkList *list,
16854 GtkSelectionMode mode );
16857 Set the selection mode MODE which can be of GTK_SELECTION_SINGLE,
16858 GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE or
16859 GTK_SELECTION_EXTENDED.
16862 GtkList *GTK_LIST( gpointer obj );
16865 Cast a generic pointer to `GtkList *'. *Note Standard Macros::, for
16869 GtkListClass *GTK_LIST_CLASS( gpointer class);
16872 Cast a generic pointer to `GtkListClass*'. *Note Standard Macros::,
16876 gint GTK_IS_LIST( gpointer obj);
16879 Determine if a generic pointer refers to a `GtkList' object. *Note
16880 Standard Macros::, for more info.
16882 <!-- ----------------------------------------------------------------- -->
16885 Following is an example program that will print out the changes of the
16886 selection of a GtkList, and lets you "arrest" list items into a prison
16887 by selecting them with the rightmost mouse button.
16890 /* example-start list list.c */
16892 /* Include the gtk+ header files
16893 * Include stdio.h, we need that for the printf() function
16895 #include <gtk/gtk.h>
16898 /* This is our data identification string to store
16899 * data in list items
16901 const gchar *list_item_data_key="list_item_data";
16904 /* prototypes for signal handler that we are going to connect
16905 * to the GtkList widget
16907 static void sigh_print_selection( GtkWidget *gtklist,
16908 gpointer func_data);
16910 static void sigh_button_event( GtkWidget *gtklist,
16911 GdkEventButton *event,
16912 GtkWidget *frame );
16915 /* Main function to set up the user interface */
16917 gint main (int argc,
16920 GtkWidget *separator;
16923 GtkWidget *scrolled_window;
16925 GtkWidget *gtklist;
16927 GtkWidget *list_item;
16933 /* Initialize gtk+ (and subsequently gdk) */
16935 gtk_init(&argc, &argv);
16938 /* Create a window to put all the widgets in
16939 * connect gtk_main_quit() to the "destroy" event of
16940 * the window to handle window manager close-window-events
16942 window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
16943 gtk_window_set_title(GTK_WINDOW(window), "GtkList Example");
16944 gtk_signal_connect(GTK_OBJECT(window),
16946 GTK_SIGNAL_FUNC(gtk_main_quit),
16950 /* Inside the window we need a box to arrange the widgets
16952 vbox=gtk_vbox_new(FALSE, 5);
16953 gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
16954 gtk_container_add(GTK_CONTAINER(window), vbox);
16955 gtk_widget_show(vbox);
16957 /* This is the scrolled window to put the GtkList widget inside */
16958 scrolled_window=gtk_scrolled_window_new(NULL, NULL);
16959 gtk_widget_set_usize(scrolled_window, 250, 150);
16960 gtk_container_add(GTK_CONTAINER(vbox), scrolled_window);
16961 gtk_widget_show(scrolled_window);
16963 /* Create the GtkList widget.
16964 * Connect the sigh_print_selection() signal handler
16965 * function to the "selection_changed" signal of the GtkList
16966 * to print out the selected items each time the selection
16968 gtklist=gtk_list_new();
16969 gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(scrolled_window),
16971 gtk_widget_show(gtklist);
16972 gtk_signal_connect(GTK_OBJECT(gtklist),
16973 "selection_changed",
16974 GTK_SIGNAL_FUNC(sigh_print_selection),
16977 /* We create a "Prison" to put a list item in ;) */
16978 frame=gtk_frame_new("Prison");
16979 gtk_widget_set_usize(frame, 200, 50);
16980 gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
16981 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
16982 gtk_container_add(GTK_CONTAINER(vbox), frame);
16983 gtk_widget_show(frame);
16985 /* Connect the sigh_button_event() signal handler to the GtkList
16986 * which will handle the "arresting" of list items
16988 gtk_signal_connect(GTK_OBJECT(gtklist),
16989 "button_release_event",
16990 GTK_SIGNAL_FUNC(sigh_button_event),
16993 /* Create a separator */
16994 separator=gtk_hseparator_new();
16995 gtk_container_add(GTK_CONTAINER(vbox), separator);
16996 gtk_widget_show(separator);
16998 /* Finally create a button and connect its "clicked" signal
16999 * to the destruction of the window */
17000 button=gtk_button_new_with_label("Close");
17001 gtk_container_add(GTK_CONTAINER(vbox), button);
17002 gtk_widget_show(button);
17003 gtk_signal_connect_object(GTK_OBJECT(button),
17005 GTK_SIGNAL_FUNC(gtk_widget_destroy),
17006 GTK_OBJECT(window));
17009 /* Now we create 5 list items, each having its own
17010 * label and add them to the GtkList using gtk_container_add()
17011 * Also we query the text string from the label and
17012 * associate it with the list_item_data_key for each list item
17014 for (i=0; i<5; i++) {
17018 sprintf(buffer, "ListItemContainer with Label #%d", i);
17019 label=gtk_label_new(buffer);
17020 list_item=gtk_list_item_new();
17021 gtk_container_add(GTK_CONTAINER(list_item), label);
17022 gtk_widget_show(label);
17023 gtk_container_add(GTK_CONTAINER(gtklist), list_item);
17024 gtk_widget_show(list_item);
17025 gtk_label_get(GTK_LABEL(label), &string);
17026 gtk_object_set_data(GTK_OBJECT(list_item),
17027 list_item_data_key,
17030 /* Here, we are creating another 5 labels, this time
17031 * we use gtk_list_item_new_with_label() for the creation
17032 * we can't query the text string from the label because
17033 * we don't have the labels pointer and therefore
17034 * we just associate the list_item_data_key of each
17035 * list item with the same text string.
17036 * For adding of the list items we put them all into a doubly
17037 * linked list (GList), and then add them by a single call to
17038 * gtk_list_append_items().
17039 * Because we use g_list_prepend() to put the items into the
17040 * doubly linked list, their order will be descending (instead
17041 * of ascending when using g_list_append())
17044 for (; i<10; i++) {
17045 sprintf(buffer, "List Item with Label %d", i);
17046 list_item=gtk_list_item_new_with_label(buffer);
17047 dlist=g_list_prepend(dlist, list_item);
17048 gtk_widget_show(list_item);
17049 gtk_object_set_data(GTK_OBJECT(list_item),
17050 list_item_data_key,
17051 "ListItem with integrated Label");
17053 gtk_list_append_items(GTK_LIST(gtklist), dlist);
17055 /* Finally we want to see the window, don't we? ;) */
17056 gtk_widget_show(window);
17058 /* Fire up the main event loop of gtk */
17061 /* We get here after gtk_main_quit() has been called which
17062 * happens if the main window gets destroyed
17067 /* This is the signal handler that got connected to button
17068 * press/release events of the GtkList
17070 void sigh_button_event( GtkWidget *gtklist,
17071 GdkEventButton *event,
17074 /* We only do something if the third (rightmost mouse button
17077 if (event->type==GDK_BUTTON_RELEASE &&
17078 event->button==3) {
17079 GList *dlist, *free_list;
17080 GtkWidget *new_prisoner;
17082 /* Fetch the currently selected list item which
17083 * will be our next prisoner ;)
17085 dlist=GTK_LIST(gtklist)->selection;
17087 new_prisoner=GTK_WIDGET(dlist->data);
17091 /* Look for already imprisoned list items, we
17092 * will put them back into the list.
17093 * Remember to free the doubly linked list that
17094 * gtk_container_children() returns
17096 dlist=gtk_container_children(GTK_CONTAINER(frame));
17099 GtkWidget *list_item;
17101 list_item=dlist->data;
17103 gtk_widget_reparent(list_item, gtklist);
17107 g_list_free(free_list);
17109 /* If we have a new prisoner, remove him from the
17110 * GtkList and put him into the frame "Prison".
17111 * We need to unselect the item first.
17113 if (new_prisoner) {
17114 GList static_dlist;
17116 static_dlist.data=new_prisoner;
17117 static_dlist.next=NULL;
17118 static_dlist.prev=NULL;
17120 gtk_list_unselect_child(GTK_LIST(gtklist),
17122 gtk_widget_reparent(new_prisoner, frame);
17127 /* This is the signal handler that gets called if GtkList
17128 * emits the "selection_changed" signal
17130 void sigh_print_selection( GtkWidget *gtklist,
17131 gpointer func_data)
17135 /* Fetch the doubly linked list of selected items
17136 * of the GtkList, remember to treat this as read-only!
17138 dlist=GTK_LIST(gtklist)->selection;
17140 /* If there are no selected items there is nothing more
17141 * to do than just telling the user so
17144 g_print("Selection cleared\n");
17147 /* Ok, we got a selection and so we print it
17149 g_print("The selection is a ");
17151 /* Get the list item from the doubly linked list
17152 * and then query the data associated with list_item_data_key.
17153 * We then just print it */
17155 GtkObject *list_item;
17156 gchar *item_data_string;
17158 list_item=GTK_OBJECT(dlist->data);
17159 item_data_string=gtk_object_get_data(list_item,
17160 list_item_data_key);
17161 g_print("%s ", item_data_string);
17170 <!-- ----------------------------------------------------------------- -->
17171 <sect1> List Item Widget
17173 The GtkListItem widget is designed to act as a container holding up to
17174 one child, providing functions for selection/deselection just like the
17175 GtkList widget requires them for its children.
17177 A GtkListItem has its own window to receive events and has its own
17178 background color which is usually white.
17180 As it is directly derived from a GtkItem it can be treated as such by
17181 using the GTK_ITEM(ListItem) macro, see the GtkItem widget for more on
17182 this. Usually a GtkListItem just holds a label to identify e.g. a
17183 filename within a GtkList -- therefore the convenience function
17184 gtk_list_item_new_with_label() is provided. The same effect can be
17185 achieved by creating a GtkLabel on its own, setting its alignment to
17186 xalign=0 and yalign=0.5 with a subsequent container addition to the
17189 As one is not forced to add a GtkLabel to a GtkListItem, you could
17190 also add a GtkVBox or a GtkArrow etc. to the GtkListItem.
17192 <!-- ----------------------------------------------------------------- -->
17195 A GtkListItem does not create new signals on its own, but inherits
17196 the signals of a GtkItem. *Note GtkItem::, for more info.
17198 <!-- ----------------------------------------------------------------- -->
17202 guint gtk_list_item_get_type( void );
17205 Returns the `GtkListItem' type identifier.
17208 GtkWidget *gtk_list_item_new( void );
17211 Create a new GtkListItem object. The new widget is returned as a
17212 pointer to a GtkWidget object. NULL is returned on failure.
17215 GtkWidget *gtk_list_item_new_with_label( gchar *label );
17218 Create a new GtkListItem object, having a single GtkLabel as the sole
17219 child. The new widget is returned as a pointer to a GtkWidget
17220 object. NULL is returned on failure.
17223 void gtk_list_item_select( GtkListItem *list_item );
17226 This function is basically a wrapper around a call to gtk_item_select
17227 (GTK_ITEM (list_item)) which will emit the select signal. *Note
17228 GtkItem::, for more info.
17231 void gtk_list_item_deselect( GtkListItem *list_item );
17234 This function is basically a wrapper around a call to
17235 gtk_item_deselect (GTK_ITEM (list_item)) which will emit the deselect
17236 signal. *Note GtkItem::, for more info.
17239 GtkListItem *GTK_LIST_ITEM( gpointer obj );
17242 Cast a generic pointer to `GtkListItem*'. *Note Standard Macros::, for
17246 GtkListItemClass *GTK_LIST_ITEM_CLASS( gpointer class );
17249 Cast a generic pointer to GtkListItemClass*. *Note Standard Macros::,
17253 gint GTK_IS_LIST_ITEM( gpointer obj );
17256 Determine if a generic pointer refers to a `GtkListItem' object.
17257 *Note Standard Macros::, for more info.
17259 <!-- ----------------------------------------------------------------- -->
17262 Please see the GtkList example on this, which covers the usage of a
17263 GtkListItem as well.