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 21st, 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 The adjustment of a progress object can be changed dynamically using:
3458 void gtk_progress_set_adjustment( GtkProgress *progress,
3459 GtkAdjustment *adjustment );
3462 Now that the progress bar has been created we can use it.
3465 void gtk_progress_bar_update( GtkProgressBar *pbar,
3466 gfloat percentage );
3469 The first argument is the progress bar you wish to operate on, and the
3470 second argument is the amount 'completed', meaning the amount the
3471 progress bar has been filled from 0-100%. This is passed to the
3472 function as a real number ranging from 0 to 1.
3474 GTK v1.2 has added new functionality to the progress bar that enables
3475 it to display its value in different ways, and to inform the user of
3476 its current value and its range.
3478 A progress bar may be set to one of a number of orientations using the
3482 void gtk_progress_bar_set_orientation( GtkProgressBar *pbar,
3483 GtkProgressBarOrientation orientation );
3486 Where the <tt/orientation/ argument may take one of the following
3487 values to indicate the direction in which the progress bar moves:
3490 <item> GTK_PROGRESS_LEFT_TO_RIGHT
3491 <item> GTK_PROGRESS_RIGHT_TO_LEFT
3492 <item> GTK_PROGRESS_BOTTOM_TO_TOP
3493 <item> GTK_PROGRESS_TOP_TO_BOTTOM
3496 When used as a measure of how far a process has progressed, the
3497 GtkProgressBar can be set to display its value in either a continuous
3498 or discrete mode. In continuous mode, the progress bar is updated for
3499 each value. In discrete mode, the progress bar is updated in a number
3500 of discrete blocks. The number of blocks is also configurable.
3502 The style of a progress bar can be set using the following function.
3505 void gtk_progress_bar_set_bar_style( GtkProgressBar *pbar,
3506 GtkProgressBarStyle style );
3509 The <tt/style/ parameter can take one of two values:
3512 <item>GTK_PROGRESS_CONTINUOUS
3513 <item>GTK_PROGRESS_DISCRETE
3516 The number of discrete blocks can be set by calling
3519 void gtk_progress_bar_set_discrete_blocks( GtkProgressBar *pbar,
3523 As well as indicating the amount of progress that has occured, the
3524 progress bar may be set to just indicate that there is some
3525 activity. This can be useful in situations where progress cannot be
3526 measured against a value range. Activity mode is not effected by the
3527 bar style that is described above, and overrides it.This mode is
3528 selected by the following function.
3531 void gtk_progress_set_activity_mode( GtkProgress *progress,
3532 guint activity_mode );
3535 The step size of the activity indicator, and the number of blocks are
3536 set using the following functions.
3539 void gtk_progress_bar_set_activity_step( GtkProgressBar *pbar,
3542 void gtk_progress_bar_set_activity_blocks( GtkProgressBar *pbar,
3546 When in continuous mode, the progress bar can also display a
3547 configurable text string within its trough, using the following
3551 void gtk_progress_set_format_string( GtkProgress *progress,
3555 The <tt/format/ argument is similiar to one that would be used in a C
3556 <tt/printf/ statement. The following directives may be used within the
3560 <item> %p - percentage
3562 <item> %l - lower range value
3563 <item> %u - upper range value
3566 The displaying of this text string can be toggled using:
3569 void gtk_progress_set_show_text( GtkProgress *progress,
3573 The <tt/show_text/ argument is a boolean TRUE/FALSE value. The
3574 appearance of the text can be modified further using:
3577 void gtk_progress_set_text_alignment( GtkProgress *progress,
3582 The <tt/x_align/ and <tt/y_align/ arguments take a value between 0.0
3583 and 1.0. Their value indicates the position of the text string within
3584 the trough. Values of 0.0 for both would place the string in the top
3585 left hand corner; values of 0.5 (the default) centres the text, and
3586 values of 1.0 places the text in the lower right hand corner.
3588 The current text setting of a progress object can be retrieved using
3589 the current or a specified adjustment value using the following two
3590 functions. The character string returned by these functions should be
3591 freed by the application (using the g_free() function). These
3592 functions return the formatted string that would be displayed within
3596 gchar *gtk_progress_get_current_text( GtkProgress *progress );
3598 gchar *gtk_progress_get_text_from_value( GtkProgress *progress,
3602 There is yet another way to change the range and value of a progress
3603 object using the following function:
3606 void gtk_progress_configure( GtkProgress *progress,
3612 This function provides quite a simple interface to the range and value
3613 of a progress object.
3615 The remaining functions can be used to get and set the current value
3616 of a progess object in various types and formats:
3619 void gtk_progress_set_percentage( GtkProgress *progress,
3620 gfloat percentage );
3622 void gtk_progress_set_value( GtkProgress *progress,
3625 gfloat gtk_progress_get_value( GtkProgress *progress );
3627 gfloat gtk_progress_get_current_percentage( GtkProgress *progress );
3629 gfloat gtk_progress_get_percentage_from_value( GtkProgress *progress,
3633 These functions are pretty self explanatory. The last function uses
3634 the the adjustment of the specified progess object to compute the
3635 percentage value of the given range value.
3637 Progress Bars are usually used with timeouts or other such functions
3638 (see section on <ref id="sec_timeouts" name="Timeouts, I/O and Idle
3639 Functions">) to give the illusion of multitasking. All will employ the
3640 gtk_progress_bar_update function in the same manner.
3642 Here is an example of the progress bar, updated using timeouts. This
3643 code also shows you how to reset the Progress Bar.
3646 /* example-start progressbar progressbar.c */
3648 #include <gtk/gtk.h>
3650 typedef struct _ProgressData {
3656 /* Update the value of the progress bar so that we get
3658 gint progress_timeout( gpointer data )
3663 /* Calculate the value of the progress bar using the
3664 * value range set in the adjustment object */
3666 new_val = gtk_progress_get_value( GTK_PROGRESS(data) ) + 1;
3668 adj = GTK_PROGRESS (data)->adjustment;
3669 if (new_val > adj->upper)
3670 new_val = adj->lower;
3672 /* Set the new value */
3673 gtk_progress_set_value (GTK_PROGRESS (data), new_val);
3675 /* As this is a timeout function, return TRUE so that it
3676 * continues to get called */
3680 /* Callback that toggles the text display within the progress
3682 void toggle_show_text( GtkWidget *widget,
3683 ProgressData *pdata )
3685 gtk_progress_set_show_text (GTK_PROGRESS (pdata->pbar),
3686 GTK_TOGGLE_BUTTON (widget)->active);
3689 /* Callback that toggles the activity mode of the progress
3691 void toggle_activity_mode( GtkWidget *widget,
3692 ProgressData *pdata )
3694 gtk_progress_set_activity_mode (GTK_PROGRESS (pdata->pbar),
3695 GTK_TOGGLE_BUTTON (widget)->active);
3698 /* Callback that toggles the continuous mode of the progress
3700 void set_continuous_mode( GtkWidget *widget,
3701 ProgressData *pdata )
3703 gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
3704 GTK_PROGRESS_CONTINUOUS);
3707 /* Callback that toggles the discrete mode of the progress
3709 void set_discrete_mode( GtkWidget *widget,
3710 ProgressData *pdata )
3712 gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
3713 GTK_PROGRESS_DISCRETE);
3716 /* Clean up allocated memory and remove the timer */
3717 void destroy_progress( GtkWidget *widget,
3718 ProgressData *pdata)
3720 gtk_timeout_remove (pdata->timer);
3722 pdata->window = NULL;
3730 ProgressData *pdata;
3732 GtkWidget *separator;
3739 gtk_init (&argc, &argv);
3741 /* Allocate memory for the data that is passwd to the callbacks */
3742 pdata = g_malloc( sizeof(ProgressData) );
3744 pdata->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3745 gtk_window_set_policy (GTK_WINDOW (pdata->window), FALSE, FALSE, TRUE);
3747 gtk_signal_connect (GTK_OBJECT (pdata->window), "destroy",
3748 GTK_SIGNAL_FUNC (destroy_progress),
3750 gtk_window_set_title (GTK_WINDOW (pdata->window), "GtkProgressBar");
3751 gtk_container_set_border_width (GTK_CONTAINER (pdata->window), 0);
3753 vbox = gtk_vbox_new (FALSE, 5);
3754 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
3755 gtk_container_add (GTK_CONTAINER (pdata->window), vbox);
3756 gtk_widget_show(vbox);
3758 /* Create a centering alignment object */
3759 align = gtk_alignment_new (0.5, 0.5, 0, 0);
3760 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 5);
3761 gtk_widget_show(align);
3763 /* Create a GtkAdjusment object to hold the range of the
3765 adj = (GtkAdjustment *) gtk_adjustment_new (0, 1, 150, 0, 0, 0);
3767 /* Create the GtkProgressBar using the adjustment */
3768 pdata->pbar = gtk_progress_bar_new_with_adjustment (adj);
3770 /* Set the format of the string that can be displayed in the
3771 * trough of the progress bar:
3774 * %l - lower range value
3775 * %u - upper range value */
3776 gtk_progress_set_format_string (GTK_PROGRESS (pdata->pbar),
3777 "%v from [%l-%u] (=%p%%)");
3778 gtk_container_add (GTK_CONTAINER (align), pdata->pbar);
3779 gtk_widget_show(pdata->pbar);
3781 /* Add a timer callback to update the value of the progress bar */
3782 pdata->timer = gtk_timeout_add (100, progress_timeout, pdata->pbar);
3784 separator = gtk_hseparator_new ();
3785 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
3786 gtk_widget_show(separator);
3788 /* rows, columns, homogeneous */
3789 table = gtk_table_new (2, 3, FALSE);
3790 gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0);
3791 gtk_widget_show(table);
3793 /* Add a check button to select displaying of the trough text */
3794 check = gtk_check_button_new_with_label ("Show text");
3795 gtk_table_attach (GTK_TABLE (table), check, 0, 1, 0, 1,
3796 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3798 gtk_signal_connect (GTK_OBJECT (check), "clicked",
3799 GTK_SIGNAL_FUNC (toggle_show_text),
3801 gtk_widget_show(check);
3803 /* Add a check button to toggle activity mode */
3804 check = gtk_check_button_new_with_label ("Activity mode");
3805 gtk_table_attach (GTK_TABLE (table), check, 0, 1, 1, 2,
3806 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3808 gtk_signal_connect (GTK_OBJECT (check), "clicked",
3809 GTK_SIGNAL_FUNC (toggle_activity_mode),
3811 gtk_widget_show(check);
3813 separator = gtk_vseparator_new ();
3814 gtk_table_attach (GTK_TABLE (table), separator, 1, 2, 0, 2,
3815 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3817 gtk_widget_show(separator);
3819 /* Add a radio button to select continuous display mode */
3820 button = gtk_radio_button_new_with_label (NULL, "Continuous");
3821 gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1,
3822 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3824 gtk_signal_connect (GTK_OBJECT (button), "clicked",
3825 GTK_SIGNAL_FUNC (set_continuous_mode),
3827 gtk_widget_show (button);
3829 /* Add a radio button to select discrete display mode */
3830 button = gtk_radio_button_new_with_label(
3831 gtk_radio_button_group (GTK_RADIO_BUTTON (button)),
3833 gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2,
3834 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3836 gtk_signal_connect (GTK_OBJECT (button), "clicked",
3837 GTK_SIGNAL_FUNC (set_discrete_mode),
3839 gtk_widget_show (button);
3841 separator = gtk_hseparator_new ();
3842 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
3843 gtk_widget_show(separator);
3845 /* Add a button to exit the program */
3846 button = gtk_button_new_with_label ("close");
3847 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
3848 (GtkSignalFunc) gtk_widget_destroy,
3849 GTK_OBJECT (pdata->window));
3850 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
3852 /* This makes it so the button is the default. */
3853 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
3855 /* This grabs this button to be the default button. Simply hitting
3856 * the "Enter" key will cause this button to activate. */
3857 gtk_widget_grab_default (button);
3858 gtk_widget_show(button);
3860 gtk_widget_show (pdata->window);
3869 <!-- ----------------------------------------------------------------- -->
3872 The Dialog widget is very simple, and is actually just a window with a
3873 few things pre-packed into it for you. The structure for a Dialog is:
3881 GtkWidget *action_area;
3885 So you see, it simply creates a window, and then packs a vbox into the
3886 top, then a separator, and then an hbox for the "action_area".
3888 The Dialog widget can be used for pop-up messages to the user, and
3889 other similar tasks. It is really basic, and there is only one
3890 function for the dialog box, which is:
3893 GtkWidget *gtk_dialog_new( void );
3896 So to create a new dialog box, use,
3900 window = gtk_dialog_new ();
3903 This will create the dialog box, and it is now up to you to use it.
3904 you could pack a button in the action_area by doing something like this:
3908 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area),
3909 button, TRUE, TRUE, 0);
3910 gtk_widget_show (button);
3913 And you could add to the vbox area by packing, for instance, a label
3914 in it, try something like this:
3917 label = gtk_label_new ("Dialogs are groovy");
3918 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox),
3919 label, TRUE, TRUE, 0);
3920 gtk_widget_show (label);
3923 As an example in using the dialog box, you could put two buttons in
3924 the action_area, a Cancel button and an Ok button, and a label in the
3925 vbox area, asking the user a question or giving an error etc. Then
3926 you could attach a different signal to each of the buttons and perform
3927 the operation the user selects.
3929 If the simple functionality provided by the default vertical and
3930 horizontal boxes in the two areas does't give you enough control for
3931 your application, then you can simply pack another layout widget into
3932 the boxes provided. For example, you could pack a table into the
3935 <!-- ----------------------------------------------------------------- -->
3936 <sect1> Pixmaps <label id="sec_Pixmaps">
3938 Pixmaps are data structures that contain pictures. These pictures can
3939 be used in various places, but most visibly as icons on the X-Windows
3940 desktop, or as cursors.
3942 A pixmap which only has 2 colors is called a bitmap, and there are a
3943 few additional routines for handling this common special case.
3945 To understand pixmaps, it would help to understand how X-windows
3946 works. Under X-windows, applications do not need to be running on the
3947 same computer that is interacting with the user. Instead, the various
3948 applications, called "clients", all communicate with a program which
3949 displays the graphics and handles the keyboard and mouse. This
3950 program which interacts directly with the user is called a "display
3951 server" or "X server." Since the communication might take place over
3952 a network, it's important to keep some information with the X server.
3953 Pixmaps, for example, are stored in the memory of the X server. This
3954 means that once pixmap values are set, they don't need to keep getting
3955 transmitted over the network; instead a command is sent to "display
3956 pixmap number XYZ here." Even if you aren't using X-windows with GTK
3957 currently, using constructs such as Pixmaps will make your programs
3958 work acceptably under X-windows.
3960 To use pixmaps in GTK, we must first build a GdkPixmap structure using
3961 routines from the GDK layer. Pixmaps can either be created from
3962 in-memory data, or from data read from a file. We'll go through each
3963 of the calls to create a pixmap.
3966 GdkPixmap *gdk_bitmap_create_from_data( GdkWindow *window,
3972 This routine is used to create a single-plane pixmap (2 colors) from
3973 data in memory. Each bit of the data represents whether that pixel is
3974 off or on. Width and height are in pixels. The GdkWindow pointer is
3975 to the current window, since a pixmap resources are meaningful only in
3976 the context of the screen where it is to be displayed.
3979 GdkPixmap *gdk_pixmap_create_from_data( GdkWindow *window,
3988 This is used to create a pixmap of the given depth (number of colors) from
3989 the bitmap data specified. <tt/fg/ and <tt/bg/ are the foreground and
3990 background color to use.
3993 GdkPixmap *gdk_pixmap_create_from_xpm( GdkWindow *window,
3995 GdkColor *transparent_color,
3996 const gchar *filename );
3999 XPM format is a readable pixmap representation for the X Window
4000 System. It is widely used and many different utilities are available
4001 for creating image files in this format. The file specified by
4002 filename must contain an image in that format and it is loaded into
4003 the pixmap structure. The mask specifies which bits of the pixmap are
4004 opaque. All other bits are colored using the color specified by
4005 transparent_color. An example using this follows below.
4008 GdkPixmap *gdk_pixmap_create_from_xpm_d( GdkWindow *window,
4010 GdkColor *transparent_color,
4014 Small images can be incorporated into a program as data in the XPM
4015 format. A pixmap is created using this data, instead of reading it
4016 from a file. An example of such data is
4020 static const char * xpm_data[] = {
4023 ". c #000000000000",
4024 "X c #FFFFFFFFFFFF",
4043 When we're done using a pixmap and not likely to reuse it again soon,
4044 it is a good idea to release the resource using
4045 gdk_pixmap_unref(). Pixmaps should be considered a precious resource.
4047 Once we've created a pixmap, we can display it as a GTK widget. We
4048 must create a GTK pixmap widget to contain the GDK pixmap. This is
4052 GtkWidget *gtk_pixmap_new( GdkPixmap *pixmap,
4056 The other pixmap widget calls are
4059 guint gtk_pixmap_get_type( void );
4061 void gtk_pixmap_set( GtkPixmap *pixmap,
4065 void gtk_pixmap_get( GtkPixmap *pixmap,
4070 gtk_pixmap_set is used to change the pixmap that the widget is currently
4071 managing. Val is the pixmap created using GDK.
4073 The following is an example of using a pixmap in a button.
4076 /* example-start pixmap pixmap.c */
4078 #include <gtk/gtk.h>
4081 /* XPM data of Open-File icon */
4082 static const char * xpm_data[] = {
4085 ". c #000000000000",
4086 "X c #FFFFFFFFFFFF",
4105 /* when invoked (via signal delete_event), terminates the application.
4107 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
4112 /* is invoked when the button is clicked. It just prints a message.
4114 void button_clicked( GtkWidget *widget, gpointer data ) {
4115 printf( "button clicked\n" );
4118 int main( int argc, char *argv[] )
4120 /* GtkWidget is the storage type for widgets */
4121 GtkWidget *window, *pixmapwid, *button;
4126 /* create the main window, and attach delete_event signal to terminating
4128 gtk_init( &argc, &argv );
4129 window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
4130 gtk_signal_connect( GTK_OBJECT (window), "delete_event",
4131 GTK_SIGNAL_FUNC (close_application), NULL );
4132 gtk_container_set_border_width( GTK_CONTAINER (window), 10 );
4133 gtk_widget_show( window );
4135 /* now for the pixmap from gdk */
4136 style = gtk_widget_get_style( window );
4137 pixmap = gdk_pixmap_create_from_xpm_d( window->window, &mask,
4138 &style->bg[GTK_STATE_NORMAL],
4139 (gchar **)xpm_data );
4141 /* a pixmap widget to contain the pixmap */
4142 pixmapwid = gtk_pixmap_new( pixmap, mask );
4143 gtk_widget_show( pixmapwid );
4145 /* a button to contain the pixmap widget */
4146 button = gtk_button_new();
4147 gtk_container_add( GTK_CONTAINER(button), pixmapwid );
4148 gtk_container_add( GTK_CONTAINER(window), button );
4149 gtk_widget_show( button );
4151 gtk_signal_connect( GTK_OBJECT(button), "clicked",
4152 GTK_SIGNAL_FUNC(button_clicked), NULL );
4154 /* show the window */
4162 To load a file from an XPM data file called icon0.xpm in the current
4163 directory, we would have created the pixmap thus
4166 /* load a pixmap from a file */
4167 pixmap = gdk_pixmap_create_from_xpm( window->window, &mask,
4168 &style->bg[GTK_STATE_NORMAL],
4170 pixmapwid = gtk_pixmap_new( pixmap, mask );
4171 gtk_widget_show( pixmapwid );
4172 gtk_container_add( GTK_CONTAINER(window), pixmapwid );
4175 A disadvantage of using pixmaps is that the displayed object is always
4176 rectangular, regardless of the image. We would like to create desktops
4177 and applications with icons that have more natural shapes. For
4178 example, for a game interface, we would like to have round buttons to
4179 push. The way to do this is using shaped windows.
4181 A shaped window is simply a pixmap where the background pixels are
4182 transparent. This way, when the background image is multi-colored, we
4183 don't overwrite it with a rectangular, non-matching border around our
4184 icon. The following example displays a full wheelbarrow image on the
4188 /* example-start wheelbarrow wheelbarrow.c */
4190 #include <gtk/gtk.h>
4193 static char * WheelbarrowFull_xpm[] = {
4196 ". c #DF7DCF3CC71B",
4197 "X c #965875D669A6",
4198 "o c #71C671C671C6",
4199 "O c #A699A289A699",
4200 "+ c #965892489658",
4201 "@ c #8E38410330C2",
4202 "# c #D75C7DF769A6",
4203 "$ c #F7DECF3CC71B",
4204 "% c #96588A288E38",
4205 "& c #A69992489E79",
4206 "* c #8E3886178E38",
4207 "= c #104008200820",
4208 "- c #596510401040",
4209 "; c #C71B30C230C2",
4210 ": c #C71B9A699658",
4211 "> c #618561856185",
4212 ", c #20811C712081",
4213 "< c #104000000000",
4214 "1 c #861720812081",
4215 "2 c #DF7D4D344103",
4216 "3 c #79E769A671C6",
4217 "4 c #861782078617",
4218 "5 c #41033CF34103",
4219 "6 c #000000000000",
4220 "7 c #49241C711040",
4221 "8 c #492445144924",
4222 "9 c #082008200820",
4223 "0 c #69A618611861",
4224 "q c #B6DA71C65144",
4225 "w c #410330C238E3",
4226 "e c #CF3CBAEAB6DA",
4227 "r c #71C6451430C2",
4228 "t c #EFBEDB6CD75C",
4229 "y c #28A208200820",
4230 "u c #186110401040",
4231 "i c #596528A21861",
4232 "p c #71C661855965",
4233 "a c #A69996589658",
4234 "s c #30C228A230C2",
4235 "d c #BEFBA289AEBA",
4236 "f c #596545145144",
4237 "g c #30C230C230C2",
4238 "h c #8E3882078617",
4239 "j c #208118612081",
4240 "k c #38E30C300820",
4241 "l c #30C2208128A2",
4242 "z c #38E328A238E3",
4243 "x c #514438E34924",
4244 "c c #618555555965",
4245 "v c #30C2208130C2",
4246 "b c #38E328A230C2",
4247 "n c #28A228A228A2",
4248 "m c #41032CB228A2",
4249 "M c #104010401040",
4250 "N c #492438E34103",
4251 "B c #28A2208128A2",
4252 "V c #A699596538E3",
4253 "C c #30C21C711040",
4254 "Z c #30C218611040",
4255 "A c #965865955965",
4256 "S c #618534D32081",
4257 "D c #38E31C711040",
4258 "F c #082000000820",
4267 "ty> 459@>+&& ",
4269 "%$;=* *3:.Xa.dfg> ",
4270 "Oh$;ya *3d.a8j,Xe.d3g8+ ",
4271 " Oh$;ka *3d$a8lz,,xxc:.e3g54 ",
4272 " Oh$;kO *pd$%svbzz,sxxxxfX..&wn> ",
4273 " Oh$@mO *3dthwlsslszjzxxxxxxx3:td8M4 ",
4274 " Oh$@g& *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B* ",
4275 " Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5& ",
4276 " Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM* ",
4277 " OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
4278 " 2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
4279 " :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
4280 " +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
4281 " *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&en",
4282 " p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>",
4283 " OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ",
4284 " 3206Bwxxszx%et.eaAp77m77mmmf3&eeeg* ",
4285 " @26MvzxNzvlbwfpdettttttttttt.c,n& ",
4286 " *;16=lsNwwNwgsvslbwwvccc3pcfu<o ",
4287 " p;<69BvwwsszslllbBlllllllu<5+ ",
4288 " OS0y6FBlvvvzvzss,u=Blllj=54 ",
4289 " c1-699Blvlllllu7k96MMMg4 ",
4290 " *10y8n6FjvllllB<166668 ",
4291 " S-kg+>666<M<996-y6n<8* ",
4292 " p71=4 m69996kD8Z-66698&& ",
4293 " &i0ycm6n4 ogk17,0<6666g ",
4294 " N-k-<> >=01-kuu666> ",
4295 " ,6ky& &46-10ul,66, ",
4296 " Ou0<> o66y<ulw<66& ",
4297 " *kk5 >66By7=xu664 ",
4298 " <<M4 466lj<Mxu66o ",
4299 " *>> +66uv,zN666* ",
4309 /* When invoked (via signal delete_event), terminates the application */
4310 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
4314 int main (int argc, char *argv[])
4316 /* GtkWidget is the storage type for widgets */
4317 GtkWidget *window, *pixmap, *fixed;
4318 GdkPixmap *gdk_pixmap;
4323 /* Create the main window, and attach delete_event signal to terminate
4324 * the application. Note that the main window will not have a titlebar
4325 * since we're making it a popup. */
4326 gtk_init (&argc, &argv);
4327 window = gtk_window_new( GTK_WINDOW_POPUP );
4328 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
4329 GTK_SIGNAL_FUNC (close_application), NULL);
4330 gtk_widget_show (window);
4332 /* Now for the pixmap and the pixmap widget */
4333 style = gtk_widget_get_default_style();
4334 gc = style->black_gc;
4335 gdk_pixmap = gdk_pixmap_create_from_xpm_d( window->window, &mask,
4336 &style->bg[GTK_STATE_NORMAL],
4337 WheelbarrowFull_xpm );
4338 pixmap = gtk_pixmap_new( gdk_pixmap, mask );
4339 gtk_widget_show( pixmap );
4341 /* To display the pixmap, we use a fixed widget to place the pixmap */
4342 fixed = gtk_fixed_new();
4343 gtk_widget_set_usize( fixed, 200, 200 );
4344 gtk_fixed_put( GTK_FIXED(fixed), pixmap, 0, 0 );
4345 gtk_container_add( GTK_CONTAINER(window), fixed );
4346 gtk_widget_show( fixed );
4348 /* This masks out everything except for the image itself */
4349 gtk_widget_shape_combine_mask( window, mask, 0, 0 );
4351 /* show the window */
4352 gtk_widget_set_uposition( window, 20, 400 );
4353 gtk_widget_show( window );
4361 To make the wheelbarrow image sensitive, we could attach the button
4362 press event signal to make it do something. The following few lines
4363 would make the picture sensitive to a mouse button being pressed which
4364 makes the application terminate.
4367 gtk_widget_set_events( window,
4368 gtk_widget_get_events( window ) |
4369 GDK_BUTTON_PRESS_MASK );
4371 gtk_signal_connect( GTK_OBJECT(window), "button_press_event",
4372 GTK_SIGNAL_FUNC(close_application), NULL );
4375 <!-- ----------------------------------------------------------------- -->
4378 Ruler widgets are used to indicate the location of the mouse pointer
4379 in a given window. A window can have a vertical ruler spanning across
4380 the width and a horizontal ruler spanning down the height. A small
4381 triangular indicator on the ruler shows the exact location of the
4382 pointer relative to the ruler.
4384 A ruler must first be created. Horizontal and vertical rulers are
4388 GtkWidget *gtk_hruler_new( void ); /* horizontal ruler */
4390 GtkWidget *gtk_vruler_new( void ); /* vertical ruler */
4393 Once a ruler is created, we can define the unit of measurement. Units
4394 of measure for rulers can be GTK_PIXELS, GTK_INCHES or
4395 GTK_CENTIMETERS. This is set using
4398 void gtk_ruler_set_metric( GtkRuler *ruler,
4399 GtkMetricType metric );
4402 The default measure is GTK_PIXELS.
4405 gtk_ruler_set_metric( GTK_RULER(ruler), GTK_PIXELS );
4408 Other important characteristics of a ruler are how to mark the units
4409 of scale and where the position indicator is initially placed. These
4410 are set for a ruler using
4413 void gtk_ruler_set_range( GtkRuler *ruler,
4420 The lower and upper arguments define the extent of the ruler, and
4421 max_size is the largest possible number that will be displayed.
4422 Position defines the initial position of the pointer indicator within
4425 A vertical ruler can span an 800 pixel wide window thus
4428 gtk_ruler_set_range( GTK_RULER(vruler), 0, 800, 0, 800);
4431 The markings displayed on the ruler will be from 0 to 800, with a
4432 number for every 100 pixels. If instead we wanted the ruler to range
4433 from 7 to 16, we would code
4436 gtk_ruler_set_range( GTK_RULER(vruler), 7, 16, 0, 20);
4439 The indicator on the ruler is a small triangular mark that indicates
4440 the position of the pointer relative to the ruler. If the ruler is
4441 used to follow the mouse pointer, the motion_notify_event signal
4442 should be connected to the motion_notify_event method of the ruler.
4443 To follow all mouse movements within a window area, we would use
4446 #define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
4448 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4449 (GtkSignalFunc)EVENT_METHOD(ruler, motion_notify_event),
4450 GTK_OBJECT(ruler) );
4453 The following example creates a drawing area with a horizontal ruler
4454 above it and a vertical ruler to the left of it. The size of the
4455 drawing area is 600 pixels wide by 400 pixels high. The horizontal
4456 ruler spans from 7 to 13 with a mark every 100 pixels, while the
4457 vertical ruler spans from 0 to 400 with a mark every 100 pixels.
4458 Placement of the drawing area and the rulers is done using a table.
4461 /* example-start rulers rulers.c */
4463 #include <gtk/gtk.h>
4465 #define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
4470 /* This routine gets control when the close button is clicked */
4471 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
4475 /* The main routine */
4476 int main( int argc, char *argv[] ) {
4477 GtkWidget *window, *table, *area, *hrule, *vrule;
4479 /* Initialize GTK and create the main window */
4480 gtk_init( &argc, &argv );
4482 window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
4483 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
4484 GTK_SIGNAL_FUNC( close_application ), NULL);
4485 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
4487 /* Create a table for placing the ruler and the drawing area */
4488 table = gtk_table_new( 3, 2, FALSE );
4489 gtk_container_add( GTK_CONTAINER(window), table );
4491 area = gtk_drawing_area_new();
4492 gtk_drawing_area_size( (GtkDrawingArea *)area, XSIZE, YSIZE );
4493 gtk_table_attach( GTK_TABLE(table), area, 1, 2, 1, 2,
4494 GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0 );
4495 gtk_widget_set_events( area, GDK_POINTER_MOTION_MASK |
4496 GDK_POINTER_MOTION_HINT_MASK );
4498 /* The horizontal ruler goes on top. As the mouse moves across the
4499 * drawing area, a motion_notify_event is passed to the
4500 * appropriate event handler for the ruler. */
4501 hrule = gtk_hruler_new();
4502 gtk_ruler_set_metric( GTK_RULER(hrule), GTK_PIXELS );
4503 gtk_ruler_set_range( GTK_RULER(hrule), 7, 13, 0, 20 );
4504 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4505 (GtkSignalFunc)EVENT_METHOD(hrule,
4506 motion_notify_event),
4507 GTK_OBJECT(hrule) );
4508 /* GTK_WIDGET_CLASS(GTK_OBJECT(hrule)->klass)->motion_notify_event, */
4509 gtk_table_attach( GTK_TABLE(table), hrule, 1, 2, 0, 1,
4510 GTK_EXPAND|GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0 );
4512 /* The vertical ruler goes on the left. As the mouse moves across
4513 * the drawing area, a motion_notify_event is passed to the
4514 * appropriate event handler for the ruler. */
4515 vrule = gtk_vruler_new();
4516 gtk_ruler_set_metric( GTK_RULER(vrule), GTK_PIXELS );
4517 gtk_ruler_set_range( GTK_RULER(vrule), 0, YSIZE, 10, YSIZE );
4518 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4520 GTK_WIDGET_CLASS(GTK_OBJECT(vrule)->klass)->
4521 motion_notify_event,
4522 GTK_OBJECT(vrule) );
4523 gtk_table_attach( GTK_TABLE(table), vrule, 0, 1, 1, 2,
4524 GTK_FILL, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0 );
4526 /* Now show everything */
4527 gtk_widget_show( area );
4528 gtk_widget_show( hrule );
4529 gtk_widget_show( vrule );
4530 gtk_widget_show( table );
4531 gtk_widget_show( window );
4539 <!-- ----------------------------------------------------------------- -->
4542 Statusbars are simple widgets used to display a text message. They
4543 keep a stack of the messages pushed onto them, so that popping the
4544 current message will re-display the previous text message.
4546 In order to allow different parts of an application to use the same
4547 statusbar to display messages, the statusbar widget issues Context
4548 Identifiers which are used to identify different 'users'. The message
4549 on top of the stack is the one displayed, no matter what context it is
4550 in. Messages are stacked in last-in-first-out order, not context
4553 A statusbar is created with a call to:
4556 GtkWidget *gtk_statusbar_new( void );
4559 A new Context Identifier is requested using a call to the following
4560 function with a short textual description of the context:
4563 guint gtk_statusbar_get_context_id( GtkStatusbar *statusbar,
4564 const gchar *context_description );
4567 There are three functions that can operate on statusbars:
4570 guint gtk_statusbar_push( GtkStatusbar *statusbar,
4574 void gtk_statusbar_pop( GtkStatusbar *statusbar)
4577 void gtk_statusbar_remove( GtkStatusbar *statusbar,
4582 The first, gtk_statusbar_push, is used to add a new message to the
4583 statusbar. It returns a Message Identifier, which can be passed later
4584 to the function gtk_statusbar_remove to remove the message with the
4585 given Message and Context Identifiers from the statusbar's stack.
4587 The function gtk_statusbar_pop removes the message highest in the
4588 stack with the given Context Identifier.
4590 The following example creates a statusbar and two buttons, one for
4591 pushing items onto the statusbar, and one for popping the last item
4595 /* example-start statusbar statusbar.c */
4597 #include <gtk/gtk.h>
4600 GtkWidget *status_bar;
4602 void push_item (GtkWidget *widget, gpointer data)
4604 static int count = 1;
4607 g_snprintf(buff, 20, "Item %d", count++);
4608 gtk_statusbar_push( GTK_STATUSBAR(status_bar), GPOINTER_TO_INT(data), buff);
4613 void pop_item (GtkWidget *widget, gpointer data)
4615 gtk_statusbar_pop( GTK_STATUSBAR(status_bar), GPOINTER_TO_INT(data) );
4619 int main (int argc, char *argv[])
4628 gtk_init (&argc, &argv);
4630 /* create a new window */
4631 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4632 gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
4633 gtk_window_set_title(GTK_WINDOW (window), "GTK Statusbar Example");
4634 gtk_signal_connect(GTK_OBJECT (window), "delete_event",
4635 (GtkSignalFunc) gtk_exit, NULL);
4637 vbox = gtk_vbox_new(FALSE, 1);
4638 gtk_container_add(GTK_CONTAINER(window), vbox);
4639 gtk_widget_show(vbox);
4641 status_bar = gtk_statusbar_new();
4642 gtk_box_pack_start (GTK_BOX (vbox), status_bar, TRUE, TRUE, 0);
4643 gtk_widget_show (status_bar);
4645 context_id = gtk_statusbar_get_context_id(
4646 GTK_STATUSBAR(status_bar), "Statusbar example");
4648 button = gtk_button_new_with_label("push item");
4649 gtk_signal_connect(GTK_OBJECT(button), "clicked",
4650 GTK_SIGNAL_FUNC (push_item), GINT_TO_POINTER(context_id) );
4651 gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 2);
4652 gtk_widget_show(button);
4654 button = gtk_button_new_with_label("pop last item");
4655 gtk_signal_connect(GTK_OBJECT(button), "clicked",
4656 GTK_SIGNAL_FUNC (pop_item), GINT_TO_POINTER(context_id) );
4657 gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 2);
4658 gtk_widget_show(button);
4660 /* always display the window as the last step so it all splashes on
4661 * the screen at once. */
4662 gtk_widget_show(window);
4671 <!-- ----------------------------------------------------------------- -->
4674 The Entry widget allows text to be typed and displayed in a single line
4675 text box. The text may be set with function calls that allow new text
4676 to replace, prepend or append the current contents of the Entry widget.
4678 There are two functions for creating Entry widgets:
4681 GtkWidget *gtk_entry_new( void );
4683 GtkWidget *gtk_entry_new_with_max_length( guint16 max );
4686 The first just creates a new Entry widget, whilst the second creates a
4687 new Entry and sets a limit on the length of the text within the Entry.
4689 There are several functions for altering the text which is currently
4690 within the Entry widget.
4693 void gtk_entry_set_text( GtkEntry *entry,
4694 const gchar *text );
4696 void gtk_entry_append_text( GtkEntry *entry,
4697 const gchar *text );
4699 void gtk_entry_prepend_text( GtkEntry *entry,
4700 const gchar *text );
4703 The function gtk_entry_set_text sets the contents of the Entry widget,
4704 replacing the current contents. The functions gtk_entry_append_text
4705 and gtk_entry_prepend_text allow the current contents to be appended
4708 The next function allows the current insertion point to be set.
4711 void gtk_entry_set_position( GtkEntry *entry,
4715 The contents of the Entry can be retrieved by using a call to the
4716 following function. This is useful in the callback functions described below.
4719 gchar *gtk_entry_get_text( GtkEntry *entry );
4722 The value returned by this function is used internally, and must not
4723 be freed using either free() or g_free()
4725 If we don't want the contents of the Entry to be changed by someone typing
4726 into it, we can change its editable state.
4729 void gtk_entry_set_editable( GtkEntry *entry,
4730 gboolean editable );
4733 The function above allows us to toggle the editable state of the
4734 Entry widget by passing in a TRUE or FALSE value for the <tt/editable/
4737 If we are using the Entry where we don't want the text entered to be
4738 visible, for example when a password is being entered, we can use the
4739 following function, which also takes a boolean flag.
4742 void gtk_entry_set_visibility( GtkEntry *entry,
4746 A region of the text may be set as selected by using the following
4747 function. This would most often be used after setting some default
4748 text in an Entry, making it easy for the user to remove it.
4751 void gtk_entry_select_region( GtkEntry *entry,
4756 If we want to catch when the user has entered text, we can connect to
4757 the <tt/activate/ or <tt/changed/ signal. Activate is raised when the
4758 user hits the enter key within the Entry widget. Changed is raised
4759 when the text changes at all, e.g. for every character entered or
4762 The following code is an example of using an Entry widget.
4765 /* example-start entry entry.c */
4767 #include <gtk/gtk.h>
4769 void enter_callback(GtkWidget *widget, GtkWidget *entry)
4772 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
4773 printf("Entry contents: %s\n", entry_text);
4776 void entry_toggle_editable (GtkWidget *checkbutton,
4779 gtk_entry_set_editable(GTK_ENTRY(entry),
4780 GTK_TOGGLE_BUTTON(checkbutton)->active);
4783 void entry_toggle_visibility (GtkWidget *checkbutton,
4786 gtk_entry_set_visibility(GTK_ENTRY(entry),
4787 GTK_TOGGLE_BUTTON(checkbutton)->active);
4790 int main (int argc, char *argv[])
4794 GtkWidget *vbox, *hbox;
4799 gtk_init (&argc, &argv);
4801 /* create a new window */
4802 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4803 gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
4804 gtk_window_set_title(GTK_WINDOW (window), "GTK Entry");
4805 gtk_signal_connect(GTK_OBJECT (window), "delete_event",
4806 (GtkSignalFunc) gtk_exit, NULL);
4808 vbox = gtk_vbox_new (FALSE, 0);
4809 gtk_container_add (GTK_CONTAINER (window), vbox);
4810 gtk_widget_show (vbox);
4812 entry = gtk_entry_new_with_max_length (50);
4813 gtk_signal_connect(GTK_OBJECT(entry), "activate",
4814 GTK_SIGNAL_FUNC(enter_callback),
4816 gtk_entry_set_text (GTK_ENTRY (entry), "hello");
4817 gtk_entry_append_text (GTK_ENTRY (entry), " world");
4818 gtk_entry_select_region (GTK_ENTRY (entry),
4819 0, GTK_ENTRY(entry)->text_length);
4820 gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0);
4821 gtk_widget_show (entry);
4823 hbox = gtk_hbox_new (FALSE, 0);
4824 gtk_container_add (GTK_CONTAINER (vbox), hbox);
4825 gtk_widget_show (hbox);
4827 check = gtk_check_button_new_with_label("Editable");
4828 gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
4829 gtk_signal_connect (GTK_OBJECT(check), "toggled",
4830 GTK_SIGNAL_FUNC(entry_toggle_editable), entry);
4831 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);
4832 gtk_widget_show (check);
4834 check = gtk_check_button_new_with_label("Visible");
4835 gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
4836 gtk_signal_connect (GTK_OBJECT(check), "toggled",
4837 GTK_SIGNAL_FUNC(entry_toggle_visibility), entry);
4838 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);
4839 gtk_widget_show (check);
4841 button = gtk_button_new_with_label ("Close");
4842 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
4843 GTK_SIGNAL_FUNC(gtk_exit),
4844 GTK_OBJECT (window));
4845 gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
4846 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
4847 gtk_widget_grab_default (button);
4848 gtk_widget_show (button);
4850 gtk_widget_show(window);
4858 <!-- ----------------------------------------------------------------- -->
4861 The Spin Button widget is generally used to allow the user to select a
4862 value from a range of numeric values. It consists of a text
4863 entry box with up and down arrow buttons attached to the
4864 side. Selecting one of the buttons causes the value to 'spin' up and
4865 down the range of possible values. The entry box may also be edited
4866 directly to enter a specific value.
4868 The Spin Button allows the value to have zero or a number of decimal
4869 places and to be incremented/decremented in configurable steps. The
4870 action of holding down one of the buttons optionally result in an
4871 acceleration of change in the value according to how long it is
4874 The Spin Button uses an <ref id="sec_Adjustment" name="Adjustment">
4875 object to hold information about the range of values that the spin
4876 button can take. This makes for a powerful Spin Button widget.
4878 Recall that an adjustment widget is created with the following
4879 function, which illustrates the information that it holds:
4882 GtkObject *gtk_adjustment_new( gfloat value,
4885 gfloat step_increment,
4886 gfloat page_increment,
4890 These attributes of an Adjustment are used by the Spin Button in the
4894 <item> <tt/value/: initial value for the Spin Button
4895 <item> <tt/lower/: lower range value
4896 <item> <tt/upper/: upper range value
4897 <item> <tt/step_increment/: value to increment/decrement when pressing
4898 mouse button 1 on a button
4899 <item> <tt/page_increment/: value to increment/decrement when pressing
4900 mouse button 2 on a button
4901 <item> <tt/page_size/: unused
4904 Additionally, mouse button 3 can be used to jump directly to the
4905 <tt/upper/ or <tt/lower/ values when used to select one of the
4906 buttons. Lets look at how to create a Spin Button:
4909 GtkWidget *gtk_spin_button_new( GtkAdjustment *adjustment,
4914 The <tt/climb_rate/ argument take a value between 0.0 and 1.0 and
4915 indicates the amount of acceleration that the Spin Button has. The
4916 <tt/digits/ argument specifies the number of decimal places to which
4917 the value will be displayed.
4919 A Spin Button can be reconfigured after creation using the following
4923 void gtk_spin_button_configure( GtkSpinButton *spin_button,
4924 GtkAdjustment *adjustment,
4929 The <tt/spin_button/ argument specifies the Spin Button widget that is
4930 to be reconfigured. The other arguments are as specified above.
4932 The adjustment can be set and retrieved independantly using the
4933 following two functions:
4936 void gtk_spin_button_set_adjustment( GtkSpinButton *spin_button,
4937 GtkAdjustment *adjustment );
4939 GtkAdjustment *gtk_spin_button_get_adjustment( GtkSpinButton *spin_button );
4942 The number of decimal places can also be altered using:
4945 void gtk_spin_button_set_digits( GtkSpinButton *spin_button,
4949 The value that a Spin Button is currently displaying can be changed
4950 using the following function:
4953 void gtk_spin_button_set_value( GtkSpinButton *spin_button,
4957 The current value of a Spin Button can be retrieved as either a
4958 floating point or integer value with the following functions:
4961 gfloat gtk_spin_button_get_value_as_float( GtkSpinButton *spin_button );
4963 gint gtk_spin_button_get_value_as_int( GtkSpinButton *spin_button );
4966 If you want to alter the value of a Spin Value relative to its current
4967 value, then the following function can be used:
4970 void gtk_spin_button_spin( GtkSpinButton *spin_button,
4971 GtkSpinType direction,
4975 The <tt/direction/ parameter can take one of the following values:
4978 <item> GTK_SPIN_STEP_FORWARD
4979 <item> GTK_SPIN_STEP_BACKWARD
4980 <item> GTK_SPIN_PAGE_FORWARD
4981 <item> GTK_SPIN_PAGE_BACKWARD
4982 <item> GTK_SPIN_HOME
4984 <item> GTK_SPIN_USER_DEFINED
4987 This function packs in quite a bit of functionality, which I will
4988 attempt to clearly explain. Many of these settings use values from the
4989 Adjustment object that is associated with a Spin Button.
4991 GTK_SPIN_STEP_FORWARD and GTK_SPIN_STEP_BACKWARD change the value of
4992 the Spin Button by the amount specified by <tt/increment/, unless
4993 <tt/increment/ is equal to 0, in which case the value is changed by
4994 the value of <tt/step_increment/ in theAdjustment.
4996 GTK_SPIN_PAGE_FORWARD and GTK_SPIN_PAGE_BACKWARD simply alter the value of
4997 the Spin Button by <tt/increment/.
4999 GTK_SPIN_HOME sets the value of the Spin Button to the bottom of the
5002 GTK_SPIN_END sets the value of the Spin Button to the top of the
5005 GTK_SPIN_USER_DEFINED simply alters the value of the Spin Button by
5006 the specified amount.
5008 We move away from functions for setting and retreving the range attributes
5009 of the Spin Button now, and move onto functions that effect the
5010 appearance and behaviour of the Spin Button widget itself.
5012 The first of these functions is used to constrain the text box of the
5013 Spin Button such that it may only contain a numric value. This
5014 prevents a user from typing anything other than numeric values into
5015 the text box of a Spin Button:
5018 void gtk_spin_button_set_numeric( GtkSpinButton *spin_button,
5022 You can set whether a Spin Button will wrap around between the upper
5023 and lower range values with the following function:
5026 void gtk_spin_button_set_wrap( GtkSpinButton *spin_button,
5030 You can set a Spin Button to round the value to the nearest
5031 <tt/step_increment/, which is set within the Adjustment object used
5032 with the Spin Button. This is accomplished with the following
5036 void gtk_spin_button_set_snap_to_ticks( GtkSpinButton *spin_button,
5037 gboolean snap_to_ticks );
5040 The update policy of a Spin Button can be changed with the following
5044 void gtk_spin_button_set_update_policy( GtkSpinButton *spin_button,
5045 GtkSpinButtonUpdatePolicy policy );
5048 <!-- TODO: find out what this does - TRG -->
5050 The possible values of <tt/policy/ are either GTK_UPDATE_ALWAYS or
5051 GTK_UPDATE_IF_VALID.
5053 These policies affect the behavior of a Spin Button when parsing
5054 inserted text and syncing it's value with the values of the
5057 In the case of GTK_UPDATE_IF_VALID the Spin Button only value gets
5058 changed if the text input is a numeric value that
5059 is within the range specified by the Adjustment. Otherwise
5060 the text is reset to the current value.
5062 In case of GTK_UPDATE_ALWAYS we ignore errors while converting text
5063 into a numeric value.
5065 The appearance of the buttons used in a Spin Button can be changed
5066 using the following function:
5069 void gtk_spin_button_set_shadow_type( GtkSpinButton *spin_button,
5070 GtkShadowType shadow_type );
5073 As usual, the <tt/shadow_type/ can be one of:
5076 <item> GTK_SHADOW_IN
5077 <item> GTK_SHADOW_OUT
5078 <item> GTK_SHADOW_ETCHED_IN
5079 <item> GTK_SHADOW_ETCHED_OUT
5082 Finally, you can explicitly request that a Spin Button update itself:
5085 void gtk_spin_button_update( GtkSpinButton *spin_button );
5088 It's example time again.
5091 /* example-start spinbutton spinbutton.c */
5093 #include <gtk/gtk.h>
5095 static GtkWidget *spinner1;
5097 void toggle_snap( GtkWidget *widget,
5098 GtkSpinButton *spin )
5100 gtk_spin_button_set_snap_to_ticks (spin, GTK_TOGGLE_BUTTON (widget)->active);
5103 void toggle_numeric( GtkWidget *widget,
5104 GtkSpinButton *spin )
5106 gtk_spin_button_set_numeric (spin, GTK_TOGGLE_BUTTON (widget)->active);
5109 void change_digits( GtkWidget *widget,
5110 GtkSpinButton *spin )
5112 gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinner1),
5113 gtk_spin_button_get_value_as_int (spin));
5116 void get_value( GtkWidget *widget,
5121 GtkSpinButton *spin;
5123 spin = GTK_SPIN_BUTTON (spinner1);
5124 label = GTK_LABEL (gtk_object_get_user_data (GTK_OBJECT (widget)));
5125 if (GPOINTER_TO_INT (data) == 1)
5126 sprintf (buf, "%d", gtk_spin_button_get_value_as_int (spin));
5128 sprintf (buf, "%0.*f", spin->digits,
5129 gtk_spin_button_get_value_as_float (spin));
5130 gtk_label_set_text (label, buf);
5140 GtkWidget *main_vbox;
5143 GtkWidget *spinner2;
5147 GtkWidget *val_label;
5150 /* Initialise GTK */
5151 gtk_init(&argc, &argv);
5153 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5155 gtk_signal_connect (GTK_OBJECT (window), "destroy",
5156 GTK_SIGNAL_FUNC (gtk_main_quit),
5159 gtk_window_set_title (GTK_WINDOW (window), "Spin Button");
5161 main_vbox = gtk_vbox_new (FALSE, 5);
5162 gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 10);
5163 gtk_container_add (GTK_CONTAINER (window), main_vbox);
5165 frame = gtk_frame_new ("Not accelerated");
5166 gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
5168 vbox = gtk_vbox_new (FALSE, 0);
5169 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
5170 gtk_container_add (GTK_CONTAINER (frame), vbox);
5172 /* Day, month, year spinners */
5174 hbox = gtk_hbox_new (FALSE, 0);
5175 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
5177 vbox2 = gtk_vbox_new (FALSE, 0);
5178 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5180 label = gtk_label_new ("Day :");
5181 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5182 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5184 adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 31.0, 1.0,
5186 spinner = gtk_spin_button_new (adj, 0, 0);
5187 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
5188 gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
5190 gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5192 vbox2 = gtk_vbox_new (FALSE, 0);
5193 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5195 label = gtk_label_new ("Month :");
5196 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5197 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5199 adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 12.0, 1.0,
5201 spinner = gtk_spin_button_new (adj, 0, 0);
5202 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
5203 gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
5204 GTK_SHADOW_ETCHED_IN);
5205 gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5207 vbox2 = gtk_vbox_new (FALSE, 0);
5208 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5210 label = gtk_label_new ("Year :");
5211 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5212 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5214 adj = (GtkAdjustment *) gtk_adjustment_new (1998.0, 0.0, 2100.0,
5216 spinner = gtk_spin_button_new (adj, 0, 0);
5217 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), FALSE);
5218 gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
5220 gtk_widget_set_usize (spinner, 55, 0);
5221 gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5223 frame = gtk_frame_new ("Accelerated");
5224 gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
5226 vbox = gtk_vbox_new (FALSE, 0);
5227 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
5228 gtk_container_add (GTK_CONTAINER (frame), vbox);
5230 hbox = gtk_hbox_new (FALSE, 0);
5231 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5233 vbox2 = gtk_vbox_new (FALSE, 0);
5234 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5236 label = gtk_label_new ("Value :");
5237 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5238 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5240 adj = (GtkAdjustment *) gtk_adjustment_new (0.0, -10000.0, 10000.0,
5242 spinner1 = gtk_spin_button_new (adj, 1.0, 2);
5243 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner1), TRUE);
5244 gtk_widget_set_usize (spinner1, 100, 0);
5245 gtk_box_pack_start (GTK_BOX (vbox2), spinner1, FALSE, TRUE, 0);
5247 vbox2 = gtk_vbox_new (FALSE, 0);
5248 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5250 label = gtk_label_new ("Digits :");
5251 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5252 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5254 adj = (GtkAdjustment *) gtk_adjustment_new (2, 1, 5, 1, 1, 0);
5255 spinner2 = gtk_spin_button_new (adj, 0.0, 0);
5256 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner2), TRUE);
5257 gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
5258 GTK_SIGNAL_FUNC (change_digits),
5259 (gpointer) spinner2);
5260 gtk_box_pack_start (GTK_BOX (vbox2), spinner2, FALSE, TRUE, 0);
5262 hbox = gtk_hbox_new (FALSE, 0);
5263 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5265 button = gtk_check_button_new_with_label ("Snap to 0.5-ticks");
5266 gtk_signal_connect (GTK_OBJECT (button), "clicked",
5267 GTK_SIGNAL_FUNC (toggle_snap),
5269 gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
5270 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
5272 button = gtk_check_button_new_with_label ("Numeric only input mode");
5273 gtk_signal_connect (GTK_OBJECT (button), "clicked",
5274 GTK_SIGNAL_FUNC (toggle_numeric),
5276 gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
5277 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
5279 val_label = gtk_label_new ("");
5281 hbox = gtk_hbox_new (FALSE, 0);
5282 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5283 button = gtk_button_new_with_label ("Value as Int");
5284 gtk_object_set_user_data (GTK_OBJECT (button), val_label);
5285 gtk_signal_connect (GTK_OBJECT (button), "clicked",
5286 GTK_SIGNAL_FUNC (get_value),
5287 GINT_TO_POINTER (1));
5288 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
5290 button = gtk_button_new_with_label ("Value as Float");
5291 gtk_object_set_user_data (GTK_OBJECT (button), val_label);
5292 gtk_signal_connect (GTK_OBJECT (button), "clicked",
5293 GTK_SIGNAL_FUNC (get_value),
5294 GINT_TO_POINTER (2));
5295 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
5297 gtk_box_pack_start (GTK_BOX (vbox), val_label, TRUE, TRUE, 0);
5298 gtk_label_set_text (GTK_LABEL (val_label), "0");
5300 hbox = gtk_hbox_new (FALSE, 0);
5301 gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, TRUE, 0);
5303 button = gtk_button_new_with_label ("Close");
5304 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
5305 GTK_SIGNAL_FUNC (gtk_widget_destroy),
5306 GTK_OBJECT (window));
5307 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
5309 gtk_widget_show_all (window);
5311 /* Enter the event loop */
5319 <!-- ----------------------------------------------------------------- -->
5322 The combo box is another fairly simple widget that is really just a
5323 collection of other widgets. From the users point of view, the widget
5324 consists of a text entry box and a pull down menu from which the user
5325 can select one of a set of predefined entries. Alternatively, the user
5326 can type a different option directly into the text box.
5328 The following extract from the structure that defines a Combo Box
5329 identifies several of the components:
5342 As you can see, the Combo Box has two principle parts that you really
5343 care about: an entry and a list.
5345 First off, to create a combo box, use:
5348 GtkWidget *gtk_combo_new( void );
5351 Now, if you want to set the string in the entry section of the combo
5352 box, this is done by manipulating the <tt/entry/ widget directly:
5355 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), "My String.");
5358 To set the values in the popdown list, one uses the function:
5361 void gtk_combo_set_popdown_strings( GtkCombo *combo,
5365 Before you can do this, you have to assemble a GList of the strings
5366 that you want. GList is a linked list implementation that is part of
5367 <ref id="sec_glib" name="glib">, a library supporing GTK. For the
5368 moment, the quick and dirty explanation is that you need to set up a
5369 GList pointer, set it equal to NULL, then append strings to it with
5372 GList *g_list_append( GList *glist,
5376 It is important that you set the initial GList pointer to NULL. The
5377 value returned from the g_list_append function must be used as the new
5378 pointer to the GList.
5380 Here's a typical code segment for creating a set of options:
5385 glist = g_list_append(glist, "String 1");
5386 glist = g_list_append(glist, "String 2");
5387 glist = g_list_append(glist, "String 3");
5388 glist = g_list_append(glist, "String 4");
5390 gtk_combo_set_popdown_strings( GTK_COMBO(combo), glist) ;
5393 At this point you have a working combo box that has been set up.
5394 There are a few aspects of its behavior that you can change. These
5395 are accomplished with the functions:
5398 void gtk_combo_set_use_arrows( GtkCombo *combo,
5401 void gtk_combo_set_use_arrows_always( GtkCombo *combo,
5404 void gtk_combo_set_case_sensitive( GtkCombo *combo,
5408 <tt/gtk_combo_set_use_arrows()/ lets the user change the value in the
5409 entry using the up/down arrow keys. This doesn't bring up the list, but
5410 rather replaces the current text in the entry with the next list entry
5411 (up or down, as your key choice indicates). It does this by searching
5412 in the list for the item corresponding to the current value in the
5413 entry and selecting the previous/next item accordingly. Usually in an
5414 entry the arrow keys are used to change focus (you can do that anyway
5415 using TAB). Note that when the current item is the last of the list
5416 and you press arrow-down it changes the focus (the same applies with
5417 the first item and arrow-up).
5419 If the current value in the entry is not in the list, then the
5420 function of <tt/gtk_combo_set_use_arrows()/ is disabled.
5422 <tt/gtk_combo_set_use_arrows_always()/ similarly allows the use the
5423 the up/down arrow keys to cycle through the choices in the dropdown
5424 list, except that it wraps around the values in the list, completely
5425 disabling the use of the up and down arrow keys for changing focus.
5427 <tt/gtk_combo_set_case_sensitive()/ toggles whether or not GTK
5428 searches for entries in a case sensitive manner. This is used when
5429 the Combo widget is asked to find a value from the list using the
5430 current entry in the text box. This completion can be performed in
5431 eother a case sensitive or insensitive manner, depending upon the use
5432 of this function. The Combo widget can also simply complete the
5433 current entry if the user presses the key combination MOD-1 and
5434 'Tab'. MOD-1 is often mapped to the 'Alt' key. Note, however that some
5435 Window managers also use this key combination, which will override
5436 it's use within GTK.
5438 Now that we have a combo box, tailored to look and act how we want it,
5439 all that remains is being able to get data from the combo box. This is
5440 relatively straight forward. The majority of the time, all you are
5441 going to care about getting data from is the entry. The entry is
5442 accessed simply by GTK_ENTRY(GTK_COMBO(combo)->entry). The two
5443 principle things that you are going to want to do with it are attach
5444 to the activate signal, which indicates that the user has pressed the
5445 Return or Enter key,and read the text. The first is accomplished
5446 using something like:
5449 gtk_signal_connect(GTK_OBJECT(GTK_COMB(combo)->entry), "activate",
5450 GTK_SIGNAL_FUNC (my_callback_function), my_data);
5453 Getting the text at any arbitrary time is accomplished by simply using
5457 gchar *gtk_entry_get_text(GtkEntry *entry);
5465 string = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry));
5468 That's about all there is to it. There is a function
5471 void gtk_combo_disable_activate(GtkCombo *combo);
5474 that will disable the activate signal on the entry widget in the combo
5475 box. Personally, I can't think of why you'd want to use it, but it
5478 <!-- There are also a function to set the string on a particular item, void
5479 gtk_combo_set_item_string(GtkCombo *combo, GtkItem *item, const gchar
5480 *item_value), but this requires that you have a pointer to the
5481 appropriate GtkItem. Frankly, I have no idea how to do that.
5484 <!-- ----------------------------------------------------------------- -->
5485 <sect1> Color Selection
5487 The color selection widget is, not surprisingly, a widget for
5488 interactive selection of colors. This composite widget lets the user
5489 select a color by manipulating RGB (Red, Green, Blue) and HSV (Hue,
5490 Saturation, Value) triples. This is done either by adjusting single
5491 values with sliders or entries, or by picking the desired color from a
5492 hue-saturation wheel/value bar. Optionally, the opacity of the color
5495 The color selection widget currently emits only one signal,
5496 "color_changed", which is emitted whenever the current color in the
5497 widget changes, either when the user changes it or if it's set
5498 explicitly through gtk_color_selection_set_color().
5500 Lets have a look at what the color selection widget has to offer
5501 us. The widget comes in two flavours: gtk_color_selection and
5502 gtk_color_selection_dialog.
5505 GtkWidget *gtk_color_selection_new( void );
5508 You'll probably not be using this constructor directly. It creates an
5509 orphan GtkColorSelection widget which you'll have to parent
5510 yourself. The GtkColorSelection widget inherits from the GtkVBox
5514 GtkWidget *gtk_color_selection_dialog_new( const gchar *title );
5517 This is the most common color selection constructor. It creates a
5518 GtkColorSelectionDialog, which inherits from a GtkDialog. It consists
5519 of a GtkFrame containing a GtkColorSelection widget, a GtkHSeparator
5520 and a GtkHBox with three buttons, "Ok", "Cancel" and "Help". You can
5521 reach these buttons by accessing the "ok_button", "cancel_button" and
5522 "help_button" widgets in the GtkColorSelectionDialog structure,
5523 (i.e. GTK_COLOR_SELECTION_DIALOG(colorseldialog)->ok_button).
5526 void gtk_color_selection_set_update_policy( GtkColorSelection *colorsel,
5527 GtkUpdateType policy );
5530 This function sets the update policy. The default policy is
5531 GTK_UPDATE_CONTINUOUS which means that the current color is updated
5532 continuously when the user drags the sliders or presses the mouse and
5533 drags in the hue-saturation wheel or value bar. If you experience
5534 performance problems, you may want to set the policy to
5535 GTK_UPDATE_DISCONTINUOUS or GTK_UPDATE_DELAYED.
5538 void gtk_color_selection_set_opacity( GtkColorSelection *colorsel,
5542 The color selection widget supports adjusting the opacity of a color
5543 (also known as the alpha channel). This is disabled by
5544 default. Calling this function with use_opacity set to TRUE enables
5545 opacity. Likewise, use_opacity set to FALSE will disable opacity.
5548 void gtk_color_selection_set_color( GtkColorSelection *colorsel,
5552 You can set the current color explicitly by calling this function with
5553 a pointer to an array of colors (gdouble). The length of the array
5554 depends on whether opacity is enabled or not. Position 0 contains the
5555 red component, 1 is green, 2 is blue and opacity is at position 3
5556 (only if opacity is enabled, see
5557 gtk_color_selection_set_opacity()). All values are between 0.0 and
5561 void gtk_color_selection_get_color( GtkColorSelection *colorsel,
5565 When you need to query the current color, typically when you've
5566 received a "color_changed" signal, you use this function. Color is a
5567 pointer to the array of colors to fill in. See the
5568 gtk_color_selection_set_color() function for the description of this
5571 <!-- Need to do a whole section on DnD - TRG
5575 The color sample areas (right under the hue-saturation wheel) supports
5576 drag and drop. The type of drag and drop is "application/x-color". The
5577 message data consists of an array of 4 (or 5 if opacity is enabled)
5578 gdouble values, where the value at position 0 is 0.0 (opacity on) or
5579 1.0 (opacity off) followed by the red, green and blue values at
5580 positions 1,2 and 3 respectively. If opacity is enabled, the opacity
5581 is passed in the value at position 4.
5584 Here's a simple example demonstrating the use of the
5585 GtkColorSelectionDialog. The program displays a window containing a
5586 drawing area. Clicking on it opens a color selection dialog, and
5587 changing the color in the color selection dialog changes the
5591 /* example-start colorsel colorsel.c */
5594 #include <gdk/gdk.h>
5595 #include <gtk/gtk.h>
5597 GtkWidget *colorseldlg = NULL;
5598 GtkWidget *drawingarea = NULL;
5600 /* Color changed handler */
5602 void color_changed_cb (GtkWidget *widget, GtkColorSelection *colorsel)
5606 GdkColormap *colormap;
5608 /* Get drawingarea colormap */
5610 colormap = gdk_window_get_colormap (drawingarea->window);
5612 /* Get current color */
5614 gtk_color_selection_get_color (colorsel,color);
5616 /* Fit to a unsigned 16 bit integer (0..65535) and
5617 * insert into the GdkColor structure */
5619 gdk_color.red = (guint16)(color[0]*65535.0);
5620 gdk_color.green = (guint16)(color[1]*65535.0);
5621 gdk_color.blue = (guint16)(color[2]*65535.0);
5623 /* Allocate color */
5625 gdk_color_alloc (colormap, &gdk_color);
5627 /* Set window background color */
5629 gdk_window_set_background (drawingarea->window, &gdk_color);
5633 gdk_window_clear (drawingarea->window);
5636 /* Drawingarea event handler */
5638 gint area_event (GtkWidget *widget, GdkEvent *event, gpointer client_data)
5640 gint handled = FALSE;
5641 GtkWidget *colorsel;
5643 /* Check if we've received a button pressed event */
5645 if (event->type == GDK_BUTTON_PRESS && colorseldlg == NULL)
5647 /* Yes, we have an event and there's no colorseldlg yet! */
5651 /* Create color selection dialog */
5653 colorseldlg = gtk_color_selection_dialog_new("Select background color");
5655 /* Get the GtkColorSelection widget */
5657 colorsel = GTK_COLOR_SELECTION_DIALOG(colorseldlg)->colorsel;
5659 /* Connect to the "color_changed" signal, set the client-data
5660 * to the colorsel widget */
5662 gtk_signal_connect(GTK_OBJECT(colorsel), "color_changed",
5663 (GtkSignalFunc)color_changed_cb, (gpointer)colorsel);
5665 /* Show the dialog */
5667 gtk_widget_show(colorseldlg);
5673 /* Close down and exit handler */
5675 void destroy_window (GtkWidget *widget, gpointer client_data)
5682 gint main (gint argc, gchar *argv[])
5686 /* Initialize the toolkit, remove gtk-related commandline stuff */
5688 gtk_init (&argc,&argv);
5690 /* Create toplevel window, set title and policies */
5692 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5693 gtk_window_set_title (GTK_WINDOW(window), "Color selection test");
5694 gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, TRUE);
5696 /* Attach to the "delete" and "destroy" events so we can exit */
5698 gtk_signal_connect (GTK_OBJECT(window), "delete_event",
5699 (GtkSignalFunc)destroy_window, (gpointer)window);
5701 gtk_signal_connect (GTK_OBJECT(window), "destroy",
5702 (GtkSignalFunc)destroy_window, (gpointer)window);
5704 /* Create drawingarea, set size and catch button events */
5706 drawingarea = gtk_drawing_area_new ();
5708 gtk_drawing_area_size (GTK_DRAWING_AREA(drawingarea), 200, 200);
5710 gtk_widget_set_events (drawingarea, GDK_BUTTON_PRESS_MASK);
5712 gtk_signal_connect (GTK_OBJECT(drawingarea), "event",
5713 (GtkSignalFunc)area_event, (gpointer)drawingarea);
5715 /* Add drawingarea to window, then show them both */
5717 gtk_container_add (GTK_CONTAINER(window), drawingarea);
5719 gtk_widget_show (drawingarea);
5720 gtk_widget_show (window);
5722 /* Enter the gtk main loop (this never returns) */
5726 /* Satisfy grumpy compilers */
5733 <!-- ----------------------------------------------------------------- -->
5734 <sect1> File Selections
5736 The file selection widget is a quick and simple way to display a File
5737 dialog box. It comes complete with Ok, Cancel, and Help buttons, a
5738 great way to cut down on programming time.
5740 To create a new file selection box use:
5743 GtkWidget *gtk_file_selection_new( gchar *title );
5746 To set the filename, for example to bring up a specific directory, or
5747 give a default filename, use this function:
5750 void gtk_file_selection_set_filename( GtkFileSelection *filesel,
5754 To grab the text that the user has entered or clicked on, use this
5758 gchar *gtk_file_selection_get_filename( GtkFileSelection *filesel );
5761 There are also pointers to the widgets contained within the file
5762 selection widget. These are:
5767 <item>selection_entry
5768 <item>selection_text
5775 Most likely you will want to use the ok_button, cancel_button, and
5776 help_button pointers in signaling their use.
5778 Included here is an example stolen from testgtk.c, modified to run on
5779 its own. As you will see, there is nothing much to creating a file
5780 selection widget. While in this example the Help button appears on the
5781 screen, it does nothing as there is not a signal attached to it.
5784 /* example-start filesel filesel.c */
5786 #include <gtk/gtk.h>
5788 /* Get the selected filename and print it to the console */
5789 void file_ok_sel (GtkWidget *w, GtkFileSelection *fs)
5791 g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
5794 void destroy (GtkWidget *widget, gpointer data)
5799 int main (int argc, char *argv[])
5803 gtk_init (&argc, &argv);
5805 /* Create a new file selection widget */
5806 filew = gtk_file_selection_new ("File selection");
5808 gtk_signal_connect (GTK_OBJECT (filew), "destroy",
5809 (GtkSignalFunc) destroy, &filew);
5810 /* Connect the ok_button to file_ok_sel function */
5811 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
5812 "clicked", (GtkSignalFunc) file_ok_sel, filew );
5814 /* Connect the cancel_button to destroy the widget */
5815 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION
5816 (filew)->cancel_button),
5817 "clicked", (GtkSignalFunc) gtk_widget_destroy,
5818 GTK_OBJECT (filew));
5820 /* Lets set the filename, as if this were a save dialog, and we are giving
5821 a default filename */
5822 gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew),
5825 gtk_widget_show(filew);
5832 <!-- ***************************************************************** -->
5833 <sect> Container Widgets
5834 <!-- ***************************************************************** -->
5836 <!-- ----------------------------------------------------------------- -->
5837 <sect1>The EventBox <label id="sec_EventBox">
5839 Some GTK widgets don't have associated X windows, so they just draw on
5840 their parents. Because of this, they cannot receive events and if they
5841 are incorrectly sized, they don't clip so you can get messy
5842 overwriting etc. If you require more from these widgets, the EventBox
5845 At first glance, the EventBox widget might appear to be totally
5846 useless. It draws nothing on the screen and responds to no
5847 events. However, it does serve a function - it provides an X window
5848 for its child widget. This is important as many GTK widgets do not
5849 have an associated X window. Not having an X window saves memory and
5850 improves performance, but also has some drawbacks. A widget without an
5851 X window cannot receive events, and does not perform any clipping on
5852 its contents. Although the name <em/EventBox/ emphasizes the
5853 event-handling function, the widget can also be used for clipping.
5854 (and more, see the example below).
5856 To create a new EventBox widget, use:
5859 GtkWidget *gtk_event_box_new( void );
5862 A child widget can then be added to this EventBox:
5865 gtk_container_add( GTK_CONTAINER(event_box), child_widget );
5868 The following example demonstrates both uses of an EventBox - a label
5869 is created that is clipped to a small box, and set up so that a
5870 mouse-click on the label causes the program to exit. Resizing the
5871 window reveals varying amounts of the label.
5874 /* example-start eventbox eventbox.c */
5876 #include <gtk/gtk.h>
5879 main (int argc, char *argv[])
5882 GtkWidget *event_box;
5885 gtk_init (&argc, &argv);
5887 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5889 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
5891 gtk_signal_connect (GTK_OBJECT (window), "destroy",
5892 GTK_SIGNAL_FUNC (gtk_exit), NULL);
5894 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
5896 /* Create an EventBox and add it to our toplevel window */
5898 event_box = gtk_event_box_new ();
5899 gtk_container_add (GTK_CONTAINER(window), event_box);
5900 gtk_widget_show (event_box);
5902 /* Create a long label */
5904 label = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
5905 gtk_container_add (GTK_CONTAINER (event_box), label);
5906 gtk_widget_show (label);
5908 /* Clip it short. */
5909 gtk_widget_set_usize (label, 110, 20);
5911 /* And bind an action to it */
5912 gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
5913 gtk_signal_connect (GTK_OBJECT(event_box), "button_press_event",
5914 GTK_SIGNAL_FUNC (gtk_exit), NULL);
5916 /* Yet one more thing you need an X window for ... */
5918 gtk_widget_realize (event_box);
5919 gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1));
5921 gtk_widget_show (window);
5930 <!-- ----------------------------------------------------------------- -->
5931 <sect1>The Alignment widget <label id="sec_Alignment">
5933 The alignment widget allows you to place a widget within its window at
5934 a position and size relative to the size of the Alignment widget
5935 itself. For example, it can be very useful for centering a widget
5938 There are only two functions associated with the Alignment widget:
5941 GtkWidget* gtk_alignment_new( gfloat xalign,
5946 void gtk_alignment_set( GtkAlignment *alignment,
5953 The first function creates a new Alignment widget with the specified
5954 parameters. The second function allows the alignment paramters of an
5955 exisiting Alignment widget to be altered.
5957 All four alignment parameters are floating point numbers which can
5958 range from 0.0 to 1.0. The <tt/xalign/ and <tt/yalign/ arguments
5959 affect the position of the widget placed within the Alignment
5960 widget. The <tt/xscale/ and <tt/yscale/ arguments effect the amount of
5961 space allocated to the widget.
5963 A child widget can be added to this Alignment widget using:
5966 gtk_container_add( GTK_CONTAINER(alignment), child_widget );
5969 For an example of using an Alignment widget, refer to the example for
5970 the <ref id="sec_ProgressBar" name="Progress Bar"> widget.
5972 <!-- ----------------------------------------------------------------- -->
5973 <sect1> Fixed Container
5975 The Fixed container allows you to place widgets at a fixed position
5976 within it's window, relative to it's upper left hand corner. The
5977 position of the widgets can be changed dynamically.
5979 There are only three functions associated with the fixed widget:
5982 GtkWidget* gtk_fixed_new( void );
5984 void gtk_fixed_put( GtkFixed *fixed,
5989 void gtk_fixed_move( GtkFixed *fixed,
5995 The function <tt/gtk_fixed_new/ allows you to create a new Fixed
5998 <tt/gtk_fixed_put/ places <tt/widget/ in the container <tt/fixed/ at
5999 the position specified by <tt/x/ and <tt/y/.
6001 <tt/gtk_fixed_move/ allows the specified widget to be moved to a new
6004 The following example illustrates how to use the Fixed Container.
6007 /* example-start fixed fixed.c */
6009 #include <gtk/gtk.h>
6011 /* I'm going to be lazy and use some global variables to
6012 * store the position of the widget within the fixed
6017 /* This callback function moves the button to a new position
6018 * in the Fixed container. */
6019 void move_button( GtkWidget *widget,
6024 gtk_fixed_move( GTK_FIXED(fixed), widget, x, y);
6030 /* GtkWidget is the storage type for widgets */
6036 /* Initialise GTK */
6037 gtk_init(&argc, &argv);
6039 /* Create a new window */
6040 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6041 gtk_window_set_title(GTK_WINDOW(window), "Fixed Container");
6043 /* Here we connect the "destroy" event to a signal handler */
6044 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6045 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
6047 /* Sets the border width of the window. */
6048 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6050 /* Create a Fixed Container */
6051 fixed = gtk_fixed_new();
6052 gtk_container_add(GTK_CONTAINER(window), fixed);
6053 gtk_widget_show(fixed);
6055 for (i = 1 ; i <= 3 ; i++) {
6056 /* Creates a new button with the label "Press me" */
6057 button = gtk_button_new_with_label ("Press me");
6059 /* When the button receives the "clicked" signal, it will call the
6060 * function move_button() passing it the Fixed Containter as its
6062 gtk_signal_connect (GTK_OBJECT (button), "clicked",
6063 GTK_SIGNAL_FUNC (move_button), fixed);
6065 /* This packs the button into the fixed containers window. */
6066 gtk_fixed_put (GTK_FIXED (fixed), button, i*50, i*50);
6068 /* The final step is to display this newly created widget. */
6069 gtk_widget_show (button);
6072 /* Display the window */
6073 gtk_widget_show (window);
6075 /* Enter the event loop */
6083 <!-- ----------------------------------------------------------------- -->
6084 <sect1> Layout Container
6086 The Layout container is similar to the Fixed container except that it
6087 implements an infinite (where infinity is less than 2^32) scrolling
6088 area. Xwindows has a limitation where windows can be at most 32767
6089 pixels wide or tall. The Layout container gets around this limitation
6090 by doing some exotic stuff using window and bit gravities, so that you
6091 can have smooth scrolling even when you have many child widgets in
6092 your scrolling area.
6094 A Layout container is created using:
6097 GtkWidget *gtk_layout_new( GtkAdjustment *hadjustment,
6098 GtkAdjustment *vadjustment );
6101 As you can see, you can optionally specify the Adjustment objects that
6102 the Layout widget will use for it's scrolling.
6104 You can add and move widgets in the Layout container using the
6105 following two functions:
6108 void gtk_layout_put( GtkLayout *layout,
6113 void gtk_layout_move( GtkLayout *layout,
6119 The size of the Layout container can be set using the next function:
6122 void gtk_layout_set_size( GtkLayout *layout,
6127 Layout containers are one of the very few widgets in the GTK widget
6128 set that actively repaint themselves on screen as they are changed
6129 using the above functions (the vast majority of widgets queue
6130 requests which are then processed when control returns to the
6131 <tt/gtk_main()/ function).
6133 When you want to make a large number of changes to a Layout container,
6134 you can use the following two functions to disable and re-enable this
6135 repainting functionality:
6138 void gtk_layout_freeze( GtkLayout *layout );
6140 void gtk_layout_thaw( GtkLayout *layout );
6143 The final four functions for use with Layout widgets are for
6144 manipulating the horizontal and vertical adjustment widgets:
6147 GtkAdjustment* gtk_layout_get_hadjustment( GtkLayout *layout );
6149 GtkAdjustment* gtk_layout_get_vadjustment( GtkLayout *layout );
6151 void gtk_layout_set_hadjustment( GtkLayout *layout,
6152 GtkAdjustment *adjustment );
6154 void gtk_layout_set_vadjustment( GtkLayout *layout,
6155 GtkAdjustment *adjustment);
6158 <!-- ----------------------------------------------------------------- -->
6159 <sect1> Frames <label id="sec_Frames">
6161 Frames can be used to enclose one or a group of widgets with a box
6162 which can optionally be labelled. The position of the label and the
6163 style of the box can be altered to suit.
6165 A Frame can be created with the following function:
6168 GtkWidget *gtk_frame_new( const gchar *label );
6171 The label is by default placed in the upper left hand corner of the
6172 frame. A value of NULL for the <tt/label/ argument will result in no
6173 label being displayed. The text of the label can be changed using the
6177 void gtk_frame_set_label( GtkFrame *frame,
6178 const gchar *label );
6181 The position of the label can be changed using this function:
6184 void gtk_frame_set_label_align( GtkFrame *frame,
6189 <tt/xalign/ and <tt/yalign/ take values between 0.0 and 1.0. <tt/xalign/
6190 indicates the position of the label along the top horizontal of the
6191 frame. <tt/yalign/ is not currently used. The default value of xalign
6192 is 0.0 which places the label at the left hand end of the frame.
6194 The next function alters the style of the box that is used to outline
6198 void gtk_frame_set_shadow_type( GtkFrame *frame,
6199 GtkShadowType type);
6202 The <tt/type/ argument can take one of the following values:
6204 <item> GTK_SHADOW_NONE
6205 <item> GTK_SHADOW_IN
6206 <item> GTK_SHADOW_OUT
6207 <item> GTK_SHADOW_ETCHED_IN (the default)
6208 <item> GTK_SHADOW_ETCHED_OUT
6211 The following code example illustrates the use of the Frame widget.
6214 /* example-start frame frame.c */
6216 #include <gtk/gtk.h>
6221 /* GtkWidget is the storage type for widgets */
6227 /* Initialise GTK */
6228 gtk_init(&argc, &argv);
6230 /* Create a new window */
6231 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6232 gtk_window_set_title(GTK_WINDOW(window), "Frame Example");
6234 /* Here we connect the "destroy" event to a signal handler */
6235 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6236 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
6238 gtk_widget_set_usize(window, 300, 300);
6239 /* Sets the border width of the window. */
6240 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6242 /* Create a Frame */
6243 frame = gtk_frame_new(NULL);
6244 gtk_container_add(GTK_CONTAINER(window), frame);
6246 /* Set the frames label */
6247 gtk_frame_set_label( GTK_FRAME(frame), "GTK Frame Widget" );
6249 /* Align the label at the right of the frame */
6250 gtk_frame_set_label_align( GTK_FRAME(frame), 1.0, 0.0);
6252 /* Set the style of the frame */
6253 gtk_frame_set_shadow_type( GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
6255 gtk_widget_show(frame);
6257 /* Display the window */
6258 gtk_widget_show (window);
6260 /* Enter the event loop */
6269 <!-- ----------------------------------------------------------------- -->
6270 <sect1> Aspect Frames
6272 The aspect frame widget is like a frame widget, except that it also
6273 enforces the aspect ratio (that is, the ratio of the width to the
6274 height) of the child widget to have a certain value, adding extra
6275 space if necessary. This is useful, for instance, if you want to
6276 preview a larger image. The size of the preview should vary when the
6277 user resizes the window, but the aspect ratio needs to always match
6280 To create a new aspect frame use:
6283 GtkWidget *gtk_aspect_frame_new( const gchar *label,
6290 <tt/xalign/ and <tt/yalign/ specify alignment as with Alignment
6291 widgets. If <tt/obey_child/ is true, the aspect ratio of a child
6292 widget will match the aspect ratio of the ideal size it requests.
6293 Otherwise, it is given by <tt/ratio/.
6295 To change the options of an existing aspect frame, you can use:
6298 void gtk_aspect_frame_set( GtkAspectFrame *aspect_frame,
6305 As an example, the following program uses an AspectFrame to present a
6306 drawing area whose aspect ratio will always be 2:1, no matter how the
6307 user resizes the top-level window.
6310 /* example-start aspectframe aspectframe.c */
6312 #include <gtk/gtk.h>
6315 main (int argc, char *argv[])
6318 GtkWidget *aspect_frame;
6319 GtkWidget *drawing_area;
6320 gtk_init (&argc, &argv);
6322 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6323 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
6324 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6325 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
6326 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6328 /* Create an aspect_frame and add it to our toplevel window */
6330 aspect_frame = gtk_aspect_frame_new ("2x1", /* label */
6333 2, /* xsize/ysize = 2 */
6334 FALSE /* ignore child's aspect */);
6336 gtk_container_add (GTK_CONTAINER(window), aspect_frame);
6337 gtk_widget_show (aspect_frame);
6339 /* Now add a child widget to the aspect frame */
6341 drawing_area = gtk_drawing_area_new ();
6343 /* Ask for a 200x200 window, but the AspectFrame will give us a 200x100
6344 * window since we are forcing a 2x1 aspect ratio */
6345 gtk_widget_set_usize (drawing_area, 200, 200);
6346 gtk_container_add (GTK_CONTAINER(aspect_frame), drawing_area);
6347 gtk_widget_show (drawing_area);
6349 gtk_widget_show (window);
6356 <!-- ----------------------------------------------------------------- -->
6357 <sect1> Paned Window Widgets
6359 The paned window widgets are useful when you want to divide an area
6360 into two parts, with the relative size of the two parts controlled by
6361 the user. A groove is drawn between the two portions with a handle
6362 that the user can drag to change the ratio. The division can either be
6363 horizontal (HPaned) or vertical (VPaned).
6365 To create a new paned window, call one of:
6368 GtkWidget *gtk_hpaned_new (void);
6370 GtkWidget *gtk_vpaned_new (void);
6373 After creating the paned window widget, you need to add child widgets
6374 to its two halves. To do this, use the functions:
6377 void gtk_paned_add1 (GtkPaned *paned, GtkWidget *child);
6379 void gtk_paned_add2 (GtkPaned *paned, GtkWidget *child);
6382 <tt/gtk_paned_add1()/ adds the child widget to the left or top half of
6383 the paned window. <tt/gtk_paned_add2()/ adds the child widget to the
6384 right or bottom half of the paned window.
6386 A paned widget can be changed visually using the following two
6390 void gtk_paned_set_handle_size( GtkPaned *paned,
6393 void gtk_paned_set_gutter_size( GtkPaned *paned,
6397 The first of these sets the size of the handle and the second sets the
6398 size of the gutter that is between the two parts of the paned window.
6400 As an example, we will create part of the user interface of an
6401 imaginary email program. A window is divided into two portions
6402 vertically, with the top portion being a list of email messages and
6403 the bottom portion the text of the email message. Most of the program
6404 is pretty straightforward. A couple of points to note: text can't be
6405 added to a Text widget until it is realized. This could be done by
6406 calling <tt/gtk_widget_realize()/, but as a demonstration of an
6407 alternate technique, we connect a handler to the "realize" signal to
6408 add the text. Also, we need to add the <tt/GTK_SHRINK/ option to some
6409 of the items in the table containing the text window and its
6410 scrollbars, so that when the bottom portion is made smaller, the
6411 correct portions shrink instead of being pushed off the bottom of the
6415 /* example-start paned paned.c */
6417 #include <gtk/gtk.h>
6419 /* Create the list of "messages" */
6424 GtkWidget *scrolled_window;
6426 GtkWidget *list_item;
6431 /* Create a new scrolled window, with scrollbars only if needed */
6432 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
6433 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
6434 GTK_POLICY_AUTOMATIC,
6435 GTK_POLICY_AUTOMATIC);
6437 /* Create a new list and put it in the scrolled window */
6438 list = gtk_list_new ();
6439 gtk_scrolled_window_add_with_viewport (
6440 GTK_SCROLLED_WINDOW (scrolled_window), list);
6441 gtk_widget_show (list);
6443 /* Add some messages to the window */
6444 for (i=0; i<10; i++) {
6446 sprintf(buffer,"Message #%d",i);
6447 list_item = gtk_list_item_new_with_label (buffer);
6448 gtk_container_add (GTK_CONTAINER(list), list_item);
6449 gtk_widget_show (list_item);
6453 return scrolled_window;
6456 /* Add some text to our text widget - this is a callback that is invoked
6457 when our window is realized. We could also force our window to be
6458 realized with gtk_widget_realize, but it would have to be part of
6459 a hierarchy first */
6462 realize_text (GtkWidget *text, gpointer data)
6464 gtk_text_freeze (GTK_TEXT (text));
6465 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
6466 "From: pathfinder@nasa.gov\n"
6467 "To: mom@nasa.gov\n"
6468 "Subject: Made it!\n"
6470 "We just got in this morning. The weather has been\n"
6471 "great - clear but cold, and there are lots of fun sights.\n"
6472 "Sojourner says hi. See you soon.\n"
6475 gtk_text_thaw (GTK_TEXT (text));
6478 /* Create a scrolled text area that displays a "message" */
6484 GtkWidget *hscrollbar;
6485 GtkWidget *vscrollbar;
6487 /* Create a table to hold the text widget and scrollbars */
6488 table = gtk_table_new (2, 2, FALSE);
6490 /* Put a text widget in the upper left hand corner. Note the use of
6491 * GTK_SHRINK in the y direction */
6492 text = gtk_text_new (NULL, NULL);
6493 gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
6494 GTK_FILL | GTK_EXPAND,
6495 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
6496 gtk_widget_show (text);
6498 /* Put a HScrollbar in the lower left hand corner */
6499 hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
6500 gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
6501 GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
6502 gtk_widget_show (hscrollbar);
6504 /* And a VScrollbar in the upper right */
6505 vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
6506 gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
6507 GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
6508 gtk_widget_show (vscrollbar);
6510 /* Add a handler to put a message in the text widget when it is realized */
6511 gtk_signal_connect (GTK_OBJECT (text), "realize",
6512 GTK_SIGNAL_FUNC (realize_text), NULL);
6518 main (int argc, char *argv[])
6525 gtk_init (&argc, &argv);
6527 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6528 gtk_window_set_title (GTK_WINDOW (window), "Paned Windows");
6529 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6530 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
6531 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6532 gtk_widget_set_usize (GTK_WIDGET(window), 450, 400);
6534 /* create a vpaned widget and add it to our toplevel window */
6536 vpaned = gtk_vpaned_new ();
6537 gtk_container_add (GTK_CONTAINER(window), vpaned);
6538 gtk_paned_set_handle_size (GTK_PANED(vpaned),
6540 gtk_paned_set_gutter_size (GTK_PANED(vpaned),
6542 gtk_widget_show (vpaned);
6544 /* Now create the contents of the two halves of the window */
6546 list = create_list ();
6547 gtk_paned_add1 (GTK_PANED(vpaned), list);
6548 gtk_widget_show (list);
6550 text = create_text ();
6551 gtk_paned_add2 (GTK_PANED(vpaned), text);
6552 gtk_widget_show (text);
6553 gtk_widget_show (window);
6560 <!-- ----------------------------------------------------------------- -->
6561 <sect1>Viewports <label id="sec_Viewports">
6563 It is unlikely that you will ever need to use the Viewport widget
6564 directly. You are much more likely to use the
6565 <ref id="sec_ScrolledWindows" name="Scrolled Windows"> widget which
6566 itself uses the Viewport.
6568 A viewport widget allows you to place a larger widget within it such
6569 that you can view a part of it at a time. It uses
6570 <ref id="sec_Adjustment" name="Adjustments"> to define the area that
6571 is currently in view.
6573 A Viewport is created with the function
6576 GtkWidget *gtk_viewport_new( GtkAdjustment *hadjustment,
6577 GtkAdjustment *vadjustment );
6580 As you can see you can specify the horizontal and vertical Adjustments
6581 that the widget is to use when you create the widget. It will create
6582 it's own if you pass NULL as the value of the arguments.
6584 You can get and set the adjustments after the widget has been created
6585 using the following four functions:
6588 GtkAdjustment *gtk_viewport_get_hadjustment (GtkViewport *viewport );
6590 GtkAdjustment *gtk_viewport_get_vadjustment (GtkViewport *viewport );
6592 void gtk_viewport_set_hadjustment( GtkViewport *viewport,
6593 GtkAdjustment *adjustment );
6595 void gtk_viewport_set_vadjustment( GtkViewport *viewport,
6596 GtkAdjustment *adjustment );
6599 The only other viewport function is used to alter its appearance:
6602 void gtk_viewport_set_shadow_type( GtkViewport *viewport,
6603 GtkShadowType type );
6606 Possible values for the <tt/type/ parameter are:
6608 <item> GTK_SHADOW_NONE,
6609 <item> GTK_SHADOW_IN,
6610 <item> GTK_SHADOW_OUT,
6611 <item> GTK_SHADOW_ETCHED_IN,
6612 <item> GTK_SHADOW_ETCHED_OUT
6615 <!-- ----------------------------------------------------------------- -->
6616 <sect1>Scrolled Windows <label id="sec_ScrolledWindows">
6618 Scrolled windows are used to create a scrollable area inside a real
6619 window. You may insert any type of widget into a scrolled window, and
6620 it will be accessible regardless of the size by using the scrollbars.
6622 The following function is used to create a new scrolled window.
6625 GtkWidget *gtk_scrolled_window_new( GtkAdjustment *hadjustment,
6626 GtkAdjustment *vadjustment );
6629 Where the first argument is the adjustment for the horizontal
6630 direction, and the second, the adjustment for the vertical direction.
6631 These are almost always set to NULL.
6634 void gtk_scrolled_window_set_policy( GtkScrolledWindow *scrolled_window,
6635 GtkPolicyType hscrollbar_policy,
6636 GtkPolicyType vscrollbar_policy );
6639 This sets the policy to be used with respect to the scrollbars.
6640 The first argument is the scrolled window you wish to change. The second
6641 sets the policy for the horizontal scrollbar, and the third the policy for
6642 the vertical scrollbar.
6644 The policy may be one of GTK_POLICY_AUTOMATIC, or GTK_POLICY_ALWAYS.
6645 GTK_POLICY_AUTOMATIC will automatically decide whether you need
6646 scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars
6649 You can then place your object into the scrolled window using the
6653 void gtk_scrolled_window_add_with_viewport( GtkScrolledWindow *scrolled_window,
6657 Here is a simple example that packs 100 toggle buttons into a scrolled
6658 window. I've only commented on the parts that may be new to you.
6661 /* example-start scrolledwin scrolledwin.c */
6663 #include <gtk/gtk.h>
6665 void destroy(GtkWidget *widget, gpointer data)
6670 int main (int argc, char *argv[])
6672 static GtkWidget *window;
6673 GtkWidget *scrolled_window;
6679 gtk_init (&argc, &argv);
6681 /* Create a new dialog window for the scrolled window to be
6682 * packed into. A dialog is just like a normal window except it has a
6683 * vbox and a horizontal separator packed into it. It's just a shortcut
6684 * for creating dialogs */
6685 window = gtk_dialog_new ();
6686 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6687 (GtkSignalFunc) destroy, NULL);
6688 gtk_window_set_title (GTK_WINDOW (window), "GtkScrolledWindow example");
6689 gtk_container_set_border_width (GTK_CONTAINER (window), 0);
6690 gtk_widget_set_usize(window, 300, 300);
6692 /* create a new scrolled window. */
6693 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
6695 gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 10);
6697 /* the policy is one of GTK_POLICY AUTOMATIC, or GTK_POLICY_ALWAYS.
6698 * GTK_POLICY_AUTOMATIC will automatically decide whether you need
6699 * scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars
6700 * there. The first one is the horizontal scrollbar, the second,
6702 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
6703 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
6704 /* The dialog window is created with a vbox packed into it. */
6705 gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)->vbox), scrolled_window,
6707 gtk_widget_show (scrolled_window);
6709 /* create a table of 10 by 10 squares. */
6710 table = gtk_table_new (10, 10, FALSE);
6712 /* set the spacing to 10 on x and 10 on y */
6713 gtk_table_set_row_spacings (GTK_TABLE (table), 10);
6714 gtk_table_set_col_spacings (GTK_TABLE (table), 10);
6716 /* pack the table into the scrolled window */
6717 gtk_scrolled_window_add_with_viewport (
6718 GTK_SCROLLED_WINDOW (scrolled_window), table);
6719 gtk_widget_show (table);
6721 /* this simply creates a grid of toggle buttons on the table
6722 * to demonstrate the scrolled window. */
6723 for (i = 0; i < 10; i++)
6724 for (j = 0; j < 10; j++) {
6725 sprintf (buffer, "button (%d,%d)\n", i, j);
6726 button = gtk_toggle_button_new_with_label (buffer);
6727 gtk_table_attach_defaults (GTK_TABLE (table), button,
6729 gtk_widget_show (button);
6732 /* Add a "close" button to the bottom of the dialog */
6733 button = gtk_button_new_with_label ("close");
6734 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
6735 (GtkSignalFunc) gtk_widget_destroy,
6736 GTK_OBJECT (window));
6738 /* this makes it so the button is the default. */
6740 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
6741 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0);
6743 /* This grabs this button to be the default button. Simply hitting
6744 * the "Enter" key will cause this button to activate. */
6745 gtk_widget_grab_default (button);
6746 gtk_widget_show (button);
6748 gtk_widget_show (window);
6757 Try playing with resizing the window. You'll notice how the scrollbars
6758 react. You may also wish to use the gtk_widget_set_usize() call to set
6759 the default size of the window or other widgets.
6761 <!-- ----------------------------------------------------------------- -->
6764 Button Boxes are a convenient way to quickly layout a group of
6765 buttons. They come in both horizontal and vertical flavours. You
6766 create a new Button Box with one of the following calls, which create
6767 a horizontal or vertical box, respectively:
6770 GtkWidget *gtk_hbutton_box_new( void );
6772 GtkWidget *gtk_vbutton_box_new( void );
6775 The only attributes pertaining to button boxes effect how the buttons
6776 are layed out. You can change the spacing between the buttons with:
6779 void gtk_hbutton_box_set_spacing_default( gint spacing );
6781 void gtk_vbutton_box_set_spacing_default( gint spacing );
6784 Similarly, the current spacing values can be queried using:
6787 gint gtk_hbutton_box_get_spacing_default( void );
6789 gint gtk_vbutton_box_get_spacing_default( void );
6792 The second attribute that we can access effects the layour of the
6793 buttons within the box. It is set using one of:
6796 void gtk_hbutton_box_set_layout_default( GtkButtonBoxStyle layout );
6798 void gtk_vbutton_box_set_layout_default( GtkButtonBoxStyle layout );
6801 The <tt/layout/ argument can take one of the following values:
6804 <item> GTK_BUTTONBOX_DEFAULT_STYLE
6805 <item> GTK_BUTTONBOX_SPREAD
6806 <item> GTK_BUTTONBOX_EDGE
6807 <item> GTK_BUTTONBOX_START
6808 <item> GTK_BUTTONBOX_END
6811 The current layout setting can be retrieved using:
6814 GtkButtonBoxStyle gtk_hbutton_box_get_layout_default( void );
6816 GtkButtonBoxStyle gtk_vbutton_box_get_layout_default( void );
6819 Buttons are added to a Button Box using the usual function:
6822 gtk_container_add( GTK_CONTAINER(button_box), child_widget );
6825 Here's an example that illustrates all the different layout settings
6829 /* example-start buttonbox buttonbox.c */
6831 #include <gtk/gtk.h>
6833 /* Create a Button Box with the specified parameters */
6834 GtkWidget *create_bbox (gint horizontal,
6845 frame = gtk_frame_new (title);
6848 bbox = gtk_hbutton_box_new ();
6850 bbox = gtk_vbutton_box_new ();
6852 gtk_container_set_border_width (GTK_CONTAINER (bbox), 5);
6853 gtk_container_add (GTK_CONTAINER (frame), bbox);
6855 /* Set the appearance of the Button Box */
6856 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), layout);
6857 gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), spacing);
6858 gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), child_w, child_h);
6860 button = gtk_button_new_with_label ("OK");
6861 gtk_container_add (GTK_CONTAINER (bbox), button);
6863 button = gtk_button_new_with_label ("Cancel");
6864 gtk_container_add (GTK_CONTAINER (bbox), button);
6866 button = gtk_button_new_with_label ("Help");
6867 gtk_container_add (GTK_CONTAINER (bbox), button);
6875 static GtkWidget* window = NULL;
6876 GtkWidget *main_vbox;
6879 GtkWidget *frame_horz;
6880 GtkWidget *frame_vert;
6882 /* Initialize GTK */
6883 gtk_init( &argc, &argv );
6885 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6886 gtk_window_set_title (GTK_WINDOW (window), "Button Boxes");
6888 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6889 GTK_SIGNAL_FUNC(gtk_main_quit),
6892 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6894 main_vbox = gtk_vbox_new (FALSE, 0);
6895 gtk_container_add (GTK_CONTAINER (window), main_vbox);
6897 frame_horz = gtk_frame_new ("Horizontal Button Boxes");
6898 gtk_box_pack_start (GTK_BOX (main_vbox), frame_horz, TRUE, TRUE, 10);
6900 vbox = gtk_vbox_new (FALSE, 0);
6901 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
6902 gtk_container_add (GTK_CONTAINER (frame_horz), vbox);
6904 gtk_box_pack_start (GTK_BOX (vbox),
6905 create_bbox (TRUE, "Spread (spacing 40)", 40, 85, 20, GTK_BUTTONBOX_SPREAD),
6908 gtk_box_pack_start (GTK_BOX (vbox),
6909 create_bbox (TRUE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
6912 gtk_box_pack_start (GTK_BOX (vbox),
6913 create_bbox (TRUE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
6916 gtk_box_pack_start (GTK_BOX (vbox),
6917 create_bbox (TRUE, "End (spacing 10)", 10, 85, 20, GTK_BUTTONBOX_END),
6920 frame_vert = gtk_frame_new ("Vertical Button Boxes");
6921 gtk_box_pack_start (GTK_BOX (main_vbox), frame_vert, TRUE, TRUE, 10);
6923 hbox = gtk_hbox_new (FALSE, 0);
6924 gtk_container_set_border_width (GTK_CONTAINER (hbox), 10);
6925 gtk_container_add (GTK_CONTAINER (frame_vert), hbox);
6927 gtk_box_pack_start (GTK_BOX (hbox),
6928 create_bbox (FALSE, "Spread (spacing 5)", 5, 85, 20, GTK_BUTTONBOX_SPREAD),
6931 gtk_box_pack_start (GTK_BOX (hbox),
6932 create_bbox (FALSE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
6935 gtk_box_pack_start (GTK_BOX (hbox),
6936 create_bbox (FALSE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
6939 gtk_box_pack_start (GTK_BOX (hbox),
6940 create_bbox (FALSE, "End (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_END),
6943 gtk_widget_show_all (window);
6945 /* Enter the event loop */
6953 <!-- ----------------------------------------------------------------- -->
6956 Toolbars are usually used to group some number of widgets in order to
6957 simplify customization of their look and layout. Typically a toolbar
6958 consists of buttons with icons, labels and tooltips, but any other
6959 widget can also be put inside a toolbar. Finally, items can be
6960 arranged horizontally or vertically and buttons can be displayed with
6961 icons, labels or both.
6963 Creating a toolbar is (as one may already suspect) done with the
6967 GtkWidget *gtk_toolbar_new( GtkOrientation orientation,
6968 GtkToolbarStyle style );
6971 where orientation may be one of:
6974 GTK_ORIENTATION_HORIZONTAL
6975 GTK_ORIENTATION_VERTICAL
6986 The style applies to all the buttons created with the `item' functions
6987 (not to buttons inserted into toolbar as separate widgets).
6989 After creating a toolbar one can append, prepend and insert items
6990 (that means simple buttons) into the toolbar. To describe an item we
6991 need a label text, a tooltip text, a private tooltip text, an icon for
6992 the button and a callback function for it. For example, to append or
6993 prepend an item you may use the following functions:
6996 GtkWidget *gtk_toolbar_append_item( GtkToolbar *toolbar,
6998 const char *tooltip_text,
6999 const char *tooltip_private_text,
7001 GtkSignalFunc callback,
7002 gpointer user_data );
7004 GtkWidget *gtk_toolbar_prepend_item( GtkToolbar *toolbar,
7006 const char *tooltip_text,
7007 const char *tooltip_private_text,
7009 GtkSignalFunc callback,
7010 gpointer user_data );
7013 If you want to use gtk_toolbar_insert_item, the only additional
7014 parameter which must be specified is the position in which the item
7015 should be inserted, thus:
7018 GtkWidget *gtk_toolbar_insert_item( GtkToolbar *toolbar,
7020 const char *tooltip_text,
7021 const char *tooltip_private_text,
7023 GtkSignalFunc callback,
7028 To simplify adding spaces between toolbar items, you may use the
7029 following functions:
7032 void gtk_toolbar_append_space( GtkToolbar *toolbar );
7034 void gtk_toolbar_prepend_space( GtkToolbar *toolbar );
7036 void gtk_toolbar_insert_space( GtkToolbar *toolbar,
7041 While the size of the added space can be set globally for a
7042 whole toolbar with the function:
7045 void gtk_toolbar_set_space_size( GtkToolbar *toolbar,
7049 If it's required, the orientation of a toolbar and its style can be
7050 changed `on the fly' using the following functions:
7053 void gtk_toolbar_set_orientation( GtkToolbar *toolbar,
7054 GtkOrientation orientation );
7056 void gtk_toolbar_set_style( GtkToolbar *toolbar,
7057 GtkToolbarStyle style );
7059 void gtk_toolbar_set_tooltips( GtkToolbar *toolbar,
7063 Where <tt/orientation/ is one of GTK_ORIENTATION_HORIZONTAL or
7064 GTK_ORIENTATION_VERTICAL. The <tt/style/ is used to set appearance of
7065 the toolbar items by using one of GTK_TOOLBAR_ICONS, GTK_TOOLBAR_TEXT
7066 or GTK_TOOLBAR_BOTH.
7068 To show some other things that can be done with a toolbar, let's take
7069 the following program (we'll interrupt the listing with some
7070 additional explanations):
7073 #include <gtk/gtk.h>
7077 /* This function is connected to the Close button or
7078 * closing the window from the WM */
7079 void delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
7085 The above beginning seems for sure familiar to you if it's not your first
7086 GTK program. There is one additional thing though, we include a nice XPM
7087 picture to serve as an icon for all of the buttons.
7090 GtkWidget* close_button; /* This button will emit signal to close
7092 GtkWidget* tooltips_button; /* to enable/disable tooltips */
7093 GtkWidget* text_button,
7095 * both_button; /* radio buttons for toolbar style */
7096 GtkWidget* entry; /* a text entry to show packing any widget into
7100 In fact not all of the above widgets are needed here, but to make things
7101 clearer I put them all together.
7104 /* that's easy... when one of the buttons is toggled, we just
7105 * check which one is active and set the style of the toolbar
7107 * ATTENTION: our toolbar is passed as data to callback ! */
7108 void radio_event (GtkWidget *widget, gpointer data)
7110 if (GTK_TOGGLE_BUTTON (text_button)->active)
7111 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_TEXT);
7112 else if (GTK_TOGGLE_BUTTON (icon_button)->active)
7113 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_ICONS);
7114 else if (GTK_TOGGLE_BUTTON (both_button)->active)
7115 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_BOTH);
7118 /* even easier, just check given toggle button and enable/disable
7120 void toggle_event (GtkWidget *widget, gpointer data)
7122 gtk_toolbar_set_tooltips (GTK_TOOLBAR ( data ),
7123 GTK_TOGGLE_BUTTON (widget)->active );
7127 The above are just two callback functions that will be called when
7128 one of the buttons on a toolbar is pressed. You should already be
7129 familiar with things like this if you've already used toggle buttons (and
7133 int main (int argc, char *argv[])
7135 /* Here is our main window (a dialog) and a handle for the handlebox */
7137 GtkWidget* handlebox;
7139 /* Ok, we need a toolbar, an icon with a mask (one for all of
7140 the buttons) and an icon widget to put this icon in (but
7141 we'll create a separate widget for each button) */
7142 GtkWidget * toolbar;
7147 /* this is called in all GTK application. */
7148 gtk_init (&argc, &argv);
7150 /* create a new window with a given title, and nice size */
7151 dialog = gtk_dialog_new ();
7152 gtk_window_set_title ( GTK_WINDOW ( dialog ) , "GTKToolbar Tutorial");
7153 gtk_widget_set_usize( GTK_WIDGET ( dialog ) , 600 , 300 );
7154 GTK_WINDOW ( dialog ) ->allow_shrink = TRUE;
7156 /* typically we quit if someone tries to close us */
7157 gtk_signal_connect ( GTK_OBJECT ( dialog ), "delete_event",
7158 GTK_SIGNAL_FUNC ( delete_event ), NULL);
7160 /* we need to realize the window because we use pixmaps for
7161 * items on the toolbar in the context of it */
7162 gtk_widget_realize ( dialog );
7164 /* to make it nice we'll put the toolbar into the handle box,
7165 * so that it can be detached from the main window */
7166 handlebox = gtk_handle_box_new ();
7167 gtk_box_pack_start ( GTK_BOX ( GTK_DIALOG(dialog)->vbox ),
7168 handlebox, FALSE, FALSE, 5 );
7171 The above should be similar to any other GTK application. Just
7172 initialization of GTK, creating the window etc.. There is only one
7173 thing that probably needs some explanation: a handle box. A handle box
7174 is just another box that can be used to pack widgets in to. The
7175 difference between it and typical boxes is that it can be detached
7176 from a parent window (or, in fact, the handle box remains in the
7177 parent, but it is reduced to a very small rectangle, while all of its
7178 contents are reparented to a new freely floating window). It is
7179 usually nice to have a detachable toolbar, so these two widgets occur
7180 together quite often.
7183 /* toolbar will be horizontal, with both icons and text, and
7184 * with 5pxl spaces between items and finally,
7185 * we'll also put it into our handlebox */
7186 toolbar = gtk_toolbar_new ( GTK_ORIENTATION_HORIZONTAL,
7188 gtk_container_set_border_width ( GTK_CONTAINER ( toolbar ) , 5 );
7189 gtk_toolbar_set_space_size ( GTK_TOOLBAR ( toolbar ), 5 );
7190 gtk_container_add ( GTK_CONTAINER ( handlebox ) , toolbar );
7192 /* now we create icon with mask: we'll reuse it to create
7193 * icon widgets for toolbar items */
7194 icon = gdk_pixmap_create_from_xpm_d ( dialog->window, &mask,
7195 &dialog->style->white, gtk_xpm );
7198 Well, what we do above is just a straight-forward initialization of
7199 the toolbar widget and creation of a GDK pixmap with its mask. If you
7200 want to know something more about using pixmaps, refer to GDK
7201 documentation or to the <ref id="sec_Pixmaps" name="Pixmaps"> section
7202 earlier in this tutorial.
7205 /* our first item is <close> button */
7206 iconw = gtk_pixmap_new ( icon, mask ); /* icon widget */
7208 gtk_toolbar_append_item ( GTK_TOOLBAR (toolbar), /* our toolbar */
7209 "Close", /* button label */
7210 "Closes this app", /* this button's tooltip */
7211 "Private", /* tooltip private info */
7212 iconw, /* icon widget */
7213 GTK_SIGNAL_FUNC (delete_event), /* a signal */
7215 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) ); /* space after item */
7218 In the above code you see the simplest case: adding a button to
7219 toolbar. Just before appending a new item, we have to construct a
7220 pixmap widget to serve as an icon for this item; this step will have
7221 to be repeated for each new item. Just after the item we also add a
7222 space, so the following items will not touch each other. As you see
7223 gtk_toolbar_append_item returns a pointer to our newly created button
7224 widget, so that we can work with it in the normal way.
7227 /* now, let's make our radio buttons group... */
7228 iconw = gtk_pixmap_new ( icon, mask );
7229 icon_button = gtk_toolbar_append_element(
7230 GTK_TOOLBAR(toolbar),
7231 GTK_TOOLBAR_CHILD_RADIOBUTTON, /* a type of element */
7232 NULL, /* pointer to widget */
7234 "Only icons in toolbar", /* tooltip */
7235 "Private", /* tooltip private string */
7237 GTK_SIGNAL_FUNC (radio_event), /* signal */
7238 toolbar); /* data for signal */
7239 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7242 Here we begin creating a radio buttons group. To do this we use
7243 gtk_toolbar_append_element. In fact, using this function one can also
7244 add simple items or even spaces (type = GTK_TOOLBAR_CHILD_SPACE or
7245 GTK_TOOLBAR_CHILD_BUTTON). In the above case we start creating a radio
7246 group. In creating other radio buttons for this group a pointer to the
7247 previous button in the group is required, so that a list of buttons
7248 can be easily constructed (see the section on <ref
7249 id="sec_Radio_Buttons" name="Radio Buttons"> earlier in this
7253 /* following radio buttons refer to previous ones */
7254 iconw = gtk_pixmap_new ( icon, mask );
7256 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
7257 GTK_TOOLBAR_CHILD_RADIOBUTTON,
7260 "Only texts in toolbar",
7263 GTK_SIGNAL_FUNC (radio_event),
7265 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7267 iconw = gtk_pixmap_new ( icon, mask );
7269 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
7270 GTK_TOOLBAR_CHILD_RADIOBUTTON,
7273 "Icons and text in toolbar",
7276 GTK_SIGNAL_FUNC (radio_event),
7278 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7279 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(both_button),TRUE);
7282 In the end we have set the state of one of the buttons manually (otherwise
7283 they all stay in active state, preventing us from switching between them).
7286 /* here we have just a simple toggle button */
7287 iconw = gtk_pixmap_new ( icon, mask );
7289 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
7290 GTK_TOOLBAR_CHILD_TOGGLEBUTTON,
7293 "Toolbar with or without tips",
7296 GTK_SIGNAL_FUNC (toggle_event),
7298 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7299 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tooltips_button),TRUE);
7302 A toggle button can be created in the obvious way (if one knows how to create
7303 radio buttons already).
7306 /* to pack a widget into toolbar, we only have to
7307 * create it and append it with an appropriate tooltip */
7308 entry = gtk_entry_new ();
7309 gtk_toolbar_append_widget( GTK_TOOLBAR (toolbar),
7311 "This is just an entry",
7314 /* well, it isn't created within thetoolbar, so we must still show it */
7315 gtk_widget_show ( entry );
7318 As you see, adding any kind of widget to a toolbar is simple. The
7319 one thing you have to remember is that this widget must be shown manually
7320 (contrary to other items which will be shown together with the toolbar).
7323 /* that's it ! let's show everything. */
7324 gtk_widget_show ( toolbar );
7325 gtk_widget_show (handlebox);
7326 gtk_widget_show ( dialog );
7328 /* rest in gtk_main and wait for the fun to begin! */
7335 So, here we are at the end of toolbar tutorial. Of course, to appreciate
7336 it in full you need also this nice XPM icon, so here it is:
7340 static char * gtk_xpm[] = {
7347 "................+...............",
7348 "..............+++++.............",
7349 "............+++++@@++...........",
7350 "..........+++++@@@@@@++.........",
7351 "........++++@@@@@@@@@@++........",
7352 "......++++@@++++++++@@@++.......",
7353 ".....+++@@@+++++++++++@@@++.....",
7354 "...+++@@@@+++@@@@@@++++@@@@+....",
7355 "..+++@@@@+++@@@@@@@@+++@@@@@++..",
7356 ".++@@@@@@+++@@@@@@@@@@@@@@@@@@++",
7357 ".+#+@@@@@@++@@@@+++@@@@@@@@@@@@+",
7358 ".+##++@@@@+++@@@+++++@@@@@@@@$@.",
7359 ".+###++@@@@+++@@@+++@@@@@++$$$@.",
7360 ".+####+++@@@+++++++@@@@@+@$$$$@.",
7361 ".+#####+++@@@@+++@@@@++@$$$$$$+.",
7362 ".+######++++@@@@@@@++@$$$$$$$$+.",
7363 ".+#######+##+@@@@+++$$$$$$@@$$+.",
7364 ".+###+++##+##+@@++@$$$$$$++$$$+.",
7365 ".+###++++##+##+@@$$$$$$$@+@$$@+.",
7366 ".+###++++++#+++@$$@+@$$@++$$$@+.",
7367 ".+####+++++++#++$$@+@$$++$$$$+..",
7368 ".++####++++++#++$$@+@$++@$$$$+..",
7369 ".+#####+++++##++$$++@+++$$$$$+..",
7370 ".++####+++##+#++$$+++++@$$$$$+..",
7371 ".++####+++####++$$++++++@$$$@+..",
7372 ".+#####++#####++$$+++@++++@$@+..",
7373 ".+#####++#####++$$++@$$@+++$@@..",
7374 ".++####++#####++$$++$$$$$+@$@++.",
7375 ".++####++#####++$$++$$$$$$$$+++.",
7376 ".+++####+#####++$$++$$$$$$$@+++.",
7377 "..+++#########+@$$+@$$$$$$+++...",
7378 "...+++########+@$$$$$$$$@+++....",
7379 ".....+++######+@$$$$$$$+++......",
7380 "......+++#####+@$$$$$@++........",
7381 ".......+++####+@$$$$+++.........",
7382 ".........++###+$$$@++...........",
7383 "..........++##+$@+++............",
7384 "...........+++++++..............",
7385 ".............++++..............."};
7388 <!-- ----------------------------------------------------------------- -->
7391 The NoteBook Widget is a collection of 'pages' that overlap each
7392 other, each page contains different information. This widget has
7393 become more common lately in GUI programming, and it is a good way to
7394 show blocks of similar information that warrant separation in their
7397 The first function call you will need to know, as you can probably
7398 guess by now, is used to create a new notebook widget.
7401 GtkWidget *gtk_notebook_new( void );
7404 Once the notebook has been created, there are a number of functions
7405 that operate on the notebook widget. Let's look at them individually.
7407 The first one we will look at is how to position the page indicators.
7408 These page indicators or 'tabs' as they are referred to, can be
7409 positioned in four ways: top, bottom, left, or right.
7412 void gtk_notebook_set_tab_pos( GtkNotebook *notebook,
7413 GtkPositionType pos );
7416 GtkPostionType will be one of the following, which are pretty self
7420 <item> GTK_POS_RIGHT
7422 <item> GTK_POS_BOTTOM
7425 GTK_POS_TOP is the default.
7427 Next we will look at how to add pages to the notebook. There are three
7428 ways to add pages to the NoteBook. Let's look at the first two
7429 together as they are quite similar.
7432 void gtk_notebook_append_page( GtkNotebook *notebook,
7434 GtkWidget *tab_label );
7436 void gtk_notebook_prepend_page( GtkNotebook *notebook,
7438 GtkWidget *tab_label );
7441 These functions add pages to the notebook by inserting them from the
7442 back of the notebook (append), or the front of the notebook (prepend).
7443 <tt/child/ is the widget that is placed within the notebook page, and
7444 <tt/tab_label/ is the label for the page being added. The <tt/child/
7445 widget must be created separately, and is typically a set of options
7446 setout witin one of the other container widgets, such as a table.
7448 The final function for adding a page to the notebook contains all of
7449 the properties of the previous two, but it allows you to specify what
7450 position you want the page to be in the notebook.
7453 void gtk_notebook_insert_page( GtkNotebook *notebook,
7455 GtkWidget *tab_label,
7459 The parameters are the same as _append_ and _prepend_ except it
7460 contains an extra parameter, <tt/position/. This parameter is used to
7461 specify what place this page will be inserted into.
7463 Now that we know how to add a page, lets see how we can remove a page
7467 void gtk_notebook_remove_page( GtkNotebook *notebook,
7471 This function takes the page specified by <tt/page_num/ and removes it
7472 from the widget pointed to by <tt/notebook/.
7474 To find out what the current page is in a notebook use the function:
7477 gint gtk_notebook_get_current_page( GtkNotebook *notebook );
7480 These next two functions are simple calls to move the notebook page
7481 forward or backward. Simply provide the respective function call with
7482 the notebook widget you wish to operate on. Note: when the NoteBook is
7483 currently on the last page, and gtk_notebook_next_page is called, the
7484 notebook will wrap back to the first page. Likewise, if the NoteBook
7485 is on the first page, and gtk_notebook_prev_page is called, the
7486 notebook will wrap to the last page.
7489 void gtk_notebook_next_page( GtkNoteBook *notebook );
7491 void gtk_notebook_prev_page( GtkNoteBook *notebook );
7494 This next function sets the 'active' page. If you wish the notebook to
7495 be opened to page 5 for example, you would use this function. Without
7496 using this function, the notebook defaults to the first page.
7499 void gtk_notebook_set_page( GtkNotebook *notebook,
7503 The next two functions add or remove the notebook page tabs and the
7504 notebook border respectively.
7507 void gtk_notebook_set_show_tabs( GtkNotebook *notebook,
7508 gboolean show_tabs);
7510 void gtk_notebook_set_show_border( GtkNotebook *notebook,
7511 gboolean show_border );
7514 The next function is useful when the you have a large number of pages,
7515 and the tabs don't fit on the page. It allows the tabs to be scrolled
7516 through using two arrow buttons.
7519 void gtk_notebook_set_scrollable( GtkNotebook *notebook,
7520 gboolean scrollable );
7523 <tt/show_tabs/, <tt/show_border/ and <tt/scrollable/ can be either
7526 Now lets look at an example, it is expanded from the testgtk.c code
7527 that comes with the GTK distribution. This small program creates a
7528 window with a notebook and six buttons. The notebook contains 11
7529 pages, added in three different ways, appended, inserted, and
7530 prepended. The buttons allow you rotate the tab positions, add/remove
7531 the tabs and border, remove a page, change pages in both a forward and
7532 backward manner, and exit the program.
7535 /* example-start notebook notebook.c */
7537 #include <gtk/gtk.h>
7539 /* This function rotates the position of the tabs */
7540 void rotate_book (GtkButton *button, GtkNotebook *notebook)
7542 gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos +1) %4);
7545 /* Add/Remove the page tabs and the borders */
7546 void tabsborder_book (GtkButton *button, GtkNotebook *notebook)
7550 if (notebook->show_tabs == 0)
7552 if (notebook->show_border == 0)
7555 gtk_notebook_set_show_tabs (notebook, tval);
7556 gtk_notebook_set_show_border (notebook, bval);
7559 /* Remove a page from the notebook */
7560 void remove_book (GtkButton *button, GtkNotebook *notebook)
7564 page = gtk_notebook_get_current_page(notebook);
7565 gtk_notebook_remove_page (notebook, page);
7566 /* Need to refresh the widget --
7567 This forces the widget to redraw itself. */
7568 gtk_widget_draw(GTK_WIDGET(notebook), NULL);
7571 void delete (GtkWidget *widget, GtkWidget *event, gpointer data)
7576 int main (int argc, char *argv[])
7581 GtkWidget *notebook;
7584 GtkWidget *checkbutton;
7589 gtk_init (&argc, &argv);
7591 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
7593 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
7594 GTK_SIGNAL_FUNC (delete), NULL);
7596 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
7598 table = gtk_table_new(3,6,FALSE);
7599 gtk_container_add (GTK_CONTAINER (window), table);
7601 /* Create a new notebook, place the position of the tabs */
7602 notebook = gtk_notebook_new ();
7603 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
7604 gtk_table_attach_defaults(GTK_TABLE(table), notebook, 0,6,0,1);
7605 gtk_widget_show(notebook);
7607 /* Lets append a bunch of pages to the notebook */
7608 for (i=0; i < 5; i++) {
7609 sprintf(bufferf, "Append Frame %d", i+1);
7610 sprintf(bufferl, "Page %d", i+1);
7612 frame = gtk_frame_new (bufferf);
7613 gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
7614 gtk_widget_set_usize (frame, 100, 75);
7615 gtk_widget_show (frame);
7617 label = gtk_label_new (bufferf);
7618 gtk_container_add (GTK_CONTAINER (frame), label);
7619 gtk_widget_show (label);
7621 label = gtk_label_new (bufferl);
7622 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
7625 /* Now lets add a page to a specific spot */
7626 checkbutton = gtk_check_button_new_with_label ("Check me please!");
7627 gtk_widget_set_usize(checkbutton, 100, 75);
7628 gtk_widget_show (checkbutton);
7630 label = gtk_label_new ("Add page");
7631 gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, label, 2);
7633 /* Now finally lets prepend pages to the notebook */
7634 for (i=0; i < 5; i++) {
7635 sprintf(bufferf, "Prepend Frame %d", i+1);
7636 sprintf(bufferl, "PPage %d", i+1);
7638 frame = gtk_frame_new (bufferf);
7639 gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
7640 gtk_widget_set_usize (frame, 100, 75);
7641 gtk_widget_show (frame);
7643 label = gtk_label_new (bufferf);
7644 gtk_container_add (GTK_CONTAINER (frame), label);
7645 gtk_widget_show (label);
7647 label = gtk_label_new (bufferl);
7648 gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook), frame, label);
7651 /* Set what page to start at (page 4) */
7652 gtk_notebook_set_page (GTK_NOTEBOOK(notebook), 3);
7654 /* Create a bunch of buttons */
7655 button = gtk_button_new_with_label ("close");
7656 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
7657 GTK_SIGNAL_FUNC (delete), NULL);
7658 gtk_table_attach_defaults(GTK_TABLE(table), button, 0,1,1,2);
7659 gtk_widget_show(button);
7661 button = gtk_button_new_with_label ("next page");
7662 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
7663 (GtkSignalFunc) gtk_notebook_next_page,
7664 GTK_OBJECT (notebook));
7665 gtk_table_attach_defaults(GTK_TABLE(table), button, 1,2,1,2);
7666 gtk_widget_show(button);
7668 button = gtk_button_new_with_label ("prev page");
7669 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
7670 (GtkSignalFunc) gtk_notebook_prev_page,
7671 GTK_OBJECT (notebook));
7672 gtk_table_attach_defaults(GTK_TABLE(table), button, 2,3,1,2);
7673 gtk_widget_show(button);
7675 button = gtk_button_new_with_label ("tab position");
7676 gtk_signal_connect (GTK_OBJECT (button), "clicked",
7677 (GtkSignalFunc) rotate_book,
7678 GTK_OBJECT(notebook));
7679 gtk_table_attach_defaults(GTK_TABLE(table), button, 3,4,1,2);
7680 gtk_widget_show(button);
7682 button = gtk_button_new_with_label ("tabs/border on/off");
7683 gtk_signal_connect (GTK_OBJECT (button), "clicked",
7684 (GtkSignalFunc) tabsborder_book,
7685 GTK_OBJECT (notebook));
7686 gtk_table_attach_defaults(GTK_TABLE(table), button, 4,5,1,2);
7687 gtk_widget_show(button);
7689 button = gtk_button_new_with_label ("remove page");
7690 gtk_signal_connect (GTK_OBJECT (button), "clicked",
7691 (GtkSignalFunc) remove_book,
7692 GTK_OBJECT(notebook));
7693 gtk_table_attach_defaults(GTK_TABLE(table), button, 5,6,1,2);
7694 gtk_widget_show(button);
7696 gtk_widget_show(table);
7697 gtk_widget_show(window);
7706 Hopefully this helps you on your way with creating notebooks for your
7709 <!-- ***************************************************************** -->
7711 <!-- ***************************************************************** -->
7713 <!-- ----------------------------------------------------------------- -->
7715 The GtkCList widget has replaced the GtkList widget (which is still
7718 The GtkCList widget is a multi-column list widget that is capable of
7719 handling literally thousands of rows of information. Each column can
7720 optionally have a title, which itself is optionally active, allowing
7721 us to bind a function to its selection.
7723 <!-- ----------------------------------------------------------------- -->
7724 <sect1>Creating a GtkCList widget
7726 Creating a GtkCList is quite straightforward, once you have learned
7727 about widgets in general. It provides the almost standard two ways,
7728 that is the hard way, and the easy way. But before we create it, there
7729 is one thing we should figure out beforehand: how many columns should
7732 Not all columns have to be visible and can be used to store data that
7733 is related to a certain cell in the list.
7736 GtkWidget *gtk_clist_new ( gint columns );
7738 GtkWidget *gtk_clist_new_with_titles( gint columns,
7742 The first form is very straight forward, the second might require some
7743 explanation. Each column can have a title associated with it, and this
7744 title can be a label or a button that reacts when we click on it. If
7745 we use the second form, we must provide pointers to the title texts,
7746 and the number of pointers should equal the number of columns
7747 specified. Of course we can always use the first form, and manually
7750 Note: the GtkCList widget does not have its own scrollbars and should
7751 be placed within a GtkScrolledWindow widget if your require this
7752 functionality. This is a change from the GTK 1.0 implementation.
7754 <!-- ----------------------------------------------------------------- -->
7755 <sect1>Modes of operation
7757 There are several attributes that can be used to alter the behaviour of
7758 a GtkCList. First there is
7761 void gtk_clist_set_selection_mode( GtkCList *clist,
7762 GtkSelectionMode mode );
7765 which, as the name implies, sets the selection mode of the
7766 GtkCList. The first argument is the GtkCList widget, and the second
7767 specifies the cell selection mode (they are defined in gtkenums.h). At
7768 the time of this writing, the following modes are available to us:
7771 <item> GTK_SELECTION_SINGLE - The selection is either NULL or contains
7772 a GList pointer for a single selected item.
7774 <item> GTK_SELECTION_BROWSE - The selection is NULL if the list
7775 contains no widgets or insensitive ones only, otherwise it contains a
7776 GList pointer for one GList structure, and therefore exactly one list
7779 <item> GTK_SELECTION_MULTIPLE - The selection is NULL if no list items
7780 are selected or a GList pointer for the first selected item. That in
7781 turn points to a GList structure for the second selected item and so
7782 on. This is currently the <bf>default</bf> for the GtkCList widget.
7784 <item> GTK_SELECTION_EXTENDED - The selection is always NULL.
7787 Others might be added in later revisions of GTK.
7789 We can also define what the border of the GtkCList widget should look
7790 like. It is done through
7793 void gtk_clist_set_shadow_type( GtkCList *clist,
7794 GtkShadowType border );
7797 And the possible values for the second argument are
7800 <item> GTK_SHADOW_NONE
7802 <item> GTK_SHADOW_IN
7804 <item> GTK_SHADOW_OUT
7806 <item> GTK_SHADOW_ETCHED_IN
7808 <item> GTK_SHADOW_ETCHED_OUT
7811 <!-- ----------------------------------------------------------------- -->
7812 <sect1>Working with titles
7814 When you create a GtkCList widget, you will also get a set of title
7815 buttons automatically. They live in the top of the CList window, and
7816 can act either as normal buttons that respond to being pressed, or
7817 they can be passive, in which case they are nothing more than a
7818 title. There are four different calls that aid us in setting the
7819 status of the title buttons.
7822 void gtk_clist_column_title_active( GtkCList *clist,
7825 void gtk_clist_column_title_passive( GtkCList *clist,
7828 void gtk_clist_column_titles_active( GtkCList *clist );
7830 void gtk_clist_column_titles_passive( GtkCList *clist );
7833 An active title is one which acts as a normal button, a passive one is
7834 just a label. The first two calls above will activate/deactivate the
7835 title button above the specific column, while the last two calls
7836 activate/deactivate all title buttons in the supplied clist widget.
7838 But of course there are those cases when we don't want them at all,
7839 and so they can be hidden and shown at will using the following two
7843 void gtk_clist_column_titles_show( GtkCList *clist );
7845 void gtk_clist_column_titles_hide( GtkCList *clist );
7848 For titles to be really useful we need a mechanism to set and change
7849 them, and this is done using
7852 void gtk_clist_set_column_title( GtkCList *clist,
7857 Note that only the title of one column can be set at a time, so if all
7858 the titles are known from the beginning, then I really suggest using
7859 gtk_clist_new_with_titles (as described above) to set them. Saves you
7860 coding time, and makes your program smaller. There are some cases
7861 where getting the job done the manual way is better, and that's when
7862 not all titles will be text. GtkCList provides us with title buttons
7863 that can in fact incorporate whole widgets, for example a pixmap. It's
7867 void gtk_clist_set_column_widget( GtkCList *clist,
7869 GtkWidget *widget );
7872 which should require no special explanation.
7874 <!-- ----------------------------------------------------------------- -->
7875 <sect1>Manipulating the list itself
7877 It is possible to change the justification for a column, and it is
7881 void gtk_clist_set_column_justification( GtkCList *clist,
7883 GtkJustification justification );
7886 The GtkJustification type can take the following values:
7889 <item>GTK_JUSTIFY_LEFT - The text in the column will begin from the
7892 <item>GTK_JUSTIFY_RIGHT - The text in the column will begin from the
7895 <item>GTK_JUSTIFY_CENTER - The text is placed in the center of the
7898 <item>GTK_JUSTIFY_FILL - The text will use up all available space in
7899 the column. It is normally done by inserting extra blank spaces
7900 between words (or between individual letters if it's a single
7901 word). Much in the same way as any ordinary WYSIWYG text editor.
7904 The next function is a very important one, and should be standard in
7905 the setup of all GtkCList widgets. When the list is created, the width
7906 of the various columns are chosen to match their titles, and since
7907 this is seldom the right width we have to set it using
7910 void gtk_clist_set_column_width( GtkCList *clist,
7915 Note that the width is given in pixels and not letters. The same goes
7916 for the height of the cells in the columns, but as the default value
7917 is the height of the current font this isn't as critical to the
7918 application. Still, it is done through
7921 void gtk_clist_set_row_height( GtkCList *clist,
7925 Again, note that the height is given in pixels.
7927 We can also move the list around without user interaction, however, it
7928 does require that we know what we are looking for. Or in other words,
7929 we need the row and column of the item we want to scroll to.
7932 void gtk_clist_moveto( GtkCList *clist,
7939 The gfloat row_align is pretty important to understand. It's a value
7940 between 0.0 and 1.0, where 0.0 means that we should scroll the list so
7941 the row appears at the top, while if the value of row_align is 1.0,
7942 the row will appear at the bottom instead. All other values between
7943 0.0 and 1.0 are also valid and will place the row between the top and
7944 the bottom. The last argument, gfloat col_align works in the same way,
7945 though 0.0 marks left and 1.0 marks right instead.
7947 Depending on the application's needs, we don't have to scroll to an
7948 item that is already visible to us. So how do we know if it is
7949 visible? As usual, there is a function to find that out as well.
7952 GtkVisibility gtk_clist_row_is_visible( GtkCList *clist,
7956 The return value is is one of the following:
7959 <item>GTK_VISIBILITY_NONE
7961 <item>GTK_VISIBILITY_PARTIAL
7963 <item>GTK_VISIBILITY_FULL
7966 Note that it will only tell us if a row is visible. Currently there is
7967 no way to determine this for a column. We can get partial information
7968 though, because if the return is GTK_VISIBILITY_PARTIAL, then some of
7969 it is hidden, but we don't know if it is the row that is being cut by
7970 the lower edge of the listbox, or if the row has columns that are
7973 We can also change both the foreground and background colors of a
7974 particular row. This is useful for marking the row selected by the
7975 user, and the two functions that is used to do it are
7978 void gtk_clist_set_foreground( GtkCList *clist,
7982 void gtk_clist_set_background( GtkCList *clist,
7987 Please note that the colors must have been previously allocated.
7989 <!-- ----------------------------------------------------------------- -->
7990 <sect1>Adding rows to the list
7992 We can add rows in three ways. They can be prepended or appended to
7996 gint gtk_clist_prepend( GtkCList *clist,
7999 gint gtk_clist_append( GtkCList *clist,
8003 The return value of these two functions indicate the index of the row
8004 that was just added. We can insert a row at a given place using
8007 void gtk_clist_insert( GtkCList *clist,
8012 In these calls we have to provide a collection of pointers that are
8013 the texts we want to put in the columns. The number of pointers should
8014 equal the number of columns in the list. If the text[] argument is
8015 NULL, then there will be no text in the columns of the row. This is
8016 useful, for example, if we want to add pixmaps instead (something that
8017 has to be done manually).
8019 Also, please note that the numbering of both rows and columns start at 0.
8021 To remove an individual row we use
8024 void gtk_clist_remove( GtkCList *clist,
8028 There is also a call that removes all rows in the list. This is a lot
8029 faster than calling gtk_clist_remove once for each row, which is the
8033 void gtk_clist_clear( GtkCList *clist );
8036 There are also two convenience functions that should be used when a
8037 lot of changes have to be made to the list. This is to prevent the
8038 list flickering while being repeatedly updated, which may be highly
8039 annoying to the user. So instead it is a good idea to freeze the list,
8040 do the updates to it, and finally thaw it which causes the list to be
8041 updated on the screen.
8044 void gtk_clist_freeze( GtkCList * clist );
8046 void gtk_clist_thaw( GtkCList * clist );
8049 <!-- ----------------------------------------------------------------- -->
8050 <sect1>Setting text and pixmaps in the cells
8052 A cell can contain a pixmap, text or both. To set them the following
8056 void gtk_clist_set_text( GtkCList *clist,
8061 void gtk_clist_set_pixmap( GtkCList *clist,
8067 void gtk_clist_set_pixtext( GtkCList *clist,
8076 It's quite straightforward. All the calls have the GtkCList as the
8077 first argument, followed by the row and column of the cell, followed
8078 by the data to be set. The <tt/spacing/ argument in
8079 gtk_clist_set_pixtext is the number of pixels between the pixmap and
8080 the beginning of the text.
8082 To read back the data, we instead use
8085 gint gtk_clist_get_text( GtkCList *clist,
8090 gint gtk_clist_get_pixmap( GtkCList *clist,
8096 gint gtk_clist_get_pixtext( GtkCList *clist,
8105 It isn't necessary to read it all back in case you aren't
8106 interested. Any of the pointers that are meant for return values (all
8107 except the clist) can be NULL. So if we want to read back only the
8108 text from a cell that is of type pixtext, then we would do the
8109 following, assuming that clist, row and column already exist:
8114 gtk_clist_get_pixtext(clist, row, column, &mytext, NULL, NULL, NULL);
8117 There is one more call that is related to what's inside a cell in the
8121 GtkCellType gtk_clist_get_cell_type( GtkCList *clist,
8126 which returns the type of data in a cell. The return value is one of
8129 <item>GTK_CELL_EMPTY
8133 <item>GTK_CELL_PIXMAP
8135 <item>GTK_CELL_PIXTEXT
8137 <item>GTK_CELL_WIDGET
8140 There is also a function that will let us set the indentation, both
8141 vertical and horizontal, of a cell. The indentation value is of type
8142 gint, given in pixels, and can be both positive and negative.
8145 void gtk_clist_set_shift( GtkCList *clist,
8152 <!-- ----------------------------------------------------------------- -->
8153 <sect1>Storing data pointers
8155 With a GtkCList it is possible to set a data pointer for a row. This
8156 pointer will not be visible for the user, but is merely a convenience
8157 for the programmer to associate a row with a pointer to some
8160 The functions should be fairly self-explanatory by now
8163 void gtk_clist_set_row_data( GtkCList *clist,
8167 void gtk_clist_set_row_data_full( GtkCList *clist,
8170 GtkDestroyNotify destroy );
8172 gpointer gtk_clist_get_row_data( GtkCList *clist,
8175 gint gtk_clist_find_row_from_data( GtkCList *clist,
8179 <!-- ----------------------------------------------------------------- -->
8180 <sect1>Working with selections
8182 There are also functions available that let us force the (un)selection
8186 void gtk_clist_select_row( GtkCList *clist,
8190 void gtk_clist_unselect_row( GtkCList *clist,
8195 And also a function that will take x and y coordinates (for example,
8196 read from the mousepointer), and map that onto the list, returning the
8197 corresponding row and column.
8200 gint gtk_clist_get_selection_info( GtkCList *clist,
8207 When we detect something of interest, it might be movement of the
8208 pointer, a click somewhere in the list, we can read the pointer
8209 coordinates and find out where in the list the pointer is. Cumbersome?
8210 Luckily, there is a simpler way...
8212 <!-- ----------------------------------------------------------------- -->
8213 <sect1>The signals that bring it together
8215 As with all other widgets, there are a few signals that can be used. The
8216 GtkCList widget is derived from the GtkContainer widget, and so has all the
8217 same signals, but also the adds following:
8220 <item>select_row - This signal will send the following information, in
8221 order: GtkCList *clist, gint row, gint column, GtkEventButton *event
8223 <item>unselect_row - When the user unselects a row, this signal is
8224 activated. It sends the same information as select_row
8226 <item>click_column - Send GtkCList *clist, gint column
8229 So if we want to connect a callback to select_row, the callback
8230 function would be declared like this
8233 void select_row_callback(GtkWidget *widget,
8236 GdkEventButton *event,
8240 The callback is connected as usual with
8243 gtk_signal_connect(GTK_OBJECT( clist),
8245 GTK_SIGNAL_FUNC(select_row_callback),
8249 <!-- ----------------------------------------------------------------- -->
8250 <sect1>A GtkCList example
8254 /* example-start clist clist.c */
8256 #include <gtk/gtk.h>
8258 /* User clicked the "Add List" button. */
8259 void button_add_clicked( gpointer data )
8263 /* Something silly to add to the list. 4 rows of 2 columns each */
8264 gchar *drink[4][2] = { { "Milk", "3 Oz" },
8267 { "Snakes", "55" } };
8269 /* Here we do the actual adding of the text. It's done once for
8272 for ( indx=0 ; indx < 4 ; indx++ )
8273 gtk_clist_append( (GtkCList *) data, drink[indx]);
8278 /* User clicked the "Clear List" button. */
8279 void button_clear_clicked( gpointer data )
8281 /* Clear the list using gtk_clist_clear. This is much faster than
8282 * calling gtk_clist_remove once for each row.
8284 gtk_clist_clear( (GtkCList *) data);
8289 /* The user clicked the "Hide/Show titles" button. */
8290 void button_hide_show_clicked( gpointer data )
8292 /* Just a flag to remember the status. 0 = currently visible */
8293 static short int flag = 0;
8297 /* Hide the titles and set the flag to 1 */
8298 gtk_clist_column_titles_hide((GtkCList *) data);
8303 /* Show the titles and reset flag to 0 */
8304 gtk_clist_column_titles_show((GtkCList *) data);
8311 /* If we come here, then the user has selected a row in the list. */
8312 void selection_made( GtkWidget *clist,
8315 GdkEventButton *event,
8320 /* Get the text that is stored in the selected row and column
8321 * which was clicked in. We will receive it as a pointer in the
8324 gtk_clist_get_text(GTK_CLIST(clist), row, column, &text);
8326 /* Just prints some information about the selected row */
8327 g_print("You selected row %d. More specifically you clicked in "
8328 "column %d, and the text in this cell is %s\n\n",
8338 GtkWidget *vbox, *hbox;
8340 GtkWidget *button_add, *button_clear, *button_hide_show;
8341 gchar *titles[2] = { "Ingredients", "Amount" };
8343 gtk_init(&argc, &argv);
8345 window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
8346 gtk_widget_set_usize(GTK_WIDGET(window), 300, 150);
8348 gtk_window_set_title(GTK_WINDOW(window), "GtkCList Example");
8349 gtk_signal_connect(GTK_OBJECT(window),
8351 GTK_SIGNAL_FUNC(gtk_main_quit),
8354 vbox=gtk_vbox_new(FALSE, 5);
8355 gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
8356 gtk_container_add(GTK_CONTAINER(window), vbox);
8357 gtk_widget_show(vbox);
8359 /* Create the GtkCList. For this example we use 2 columns */
8360 clist = gtk_clist_new_with_titles( 2, titles);
8362 /* When a selection is made, we want to know about it. The callback
8363 * used is selection_made, and its code can be found further down */
8364 gtk_signal_connect(GTK_OBJECT(clist), "select_row",
8365 GTK_SIGNAL_FUNC(selection_made),
8368 /* It isn't necessary to shadow the border, but it looks nice :) */
8369 gtk_clist_set_shadow_type (GTK_CLIST(clist), GTK_SHADOW_OUT);
8371 /* What however is important, is that we set the column widths as
8372 * they will never be right otherwise. Note that the columns are
8373 * numbered from 0 and up (to 1 in this case).
8375 gtk_clist_set_column_width (GTK_CLIST(clist), 0, 150);
8377 /* Add the GtkCList widget to the vertical box and show it. */
8378 gtk_box_pack_start(GTK_BOX(vbox), clist, TRUE, TRUE, 0);
8379 gtk_widget_show(clist);
8381 /* Create the buttons and add them to the window. See the button
8382 * tutorial for more examples and comments on this.
8384 hbox = gtk_hbox_new(FALSE, 0);
8385 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
8386 gtk_widget_show(hbox);
8388 button_add = gtk_button_new_with_label("Add List");
8389 button_clear = gtk_button_new_with_label("Clear List");
8390 button_hide_show = gtk_button_new_with_label("Hide/Show titles");
8392 gtk_box_pack_start(GTK_BOX(hbox), button_add, TRUE, TRUE, 0);
8393 gtk_box_pack_start(GTK_BOX(hbox), button_clear, TRUE, TRUE, 0);
8394 gtk_box_pack_start(GTK_BOX(hbox), button_hide_show, TRUE, TRUE, 0);
8396 /* Connect our callbacks to the three buttons */
8397 gtk_signal_connect_object(GTK_OBJECT(button_add), "clicked",
8398 GTK_SIGNAL_FUNC(button_add_clicked),
8400 gtk_signal_connect_object(GTK_OBJECT(button_clear), "clicked",
8401 GTK_SIGNAL_FUNC(button_clear_clicked),
8403 gtk_signal_connect_object(GTK_OBJECT(button_hide_show), "clicked",
8404 GTK_SIGNAL_FUNC(button_hide_show_clicked),
8407 gtk_widget_show(button_add);
8408 gtk_widget_show(button_clear);
8409 gtk_widget_show(button_hide_show);
8411 /* The interface is completely set up so we show the window and
8412 * enter the gtk_main loop.
8414 gtk_widget_show(window);
8422 <!-- ***************************************************************** -->
8423 <sect> Tree Widget <label id="sec_Tree_Widgets">
8424 <!-- ***************************************************************** -->
8426 The purpose of tree widgets is to display hierarchically-organized
8427 data. The GtkTree widget itself is a vertical container for widgets of
8428 type GtkTreeItem. GtkTree itself is not terribly different from
8429 GtkList - both are derived directly from GtkContainer, and the
8430 GtkContainer methods work in the same way on GtkTree widgets as on
8431 GtkList widgets. The difference is that GtkTree widgets can be nested
8432 within other GtkTree widgets. We'll see how to do this shortly.
8434 The GtkTree widget has its own window, and defaults to a white
8435 background, as does GtkList. Also, most of the GtkTree methods work in
8436 the same way as the corresponding GtkList ones. However, GtkTree is
8437 not derived from GtkList, so you cannot use them interchangeably.
8439 <sect1> Creating a Tree
8441 A GtkTree is created in the usual way, using:
8444 GtkWidget *gtk_tree_new( void );
8447 Like the GtkList widget, a GtkTree will simply keep growing as more
8448 items are added to it, as well as when subtrees are expanded. For
8449 this reason, they are almost always packed into a
8450 GtkScrolledWindow. You might want to use gtk_widget_set_usize() on the
8451 scrolled window to ensure that it is big enough to see the tree's
8452 items, as the default size for GtkScrolledWindow is quite small.
8454 Now that you have a tree, you'll probably want to add some items to
8455 it. <ref id="sec_Tree_Item_Widget" name="The Tree Item Widget"> below
8456 explains the gory details of GtkTreeItem. For now, it'll suffice to
8460 GtkWidget *gtk_tree_item_new_with_label( gchar *label );
8463 You can then add it to the tree using one of the following (see
8464 <ref id="sec_GtkTree_Functions" name="Functions and Macros">
8465 below for more options):
8468 void gtk_tree_append( GtkTree *tree,
8469 GtkWidget *tree_item );
8471 void gtk_tree_prepend( GtkTree *tree,
8472 GtkWidget *tree_item );
8475 Note that you must add items to a GtkTree one at a time - there is no
8476 equivalent to gtk_list_*_items().
8478 <!-- ----------------------------------------------------------------- -->
8479 <sect1> Adding a Subtree
8481 A subtree is created like any other GtkTree widget. A subtree is added
8482 to another tree beneath a tree item, using:
8485 void gtk_tree_item_set_subtree( GtkTreeItem *tree_item,
8486 GtkWidget *subtree );
8489 You do not need to call gtk_widget_show() on a subtree before or after
8490 adding it to a GtkTreeItem. However, you <em>must</em> have added the
8491 GtkTreeItem in question to a parent tree before calling
8492 gtk_tree_item_set_subtree(). This is because, technically, the parent
8493 of the subtree is <em>not</em> the GtkTreeItem which "owns" it, but
8494 rather the GtkTree which holds that GtkTreeItem.
8496 When you add a subtree to a GtkTreeItem, a plus or minus sign appears
8497 beside it, which the user can click on to "expand" or "collapse" it,
8498 meaning, to show or hide its subtree. GtkTreeItems are collapsed by
8499 default. Note that when you collapse a GtkTreeItem, any selected
8500 items in its subtree remain selected, which may not be what the user
8503 <!-- ----------------------------------------------------------------- -->
8504 <sect1> Handling the Selection List
8506 As with GtkList, the GtkTree type has a <tt>selection</tt> field, and
8507 it is possible to control the behaviour of the tree (somewhat) by
8508 setting the selection type using:
8511 void gtk_tree_set_selection_mode( GtkTree *tree,
8512 GtkSelectionMode mode );
8515 The semantics associated with the various selection modes are
8516 described in the section on the GtkList widget. As with the GtkList
8517 widget, the "select_child", "unselect_child" (not really - see <ref
8518 id="sec_GtkTree_Signals" name="Signals"> below for an explanation),
8519 and "selection_changed" signals are emitted when list items are
8520 selected or unselected. However, in order to take advantage of these
8521 signals, you need to know <em>which</em> GtkTree widget they will be
8522 emitted by, and where to find the list of selected items.
8524 This is a source of potential confusion. The best way to explain this
8525 is that though all GtkTree widgets are created equal, some are more
8526 equal than others. All GtkTree widgets have their own X window, and
8527 can therefore receive events such as mouse clicks (if their
8528 GtkTreeItems or their children don't catch them first!). However, to
8529 make GTK_SELECTION_SINGLE and GTK_SELECTION_BROWSE selection types
8530 behave in a sane manner, the list of selected items is specific to the
8531 topmost GtkTree widget in a hierarchy, known as the "root tree".
8533 Thus, accessing the <tt>selection</tt>field directly in an arbitrary
8534 GtkTree widget is not a good idea unless you <em>know</em> it's the
8535 root tree. Instead, use the GTK_TREE_SELECTION (Tree) macro, which
8536 gives the root tree's selection list as a GList pointer. Of course,
8537 this list can include items that are not in the subtree in question if
8538 the selection type is GTK_SELECTION_MULTIPLE.
8540 Finally, the "select_child" (and "unselect_child", in theory) signals
8541 are emitted by all trees, but the "selection_changed" signal is only
8542 emitted by the root tree. Consequently, if you want to handle the
8543 "select_child" signal for a tree and all its subtrees, you will have
8544 to call gtk_signal_connect() for every subtree.
8546 <sect1> Tree Widget Internals
8548 The GtkTree's struct definition looks like this:
8553 GtkContainer container;
8557 GtkTree* root_tree; /* owner of selection list */
8558 GtkWidget* tree_owner;
8562 guint current_indent;
8563 guint selection_mode : 2;
8564 guint view_mode : 1;
8565 guint view_line : 1;
8569 The perils associated with accessing the <tt>selection</tt> field
8570 directly have already been mentioned. The other important fields of
8571 the struct can also be accessed with handy macros or class functions.
8572 GTK_TREE_IS_ROOT_TREE (Tree) returns a boolean value which indicates
8573 whether a tree is the root tree in a GtkTree hierarchy, while
8574 GTK_TREE_ROOT_TREE (Tree) returns the root tree, an object of type
8575 GtkTree (so, remember to cast it using GTK_WIDGET (Tree) if you want
8576 to use one of the gtk_widget_*() functions on it).
8578 Instead of directly accessing the children field of a GtkTree widget,
8579 it's probably best to cast it using GTK_CONTAINER (Tree), and pass it
8580 to the gtk_container_children() function. This creates a duplicate of
8581 the original list, so it's advisable to free it up using g_list_free()
8582 after you're done with it, or to iterate on it destructively, like
8586 children = gtk_container_children (GTK_CONTAINER (tree));
8588 do_something_nice (GTK_TREE_ITEM (children->data));
8589 children = g_list_remove_link (children, children);
8593 The <tt>tree_owner</tt> field is defined only in subtrees, where it
8594 points to the GtkTreeItem widget which holds the tree in question.
8595 The <tt>level</tt> field indicates how deeply nested a particular tree
8596 is; root trees have level 0, and each successive level of subtrees has
8597 a level one greater than the parent level. This field is set only
8598 after a GtkTree widget is actually mapped (i.e. drawn on the screen).
8600 <sect2> Signals<label id="sec_GtkTree_Signals">
8603 void selection_changed( GtkTree *tree );
8606 This signal will be emitted whenever the <tt>selection</tt> field of a
8607 GtkTree has changed. This happens when a child of the GtkTree is
8608 selected or deselected.
8611 void select_child( GtkTree *tree,
8615 This signal is emitted when a child of the GtkTree is about to get
8616 selected. This happens on calls to gtk_tree_select_item(),
8617 gtk_tree_select_child(), on <em>all</em> button presses and calls to
8618 gtk_tree_item_toggle() and gtk_item_toggle(). It may sometimes be
8619 indirectly triggered on other occasions where children get added to or
8620 removed from the GtkTree.
8623 void unselect_child (GtkTree *tree,
8627 This signal is emitted when a child of the GtkTree is about to get
8628 deselected. As of GTK+ 1.0.4, this seems to only occur on calls to
8629 gtk_tree_unselect_item() or gtk_tree_unselect_child(), and perhaps on
8630 other occasions, but <em>not</em> when a button press deselects a
8631 child, nor on emission of the "toggle" signal by gtk_item_toggle().
8633 <sect2> Functions and Macros<label id="sec_GtkTree_Functions">
8636 guint gtk_tree_get_type( void );
8639 Returns the `GtkTree' type identifier.
8642 GtkWidget* gtk_tree_new( void );
8645 Create a new GtkTree object. The new widget is returned as a pointer
8646 to a GtkWidget object. NULL is returned on failure.
8649 void gtk_tree_append( GtkTree *tree,
8650 GtkWidget *tree_item );
8653 Append a tree item to a GtkTree.
8656 void gtk_tree_prepend( GtkTree *tree,
8657 GtkWidget *tree_item );
8660 Prepend a tree item to a GtkTree.
8663 void gtk_tree_insert( GtkTree *tree,
8664 GtkWidget *tree_item,
8668 Insert a tree item into a GtkTree at the position in the list
8669 specified by <tt>position.</tt>
8672 void gtk_tree_remove_items( GtkTree *tree,
8676 Remove a list of items (in the form of a GList *) from a GtkTree.
8677 Note that removing an item from a tree dereferences (and thus usually)
8678 destroys it <em>and</em> its subtree, if it has one, <em>and</em> all
8679 subtrees in that subtree. If you want to remove only one item, you
8680 can use gtk_container_remove().
8683 void gtk_tree_clear_items( GtkTree *tree,
8688 Remove the items from position <tt>start</tt> to position <tt>end</tt>
8689 from a GtkTree. The same warning about dereferencing applies here, as
8690 gtk_tree_clear_items() simply constructs a list and passes it to
8691 gtk_tree_remove_items().
8694 void gtk_tree_select_item( GtkTree *tree,
8698 Emits the "select_item" signal for the child at position
8699 <tt>item</tt>, thus selecting the child (unless you unselect it in a
8703 void gtk_tree_unselect_item( GtkTree *tree,
8707 Emits the "unselect_item" signal for the child at position
8708 <tt>item</tt>, thus unselecting the child.
8711 void gtk_tree_select_child( GtkTree *tree,
8712 GtkWidget *tree_item );
8715 Emits the "select_item" signal for the child <tt>tree_item</tt>, thus
8719 void gtk_tree_unselect_child( GtkTree *tree,
8720 GtkWidget *tree_item );
8723 Emits the "unselect_item" signal for the child <tt>tree_item</tt>,
8724 thus unselecting it.
8727 gint gtk_tree_child_position( GtkTree *tree,
8731 Returns the position in the tree of <tt>child</tt>, unless
8732 <tt>child</tt> is not in the tree, in which case it returns -1.
8735 void gtk_tree_set_selection_mode( GtkTree *tree,
8736 GtkSelectionMode mode );
8739 Sets the selection mode, which can be one of GTK_SELECTION_SINGLE (the
8740 default), GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE, or
8741 GTK_SELECTION_EXTENDED. This is only defined for root trees, which
8742 makes sense, since the root tree "owns" the selection. Setting it for
8743 subtrees has no effect at all; the value is simply ignored.
8746 void gtk_tree_set_view_mode( GtkTree *tree,
8747 GtkTreeViewMode mode );
8750 Sets the "view mode", which can be either GTK_TREE_VIEW_LINE (the
8751 default) or GTK_TREE_VIEW_ITEM. The view mode propagates from a tree
8752 to its subtrees, and can't be set exclusively to a subtree (this is
8753 not exactly true - see the example code comments).
8755 The term "view mode" is rather ambiguous - basically, it controls the
8756 way the highlight is drawn when one of a tree's children is selected.
8757 If it's GTK_TREE_VIEW_LINE, the entire GtkTreeItem widget is
8758 highlighted, while for GTK_TREE_VIEW_ITEM, only the child widget
8759 (i.e. usually the label) is highlighted.
8762 void gtk_tree_set_view_lines( GtkTree *tree,
8766 Controls whether connecting lines between tree items are drawn.
8767 <tt>flag</tt> is either TRUE, in which case they are, or FALSE, in
8768 which case they aren't.
8771 GtkTree *GTK_TREE (gpointer obj);
8774 Cast a generic pointer to `GtkTree *'.
8777 GtkTreeClass *GTK_TREE_CLASS (gpointer class);
8780 Cast a generic pointer to `GtkTreeClass*'.
8783 gint GTK_IS_TREE (gpointer obj);
8786 Determine if a generic pointer refers to a `GtkTree' object.
8789 gint GTK_IS_ROOT_TREE (gpointer obj)
8792 Determine if a generic pointer refers to a `GtkTree' object
8793 <em>and</em> is a root tree. Though this will accept any pointer, the
8794 results of passing it a pointer that does not refer to a GtkTree are
8795 undefined and possibly harmful.
8798 GtkTree *GTK_TREE_ROOT_TREE (gpointer obj)
8801 Return the root tree of a pointer to a `GtkTree' object. The above
8805 GList *GTK_TREE_SELECTION( gpointer obj)
8808 Return the selection list of the root tree of a `GtkTree' object. The
8809 above warning applies here, too.
8811 <sect1> Tree Item Widget<label id="sec_Tree_Item_Widget">
8813 The GtkTreeItem widget, like GtkListItem, is derived from GtkItem,
8814 which in turn is derived from GtkBin. Therefore, the item itself is a
8815 generic container holding exactly one child widget, which can be of
8816 any type. The GtkTreeItem widget has a number of extra fields, but
8817 the only one we need be concerned with is the <tt>subtree</tt> field.
8819 The definition for the GtkTreeItem struct looks like this:
8827 GtkWidget *pixmaps_box;
8828 GtkWidget *plus_pix_widget, *minus_pix_widget;
8830 GList *pixmaps; /* pixmap node for this items color depth */
8836 The <tt>pixmaps_box</tt> field is a GtkEventBox which catches clicks
8837 on the plus/minus symbol which controls expansion and collapsing. The
8838 <tt>pixmaps</tt> field points to an internal data structure. Since
8839 you can always obtain the subtree of a GtkTreeItem in a (relatively)
8840 type-safe manner with the GTK_TREE_ITEM_SUBTREE (Item) macro, it's
8841 probably advisable never to touch the insides of a GtkTreeItem unless
8842 you <em>really</em> know what you're doing.
8844 Since it is directly derived from a GtkItem it can be treated as such
8845 by using the GTK_ITEM (TreeItem) macro. A GtkTreeItem usually holds a
8846 label, so the convenience function gtk_list_item_new_with_label() is
8847 provided. The same effect can be achieved using code like the
8848 following, which is actually copied verbatim from
8849 gtk_tree_item_new_with_label():
8852 tree_item = gtk_tree_item_new ();
8853 label_widget = gtk_label_new (label);
8854 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
8856 gtk_container_add (GTK_CONTAINER (tree_item), label_widget);
8857 gtk_widget_show (label_widget);
8860 As one is not forced to add a GtkLabel to a GtkTreeItem, you could
8861 also add a GtkHBox or a GtkArrow, or even a GtkNotebook (though your
8862 app will likely be quite unpopular in this case) to the GtkTreeItem.
8864 If you remove all the items from a subtree, it will be destroyed and
8865 unparented, unless you reference it beforehand, and the GtkTreeItem
8866 which owns it will be collapsed. So, if you want it to stick around,
8867 do something like the following:
8870 gtk_widget_ref (tree);
8871 owner = GTK_TREE(tree)->tree_owner;
8872 gtk_container_remove (GTK_CONTAINER(tree), item);
8873 if (tree->parent == NULL){
8874 gtk_tree_item_expand (GTK_TREE_ITEM(owner));
8875 gtk_tree_item_set_subtree (GTK_TREE_ITEM(owner), tree);
8878 gtk_widget_unref (tree);
8881 Finally, drag-n-drop <em>does</em> work with GtkTreeItems. You just
8882 have to make sure that the GtkTreeItem you want to make into a drag
8883 item or a drop site has not only been added to a GtkTree, but that
8884 each successive parent widget has a parent itself, all the way back to
8885 a toplevel or dialog window, when you call gtk_widget_dnd_drag_set()
8886 or gtk_widget_dnd_drop_set(). Otherwise, strange things will happen.
8890 GtkTreeItem inherits the "select", "deselect", and "toggle" signals
8891 from GtkItem. In addition, it adds two signals of its own, "expand"
8895 void select( GtkItem *tree_item );
8898 This signal is emitted when an item is about to be selected, either
8899 after it has been clicked on by the user, or when the program calls
8900 gtk_tree_item_select(), gtk_item_select(), or gtk_tree_select_child().
8903 void deselect( GtkItem *tree_item );
8906 This signal is emitted when an item is about to be unselected, either
8907 after it has been clicked on by the user, or when the program calls
8908 gtk_tree_item_deselect() or gtk_item_deselect(). In the case of
8909 GtkTreeItems, it is also emitted by gtk_tree_unselect_child(), and
8910 sometimes gtk_tree_select_child().
8913 void toggle( GtkItem *tree_item );
8916 This signal is emitted when the program calls gtk_item_toggle(). The
8917 effect it has when emitted on a GtkTreeItem is to call
8918 gtk_tree_select_child() (and never gtk_tree_unselect_child()) on the
8919 item's parent tree, if the item has a parent tree. If it doesn't,
8920 then the highlight is reversed on the item.
8923 void expand( GtkTreeItem *tree_item );
8926 This signal is emitted when the tree item's subtree is about to be
8927 expanded, that is, when the user clicks on the plus sign next to the
8928 item, or when the program calls gtk_tree_item_expand().
8931 void collapse( GtkTreeItem *tree_item );
8934 This signal is emitted when the tree item's subtree is about to be
8935 collapsed, that is, when the user clicks on the minus sign next to the
8936 item, or when the program calls gtk_tree_item_collapse().
8938 <sect2> Functions and Macros
8941 guint gtk_tree_item_get_type( void );
8944 Returns the `GtkTreeItem' type identifier.
8947 GtkWidget* gtk_tree_item_new( void );
8950 Create a new GtkTreeItem object. The new widget is returned as a
8951 pointer to a GtkWidget object. NULL is returned on failure.
8954 GtkWidget* gtk_tree_item_new_with_label (gchar *label);
8957 Create a new GtkTreeItem object, having a single GtkLabel as the sole
8958 child. The new widget is returned as a pointer to a GtkWidget
8959 object. NULL is returned on failure.
8962 void gtk_tree_item_select( GtkTreeItem *tree_item );
8965 This function is basically a wrapper around a call to gtk_item_select
8966 (GTK_ITEM (tree_item)) which will emit the select signal.
8969 void gtk_tree_item_deselect( GtkTreeItem *tree_item );
8972 This function is basically a wrapper around a call to
8973 gtk_item_deselect (GTK_ITEM (tree_item)) which will emit the deselect
8977 void gtk_tree_item_set_subtree( GtkTreeItem *tree_item,
8978 GtkWidget *subtree );
8981 This function adds subtree to tree_item, showing it if tree_item is
8982 expanded, or hiding it if tree_item is collapsed. Again, remember that
8983 the tree_item must have already been added to a tree for this to work.
8986 void gtk_tree_item_remove_subtree( GtkTreeItem *tree_item );
8989 This removes all of tree_item's subtree's children (thus unreferencing
8990 and destroying it, any of its children's subtrees, and so on...), then
8991 removes the subtree itself, and hides the plus/minus sign.
8994 void gtk_tree_item_expand( GtkTreeItem *tree_item );
8997 This emits the "expand" signal on tree_item, which expands it.
9000 void gtk_tree_item_collapse( GtkTreeItem *tree_item );
9003 This emits the "collapse" signal on tree_item, which collapses it.
9006 GtkTreeItem *GTK_TREE_ITEM (gpointer obj)
9009 Cast a generic pointer to `GtkTreeItem*'.
9012 GtkTreeItemClass *GTK_TREE_ITEM_CLASS (gpointer obj)
9015 Cast a generic pointer to `GtkTreeItemClass'.
9018 gint GTK_IS_TREE_ITEM (gpointer obj)
9021 Determine if a generic pointer refers to a `GtkTreeItem' object.
9024 GtkWidget GTK_TREE_ITEM_SUBTREE (gpointer obj)
9027 Returns a tree item's subtree (obj should point to a `GtkTreeItem'
9030 <sect1> Tree Example
9032 This is somewhat like the tree example in testgtk.c, but a lot less
9033 complete (although much better commented). It puts up a window with a
9034 tree, and connects all the signals for the relevant objects, so you
9035 can see when they are emitted.
9038 /* example-start tree tree.c */
9040 #include <gtk/gtk.h>
9042 /* for all the GtkItem:: and GtkTreeItem:: signals */
9043 static void cb_itemsignal (GtkWidget *item, gchar *signame)
9048 /* It's a GtkBin, so it has one child, which we know to be a
9049 label, so get that */
9050 label = GTK_LABEL (GTK_BIN (item)->child);
9051 /* Get the text of the label */
9052 gtk_label_get (label, &name);
9053 /* Get the level of the tree which the item is in */
9054 g_print ("%s called for item %s->%p, level %d\n", signame, name,
9055 item, GTK_TREE (item->parent)->level);
9058 /* Note that this is never called */
9059 static void cb_unselect_child (GtkWidget *root_tree, GtkWidget *child,
9062 g_print ("unselect_child called for root tree %p, subtree %p, child %p\n",
9063 root_tree, subtree, child);
9066 /* Note that this is called every time the user clicks on an item,
9067 whether it is already selected or not. */
9068 static void cb_select_child (GtkWidget *root_tree, GtkWidget *child,
9071 g_print ("select_child called for root tree %p, subtree %p, child %p\n",
9072 root_tree, subtree, child);
9075 static void cb_selection_changed (GtkWidget *tree)
9079 g_print ("selection_change called for tree %p\n", tree);
9080 g_print ("selected objects are:\n");
9082 i = GTK_TREE_SELECTION(tree);
9088 /* Get a GtkWidget pointer from the list node */
9089 item = GTK_WIDGET (i->data);
9090 label = GTK_LABEL (GTK_BIN (item)->child);
9091 gtk_label_get (label, &name);
9092 g_print ("\t%s on level %d\n", name, GTK_TREE
9093 (item->parent)->level);
9098 int main (int argc, char *argv[])
9100 GtkWidget *window, *scrolled_win, *tree;
9101 static gchar *itemnames[] = {"Foo", "Bar", "Baz", "Quux",
9105 gtk_init (&argc, &argv);
9107 /* a generic toplevel window */
9108 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9109 gtk_signal_connect (GTK_OBJECT(window), "delete_event",
9110 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
9111 gtk_container_set_border_width (GTK_CONTAINER(window), 5);
9113 /* A generic scrolled window */
9114 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
9115 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
9116 GTK_POLICY_AUTOMATIC,
9117 GTK_POLICY_AUTOMATIC);
9118 gtk_widget_set_usize (scrolled_win, 150, 200);
9119 gtk_container_add (GTK_CONTAINER(window), scrolled_win);
9120 gtk_widget_show (scrolled_win);
9122 /* Create the root tree */
9123 tree = gtk_tree_new();
9124 g_print ("root tree is %p\n", tree);
9125 /* connect all GtkTree:: signals */
9126 gtk_signal_connect (GTK_OBJECT(tree), "select_child",
9127 GTK_SIGNAL_FUNC(cb_select_child), tree);
9128 gtk_signal_connect (GTK_OBJECT(tree), "unselect_child",
9129 GTK_SIGNAL_FUNC(cb_unselect_child), tree);
9130 gtk_signal_connect (GTK_OBJECT(tree), "selection_changed",
9131 GTK_SIGNAL_FUNC(cb_selection_changed), tree);
9132 /* Add it to the scrolled window */
9133 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW(scrolled_win),
9135 /* Set the selection mode */
9136 gtk_tree_set_selection_mode (GTK_TREE(tree),
9137 GTK_SELECTION_MULTIPLE);
9139 gtk_widget_show (tree);
9141 for (i = 0; i < 5; i++){
9142 GtkWidget *subtree, *item;
9145 /* Create a tree item */
9146 item = gtk_tree_item_new_with_label (itemnames[i]);
9147 /* Connect all GtkItem:: and GtkTreeItem:: signals */
9148 gtk_signal_connect (GTK_OBJECT(item), "select",
9149 GTK_SIGNAL_FUNC(cb_itemsignal), "select");
9150 gtk_signal_connect (GTK_OBJECT(item), "deselect",
9151 GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
9152 gtk_signal_connect (GTK_OBJECT(item), "toggle",
9153 GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
9154 gtk_signal_connect (GTK_OBJECT(item), "expand",
9155 GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
9156 gtk_signal_connect (GTK_OBJECT(item), "collapse",
9157 GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
9158 /* Add it to the parent tree */
9159 gtk_tree_append (GTK_TREE(tree), item);
9160 /* Show it - this can be done at any time */
9161 gtk_widget_show (item);
9162 /* Create this item's subtree */
9163 subtree = gtk_tree_new();
9164 g_print ("-> item %s->%p, subtree %p\n", itemnames[i], item,
9167 /* This is still necessary if you want these signals to be called
9168 for the subtree's children. Note that selection_change will be
9169 signalled for the root tree regardless. */
9170 gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
9171 GTK_SIGNAL_FUNC(cb_select_child), subtree);
9172 gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
9173 GTK_SIGNAL_FUNC(cb_unselect_child), subtree);
9174 /* This has absolutely no effect, because it is completely ignored
9176 gtk_tree_set_selection_mode (GTK_TREE(subtree),
9177 GTK_SELECTION_SINGLE);
9178 /* Neither does this, but for a rather different reason - the
9179 view_mode and view_line values of a tree are propagated to
9180 subtrees when they are mapped. So, setting it later on would
9181 actually have a (somewhat unpredictable) effect */
9182 gtk_tree_set_view_mode (GTK_TREE(subtree), GTK_TREE_VIEW_ITEM);
9183 /* Set this item's subtree - note that you cannot do this until
9184 AFTER the item has been added to its parent tree! */
9185 gtk_tree_item_set_subtree (GTK_TREE_ITEM(item), subtree);
9187 for (j = 0; j < 5; j++){
9190 /* Create a subtree item, in much the same way */
9191 subitem = gtk_tree_item_new_with_label (itemnames[j]);
9192 /* Connect all GtkItem:: and GtkTreeItem:: signals */
9193 gtk_signal_connect (GTK_OBJECT(subitem), "select",
9194 GTK_SIGNAL_FUNC(cb_itemsignal), "select");
9195 gtk_signal_connect (GTK_OBJECT(subitem), "deselect",
9196 GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
9197 gtk_signal_connect (GTK_OBJECT(subitem), "toggle",
9198 GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
9199 gtk_signal_connect (GTK_OBJECT(subitem), "expand",
9200 GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
9201 gtk_signal_connect (GTK_OBJECT(subitem), "collapse",
9202 GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
9203 g_print ("-> -> item %s->%p\n", itemnames[j], subitem);
9204 /* Add it to its parent tree */
9205 gtk_tree_append (GTK_TREE(subtree), subitem);
9207 gtk_widget_show (subitem);
9211 /* Show the window and loop endlessly */
9212 gtk_widget_show (window);
9219 <!-- ***************************************************************** -->
9221 <!-- ***************************************************************** -->
9223 There are two ways to create menus, there's the easy way, and there's
9224 the hard way. Both have their uses, but you can usually use the
9225 itemfactory (the easy way). The "hard" way is to create all the menus
9226 using the calls directly. The easy way is to use the gtk_item_factory
9227 calls. This is much simpler, but there are advantages and
9228 disadvantages to each approach.
9230 The itemfactory is much easier to use, and to add new menus to,
9231 although writing a few wrapper functions to create menus using the
9232 manual method could go a long way towards usability. With the
9233 itemfactory, it is not possible to add images or the character '/' to
9236 <!-- ----------------------------------------------------------------- -->
9237 <sect1>Manual Menu Creation
9239 In the true tradition of teaching, we'll show you the hard way
9242 There are three widgets that go into making a menubar and submenus:
9244 <item>a menu item, which is what the user wants to select, e.g. 'Save'
9245 <item>a menu, which acts as a container for the menu items, and
9246 <item>a menubar, which is a container for each of the individual
9250 This is slightly complicated by the fact that menu item widgets are
9251 used for two different things. They are both the widgets that are
9252 packed into the menu, and the widget that is packed into the menubar,
9253 which, when selected, activates the menu.
9255 Let's look at the functions that are used to create menus and
9256 menubars. This first function is used to create a new menubar.
9260 GtkWidget *gtk_menu_bar_new( void );
9264 This rather self explanatory function creates a new menubar. You use
9265 gtk_container_add to pack this into a window, or the box_pack
9266 functions to pack it into a box - the same as buttons.
9269 GtkWidget *gtk_menu_new( void );
9272 This function returns a pointer to a new menu, it is never actually
9273 shown (with gtk_widget_show), it is just a container for the menu
9274 items. Hopefully this will become more clear when you look at the
9277 The next two calls are used to create menu items that are packed into
9278 the menu (and menubar).
9281 GtkWidget *gtk_menu_item_new( void );
9287 GtkWidget *gtk_menu_item_new_with_label( const char *label );
9290 These calls are used to create the menu items that are to be
9291 displayed. Remember to differentiate between a "menu" as created with
9292 gtk_menu_new and a "menu item" as created by the gtk_menu_item_new
9293 functions. The menu item will be an actual button with an associated
9294 action, whereas a menu will be a container holding menu items.
9296 The gtk_menu_new_with_label and gtk_menu_new functions are just as
9297 you'd expect after reading about the buttons. One creates a new menu
9298 item with a label already packed into it, and the other just creates a
9301 Once you've created a menu item you have to put it into a menu. This
9302 is done using the function gtk_menu_append. In order to capture when
9303 the item is selected by the user, we need to connect to the
9304 <tt/activate/ signal in the usual way. So, if we wanted to create a
9305 standard <tt/File/ menu, with the options <tt/Open/, <tt/Save/ and
9306 <tt/Quit/ the code would look something like:
9309 file_menu = gtk_menu_new (); /* Don't need to show menus */
9311 /* Create the menu items */
9312 open_item = gtk_menu_item_new_with_label ("Open");
9313 save_item = gtk_menu_item_new_with_label ("Save");
9314 quit_item = gtk_menu_item_new_with_label ("Quit");
9316 /* Add them to the menu */
9317 gtk_menu_append (GTK_MENU (file_menu), open_item);
9318 gtk_menu_append (GTK_MENU (file_menu), save_item);
9319 gtk_menu_append (GTK_MENU (file_menu), quit_item);
9321 /* Attach the callback functions to the activate signal */
9322 gtk_signal_connect_object (GTK_OBJECT (open_items), "activate",
9323 GTK_SIGNAL_FUNC (menuitem_response),
9324 (gpointer) "file.open");
9325 gtk_signal_connect_object (GTK_OBJECT (save_items), "activate",
9326 GTK_SIGNAL_FUNC (menuitem_response),
9327 (gpointer) "file.save");
9329 /* We can attach the Quit menu item to our exit function */
9330 gtk_signal_connect_object (GTK_OBJECT (quit_items), "activate",
9331 GTK_SIGNAL_FUNC (destroy),
9332 (gpointer) "file.quit");
9334 /* We do need to show menu items */
9335 gtk_widget_show (open_item);
9336 gtk_widget_show (save_item);
9337 gtk_widget_show (quit_item);
9340 At this point we have our menu. Now we need to create a menubar and a
9341 menu item for the <tt/File/ entry, to which we add our menu. The code
9345 menu_bar = gtk_menu_bar_new ();
9346 gtk_container_add (GTK_CONTAINER (window), menu_bar);
9347 gtk_widget_show (menu_bar);
9349 file_item = gtk_menu_item_new_with_label ("File");
9350 gtk_widget_show (file_item);
9353 Now we need to associate the menu with <tt/file_item/. This is done
9357 void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
9358 GtkWidget *submenu );
9361 So, our example would continue with
9364 gtk_menu_item_set_submenu (GTK_MENU_ITEM (file_item), file_menu);
9367 All that is left to do is to add the menu to the menubar, which is
9368 accomplished using the function
9371 void gtk_menu_bar_append( GtkMenuBar *menu_bar,
9372 GtkWidget *menu_item );
9375 which in our case looks like this:
9378 gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), file_item);
9381 If we wanted the menu right justified on the menubar, such as help
9382 menus often are, we can use the following function (again on
9383 <tt/file_item/ in the current example) before attaching it to the
9387 void gtk_menu_item_right_justify( GtkMenuItem *menu_item );
9390 Here is a summary of the steps needed to create a menu bar with menus
9394 <item> Create a new menu using gtk_menu_new()
9395 <item> Use multiple calls to gtk_menu_item_new() for each item you
9396 wish to have on your menu. And use gtk_menu_append() to put each of
9397 these new items on to the menu.
9398 <item> Create a menu item using gtk_menu_item_new(). This will be the
9399 root of the menu, the text appearing here will be on the menubar
9401 <item>Use gtk_menu_item_set_submenu() to attach the menu to the root
9402 menu item (the one created in the above step).
9403 <item> Create a new menubar using gtk_menu_bar_new. This step only
9404 needs to be done once when creating a series of menus on one menu bar.
9405 <item> Use gtk_menu_bar_append() to put the root menu onto the menubar.
9408 Creating a popup menu is nearly the same. The difference is that the
9409 menu is not posted `automatically' by a menubar, but explicitly by
9410 calling the function gtk_menu_popup() from a button-press event, for
9411 example. Take these steps:
9414 <item>Create an event handling function. It needs to have the
9417 static gint handler (GtkWidget *widget,
9420 and it will use the event to find out where to pop up the menu.
9421 <item>In the event handler, if the event is a mouse button press,
9422 treat <tt>event</tt> as a button event (which it is) and use it as
9423 shown in the sample code to pass information to gtk_menu_popup().
9424 <item>Bind that event handler to a widget with
9426 gtk_signal_connect_object (GTK_OBJECT (widget), "event",
9427 GTK_SIGNAL_FUNC (handler),
9430 where <tt>widget</tt> is the widget you are binding to,
9431 <tt>handler</tt> is the handling function, and <tt>menu</tt> is a menu
9432 created with gtk_menu_new(). This can be a menu which is also posted
9433 by a menu bar, as shown in the sample code.
9436 <!-- ----------------------------------------------------------------- -->
9437 <sect1>Manual Menu Example
9439 That should about do it. Let's take a look at an example to help clarify.
9442 /* example-start menu menu.c */
9444 #include <gtk/gtk.h>
9446 static gint button_press (GtkWidget *, GdkEvent *);
9447 static void menuitem_response (gchar *);
9455 GtkWidget *menu_bar;
9456 GtkWidget *root_menu;
9457 GtkWidget *menu_items;
9463 gtk_init (&argc, &argv);
9465 /* create a new window */
9466 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9467 gtk_widget_set_usize (GTK_WIDGET (window), 200, 100);
9468 gtk_window_set_title (GTK_WINDOW (window), "GTK Menu Test");
9469 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
9470 (GtkSignalFunc) gtk_main_quit, NULL);
9472 /* Init the menu-widget, and remember -- never
9473 * gtk_show_widget() the menu widget!!
9474 * This is the menu that holds the menu items, the one that
9475 * will pop up when you click on the "Root Menu" in the app */
9476 menu = gtk_menu_new ();
9478 /* Next we make a little loop that makes three menu-entries for "test-menu".
9479 * Notice the call to gtk_menu_append. Here we are adding a list of
9480 * menu items to our menu. Normally, we'd also catch the "clicked"
9481 * signal on each of the menu items and setup a callback for it,
9482 * but it's omitted here to save space. */
9484 for (i = 0; i < 3; i++)
9486 /* Copy the names to the buf. */
9487 sprintf (buf, "Test-undermenu - %d", i);
9489 /* Create a new menu-item with a name... */
9490 menu_items = gtk_menu_item_new_with_label (buf);
9492 /* ...and add it to the menu. */
9493 gtk_menu_append (GTK_MENU (menu), menu_items);
9495 /* Do something interesting when the menuitem is selected */
9496 gtk_signal_connect_object (GTK_OBJECT (menu_items), "activate",
9497 GTK_SIGNAL_FUNC (menuitem_response), (gpointer) g_strdup (buf));
9499 /* Show the widget */
9500 gtk_widget_show (menu_items);
9503 /* This is the root menu, and will be the label
9504 * displayed on the menu bar. There won't be a signal handler attached,
9505 * as it only pops up the rest of the menu when pressed. */
9506 root_menu = gtk_menu_item_new_with_label ("Root Menu");
9508 gtk_widget_show (root_menu);
9510 /* Now we specify that we want our newly created "menu" to be the menu
9511 * for the "root menu" */
9512 gtk_menu_item_set_submenu (GTK_MENU_ITEM (root_menu), menu);
9514 /* A vbox to put a menu and a button in: */
9515 vbox = gtk_vbox_new (FALSE, 0);
9516 gtk_container_add (GTK_CONTAINER (window), vbox);
9517 gtk_widget_show (vbox);
9519 /* Create a menu-bar to hold the menus and add it to our main window */
9520 menu_bar = gtk_menu_bar_new ();
9521 gtk_box_pack_start (GTK_BOX (vbox), menu_bar, FALSE, FALSE, 2);
9522 gtk_widget_show (menu_bar);
9524 /* Create a button to which to attach menu as a popup */
9525 button = gtk_button_new_with_label ("press me");
9526 gtk_signal_connect_object (GTK_OBJECT (button), "event",
9527 GTK_SIGNAL_FUNC (button_press), GTK_OBJECT (menu));
9528 gtk_box_pack_end (GTK_BOX (vbox), button, TRUE, TRUE, 2);
9529 gtk_widget_show (button);
9531 /* And finally we append the menu-item to the menu-bar -- this is the
9532 * "root" menu-item I have been raving about =) */
9533 gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), root_menu);
9535 /* always display the window as the last step so it all splashes on
9536 * the screen at once. */
9537 gtk_widget_show (window);
9544 /* Respond to a button-press by posting a menu passed in as widget.
9546 * Note that the "widget" argument is the menu being posted, NOT
9547 * the button that was pressed.
9550 static gint button_press (GtkWidget *widget, GdkEvent *event)
9553 if (event->type == GDK_BUTTON_PRESS) {
9554 GdkEventButton *bevent = (GdkEventButton *) event;
9555 gtk_menu_popup (GTK_MENU (widget), NULL, NULL, NULL, NULL,
9556 bevent->button, bevent->time);
9557 /* Tell calling code that we have handled this event; the buck
9562 /* Tell calling code that we have not handled this event; pass it on. */
9567 /* Print a string when a menu item is selected */
9569 static void menuitem_response (gchar *string)
9571 printf ("%s\n", string);
9576 You may also set a menu item to be insensitive and, using an accelerator
9577 table, bind keys to menu functions.
9579 <!-- ----------------------------------------------------------------- -->
9580 <sect1>Using GtkItemFactory
9582 Now that we've shown you the hard way, here's how you do it using the
9583 gtk_item_factory calls.
9585 <!-- ----------------------------------------------------------------- -->
9586 <sect1>Item Factory Example
9588 Here is an example using the GTK item factory.
9591 /* example-start menu itemfactory.c */
9593 #include <gtk/gtk.h>
9594 #include <strings.h>
9596 /* Obligatory basic callback */
9597 static void print_hello( GtkWidget *w,
9600 g_message ("Hello, World!\n");
9603 /* This is the GtkItemFactoryEntry structure used to generate new menus.
9604 Item 1: The menu path. The letter after the underscore indicates an
9605 accelerator key once the menu is open.
9606 Item 2: The accelerator key for the entry
9607 Item 3: The callback function.
9608 Item 4: The callback action. This changes the parameters with
9609 which the function is called. The default is 0.
9610 Item 5: The item type, used to define what kind of an item it is.
9611 Here are the possible values:
9615 "<Title>" -> create a title item
9616 "<Item>" -> create a simple item
9617 "<CheckItem>" -> create a check item
9618 "<ToggleItem>" -> create a toggle item
9619 "<RadioItem>" -> create a radio item
9620 <path> -> path of a radio item to link against
9621 "<Separator>" -> create a separator
9622 "<Branch>" -> create an item to hold sub items (optional)
9623 "<LastBranch>" -> create a right justified branch
9626 static GtkItemFactoryEntry menu_items[] = {
9627 { "/_File", NULL, NULL, 0, "<Branch>" },
9628 { "/File/_New", "<control>N", print_hello, 0, NULL },
9629 { "/File/_Open", "<control>O", print_hello, 0, NULL },
9630 { "/File/_Save", "<control>S", print_hello, 0, NULL },
9631 { "/File/Save _As", NULL, NULL, 0, NULL },
9632 { "/File/sep1", NULL, NULL, 0, "<Separator>" },
9633 { "/File/Quit", "<control>Q", gtk_main_quit, 0, NULL },
9634 { "/_Options", NULL, NULL, 0, "<Branch>" },
9635 { "/Options/Test", NULL, NULL, 0, NULL },
9636 { "/_Help", NULL, NULL, 0, "<LastBranch>" },
9637 { "/_Help/About", NULL, NULL, 0, NULL },
9641 void get_main_menu( GtkWidget *window,
9642 GtkWidget **menubar )
9644 GtkItemFactory *item_factory;
9645 GtkAccelGroup *accel_group;
9646 gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
9648 accel_group = gtk_accel_group_new ();
9650 /* This function initializes the item factory.
9651 Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
9652 or GTK_TYPE_OPTION_MENU.
9653 Param 2: The path of the menu.
9654 Param 3: A pointer to a gtk_accel_group. The item factory sets up
9655 the accelerator table while generating menus.
9658 item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>",
9661 /* This function generates the menu items. Pass the item factory,
9662 the number of items in the array, the array itself, and any
9663 callback data for the the menu items. */
9664 gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
9666 /* Attach the new accelerator group to the window. */
9667 gtk_accel_group_attach (accel_group, GTK_OBJECT (window));
9670 /* Finally, return the actual menu bar created by the item factory. */
9671 *menubar = gtk_item_factory_get_widget (item_factory, "<main>");
9678 GtkWidget *main_vbox;
9681 gtk_init (&argc, &argv);
9683 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9684 gtk_signal_connect (GTK_OBJECT (window), "destroy",
9685 GTK_SIGNAL_FUNC (gtk_main_quit),
9687 gtk_window_set_title (GTK_WINDOW(window), "Item Factory");
9688 gtk_widget_set_usize (GTK_WIDGET(window), 300, 200);
9690 main_vbox = gtk_vbox_new (FALSE, 1);
9691 gtk_container_border_width (GTK_CONTAINER (main_vbox), 1);
9692 gtk_container_add (GTK_CONTAINER (window), main_vbox);
9693 gtk_widget_show (main_vbox);
9695 get_main_menu (window, &menubar);
9696 gtk_box_pack_start (GTK_BOX (main_vbox), menubar, FALSE, TRUE, 0);
9697 gtk_widget_show (menubar);
9699 gtk_widget_show (window);
9708 For now, there's only this example. An explanation and lots 'o' comments
9711 <!-- ***************************************************************** -->
9713 <!-- ***************************************************************** -->
9715 The Text widget allows multiple lines of text to be displayed and
9716 edited. It supports both multi-colored and multi-font text, allowing
9717 them to be mixed in any way we wish. It also has a wide set of key
9718 based text editing commands, which are compatible with Emacs.
9720 The text widget supports full cut-and-paste facilities, including the
9721 use of double- and triple-click to select a word and a whole line,
9724 <!-- ----------------------------------------------------------------- -->
9725 <sect1>Creating and Configuring a Text box
9727 There is only one function for creating a new Text widget.
9730 GtkWidget *gtk_text_new( GtkAdjustment *hadj,
9731 GtkAdjustment *vadj );
9734 The arguments allow us to give the Text widget pointers to Adjustments
9735 that can be used to track the viewing position of the widget. Passing
9736 NULL values to either or both of these arguments will cause the
9737 gtk_text_new function to create its own.
9740 void gtk_text_set_adjustments( GtkText *text,
9741 GtkAdjustment *hadj,
9742 GtkAdjustment *vadj );
9745 The above function allows the horizontal and vertical adjustments of a
9746 text widget to be changed at any time.
9748 The text widget will not automatically create its own scrollbars when
9749 the amount of text to be displayed is too long for the display
9750 window. We therefore have to create and add them to the display layout
9754 vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
9755 gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, FALSE, 0);
9756 gtk_widget_show (vscrollbar);
9759 The above code snippet creates a new vertical scrollbar, and attaches
9760 it to the vertical adjustment of the text widget, <tt/text/. It then
9761 packs it into a box in the normal way.
9763 Note, currently the GtkText widget does not support horizontal
9766 There are two main ways in which a Text widget can be used: to allow
9767 the user to edit a body of text, or to allow us to display multiple
9768 lines of text to the user. In order for us to switch between these
9769 modes of operation, the text widget has the following function:
9772 void gtk_text_set_editable( GtkText *text,
9776 The <tt/editable/ argument is a TRUE or FALSE value that specifies
9777 whether the user is permitted to edit the contents of the Text
9778 widget. When the text widget is editable, it will display a cursor at
9779 the current insertion point.
9781 You are not, however, restricted to just using the text widget in
9782 these two modes. You can toggle the editable state of the text widget
9783 at any time, and can insert text at any time.
9785 The text widget wraps lines of text that are too long to fit onto a
9786 single line of the display window. Its default behaviour is to break
9787 words across line breaks. This can be changed using the next function:
9790 void gtk_text_set_word_wrap( GtkText *text,
9794 Using this function allows us to specify that the text widget should
9795 wrap long lines on word boundaries. The <tt/word_wrap/ argument is a
9796 TRUE or FALSE value.
9798 <!-- ----------------------------------------------------------------- -->
9799 <sect1>Text Manipulation
9801 The current insertion point of a Text widget can be set using
9803 void gtk_text_set_point( GtkText *text,
9807 where <tt/index/ is the position to set the insertion point.
9809 Analogous to this is the function for getting the current insertion
9813 guint gtk_text_get_point( GtkText *text );
9816 A function that is useful in combination with the above two functions
9820 guint gtk_text_get_length( GtkText *text );
9823 which returns the current length of the Text widget. The length is the
9824 number of characters that are within the text block of the widget,
9825 including characters such as carriage-return, which marks the end of
9828 In order to insert text at the current insertion point of a Text
9829 widget, the function gtk_text_insert is used, which also allows us to
9830 specify background and foreground colors and a font for the text.
9833 void gtk_text_insert( GtkText *text,
9841 Passing a value of <tt/NULL/ in as the value for the foreground color,
9842 background colour or font will result in the values set within the
9843 widget style to be used. Using a value of <tt/-1/ for the length
9844 parameter will result in the whole of the text string given being
9847 The text widget is one of the few within GTK that redraws itself
9848 dynamically, outside of the gtk_main function. This means that all
9849 changes to the contents of the text widget take effect
9850 immediately. This may be undesirable when performing multiple changes
9851 to the text widget. In order to allow us to perform multiple updates
9852 to the text widget without it continuously redrawing, we can freeze
9853 the widget, which temporarily stops it from automatically redrawing
9854 itself every time it is changed. We can then thaw the widget after our
9855 updates are complete.
9857 The following two functions perform this freeze and thaw action:
9860 void gtk_text_freeze( GtkText *text );
9862 void gtk_text_thaw( GtkText *text );
9865 Text is deleted from the text widget relative to the current insertion
9866 point by the following two functions. The return value is a TRUE or
9867 FALSE indicator of whether the operation was successful.
9870 gint gtk_text_backward_delete( GtkText *text,
9873 gint gtk_text_forward_delete ( GtkText *text,
9877 If you want to retrieve the contents of the text widget, then the
9878 macro <tt/GTK_TEXT_INDEX(t, index)/ allows you to retrieve the
9879 character at position <tt/index/ within the text widget <tt/t/.
9881 To retrieve larger blocks of text, we can use the function
9884 gchar *gtk_editable_get_chars( GtkEditable *editable,
9889 This is a function of the parent class of the text widget. A value of
9890 -1 as <tt/end_pos/ signifies the end of the text. The index of the
9893 The function allocates a new chunk of memory for the text block, so
9894 don't forget to free it with a call to g_free when you have finished
9897 <!-- ----------------------------------------------------------------- -->
9898 <sect1>Keyboard Shortcuts
9900 The text widget has a number of pre-installed keyboard shortcuts for
9901 common editing, motion and selection functions. These are accessed
9902 using Control and Alt key combinations.
9904 In addition to these, holding down the Control key whilst using cursor
9905 key movement will move the cursor by words rather than
9906 characters. Holding down Shift whilst using cursor movement will
9907 extend the selection.
9909 <sect2>Motion Shortcuts
9912 <item> Ctrl-A Beginning of line
9913 <item> Ctrl-E End of line
9914 <item> Ctrl-N Next Line
9915 <item> Ctrl-P Previous Line
9916 <item> Ctrl-B Backward one character
9917 <item> Ctrl-F Forward one character
9918 <item> Alt-B Backward one word
9919 <item> Alt-F Forward one word
9922 <sect2>Editing Shortcuts
9925 <item> Ctrl-H Delete Backward Character (Backspace)
9926 <item> Ctrl-D Delete Forward Character (Delete)
9927 <item> Ctrl-W Delete Backward Word
9928 <item> Alt-D Delete Forward Word
9929 <item> Ctrl-K Delete to end of line
9930 <item> Ctrl-U Delete line
9933 <sect2>Selection Shortcuts
9936 <item> Ctrl-X Cut to clipboard
9937 <item> Ctrl-C Copy to clipboard
9938 <item> Ctrl-V Paste from clipboard
9941 <!-- ----------------------------------------------------------------- -->
9942 <sect1>A GtkText Example
9945 /* example-start text text.c */
9950 #include <gtk/gtk.h>
9952 void text_toggle_editable (GtkWidget *checkbutton,
9955 gtk_text_set_editable(GTK_TEXT(text),
9956 GTK_TOGGLE_BUTTON(checkbutton)->active);
9959 void text_toggle_word_wrap (GtkWidget *checkbutton,
9962 gtk_text_set_word_wrap(GTK_TEXT(text),
9963 GTK_TOGGLE_BUTTON(checkbutton)->active);
9966 void close_application( GtkWidget *widget, gpointer data )
9971 int main (int argc, char *argv[])
9979 GtkWidget *separator;
9981 GtkWidget *vscrollbar;
9985 GdkFont *fixed_font;
9989 gtk_init (&argc, &argv);
9991 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9992 gtk_widget_set_usize (window, 600, 500);
9993 gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, FALSE);
9994 gtk_signal_connect (GTK_OBJECT (window), "destroy",
9995 GTK_SIGNAL_FUNC(close_application),
9997 gtk_window_set_title (GTK_WINDOW (window), "Text Widget Example");
9998 gtk_container_set_border_width (GTK_CONTAINER (window), 0);
10001 box1 = gtk_vbox_new (FALSE, 0);
10002 gtk_container_add (GTK_CONTAINER (window), box1);
10003 gtk_widget_show (box1);
10006 box2 = gtk_vbox_new (FALSE, 10);
10007 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
10008 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
10009 gtk_widget_show (box2);
10012 table = gtk_table_new (2, 2, FALSE);
10013 gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
10014 gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
10015 gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
10016 gtk_widget_show (table);
10018 /* Create the GtkText widget */
10019 text = gtk_text_new (NULL, NULL);
10020 gtk_text_set_editable (GTK_TEXT (text), TRUE);
10021 gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
10022 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
10023 GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
10024 gtk_widget_show (text);
10026 /* Add a vertical scrollbar to the GtkText widget */
10027 vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
10028 gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
10029 GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
10030 gtk_widget_show (vscrollbar);
10032 /* Get the system colour map and allocate the colour red */
10033 cmap = gdk_colormap_get_system();
10034 colour.red = 0xffff;
10037 if (!gdk_color_alloc(cmap, &colour)) {
10038 g_error("couldn't allocate colour");
10041 /* Load a fixed font */
10042 fixed_font = gdk_font_load ("-misc-fixed-medium-r-*-*-*-140-*-*-*-*-*-*");
10044 /* Realizing a widget creates a window for it,
10045 * ready for us to insert some text */
10046 gtk_widget_realize (text);
10048 /* Freeze the text widget, ready for multiple updates */
10049 gtk_text_freeze (GTK_TEXT (text));
10051 /* Insert some coloured text */
10052 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
10054 gtk_text_insert (GTK_TEXT (text), NULL, &colour, NULL,
10056 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
10057 "text and different ", -1);
10058 gtk_text_insert (GTK_TEXT (text), fixed_font, &text->style->black, NULL,
10061 /* Load the file text.c into the text window */
10063 infile = fopen("text.c", "r");
10071 nchars = fread(buffer, 1, 1024, infile);
10072 gtk_text_insert (GTK_TEXT (text), fixed_font, NULL,
10073 NULL, buffer, nchars);
10082 /* Thaw the text widget, allowing the updates to become visible */
10083 gtk_text_thaw (GTK_TEXT (text));
10085 hbox = gtk_hbutton_box_new ();
10086 gtk_box_pack_start (GTK_BOX (box2), hbox, FALSE, FALSE, 0);
10087 gtk_widget_show (hbox);
10089 check = gtk_check_button_new_with_label("Editable");
10090 gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, FALSE, 0);
10091 gtk_signal_connect (GTK_OBJECT(check), "toggled",
10092 GTK_SIGNAL_FUNC(text_toggle_editable), text);
10093 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);
10094 gtk_widget_show (check);
10095 check = gtk_check_button_new_with_label("Wrap Words");
10096 gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, TRUE, 0);
10097 gtk_signal_connect (GTK_OBJECT(check), "toggled",
10098 GTK_SIGNAL_FUNC(text_toggle_word_wrap), text);
10099 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), FALSE);
10100 gtk_widget_show (check);
10102 separator = gtk_hseparator_new ();
10103 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
10104 gtk_widget_show (separator);
10106 box2 = gtk_vbox_new (FALSE, 10);
10107 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
10108 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
10109 gtk_widget_show (box2);
10111 button = gtk_button_new_with_label ("close");
10112 gtk_signal_connect (GTK_OBJECT (button), "clicked",
10113 GTK_SIGNAL_FUNC(close_application),
10115 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
10116 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
10117 gtk_widget_grab_default (button);
10118 gtk_widget_show (button);
10120 gtk_widget_show (window);
10130 <!-- ***************************************************************** -->
10131 <sect> Undocumented Widgets
10132 <!-- ***************************************************************** -->
10134 These all require authors! :) Please consider contributing to our
10137 If you must use one of these widgets that are undocumented, I strongly
10138 suggest you take a look at their respective header files in the GTK
10139 distribution. GTK's function names are very descriptive. Once you
10140 have an understanding of how things work, it's not difficult to figure
10141 out how to use a widget simply by looking at its function
10142 declarations. This, along with a few examples from others' code, and
10143 it should be no problem.
10145 When you do come to understand all the functions of a new undocumented
10146 widget, please consider writing a tutorial on it so others may benefit
10149 <!-- ----------------------------------------------------------------- -->
10152 <!-- ----------------------------------------------------------------- -->
10155 <!-- ----------------------------------------------------------------- -->
10158 <!-- ----------------------------------------------------------------- -->
10159 <sect1> Drawing Area
10161 <!-- ----------------------------------------------------------------- -->
10162 <sect1> Font Selection Dialog
10164 <!-- ----------------------------------------------------------------- -->
10165 <sect1> Gamma Curve
10167 <!-- ----------------------------------------------------------------- -->
10170 <!-- ----------------------------------------------------------------- -->
10173 <!-- ----------------------------------------------------------------- -->
10174 <sect1> Plugs and Sockets
10176 <!-- ----------------------------------------------------------------- -->
10182 (This may need to be rewritten to follow the style of the rest of the tutorial)
10186 Previews serve a number of purposes in GIMP/GTK. The most important one is
10187 this. High quality images may take up to tens of megabytes of memory - easy!
10188 Any operation on an image that big is bound to take a long time. If it takes
10189 you 5-10 trial-and-errors (i.e. 10-20 steps, since you have to revert after
10190 you make an error) to choose the desired modification, it make take you
10191 literally hours to make the right one - if you don't run out of memory
10192 first. People who have spent hours in color darkrooms know the feeling.
10193 Previews to the rescue!
10195 But the annoyance of the delay is not the only issue. Oftentimes it is
10196 helpful to compare the Before and After versions side-by-side or at least
10197 back-to-back. If you're working with big images and 10 second delays,
10198 obtaining the Before and After impressions is, to say the least, difficult.
10199 For 30M images (4"x6", 600dpi, 24 bit) the side-by-side comparison is right
10200 out for most people, while back-to-back is more like back-to-1001, 1002,
10201 ..., 1010-back! Previews to the rescue!
10203 But there's more. Previews allow for side-by-side pre-previews. In other
10204 words, you write a plug-in (e.g. the filterpack simulation) which would have
10205 a number of here's-what-it-would-look-like-if-you-were-to-do-this previews.
10206 An approach like this acts as a sort of a preview palette and is very
10207 effective for subtle changes. Let's go previews!
10209 There's more. For certain plug-ins real-time image-specific human
10210 intervention maybe necessary. In the SuperNova plug-in, for example, the
10211 user is asked to enter the coordinates of the center of the future
10212 supernova. The easiest way to do this, really, is to present the user with a
10213 preview and ask him to interactively select the spot. Let's go previews!
10215 Finally, a couple of misc uses. One can use previews even when not working
10216 with big images. For example, they are useful when rendering complicated
10217 patterns. (Just check out the venerable Diffraction plug-in + many other
10218 ones!) As another example, take a look at the colormap rotation plug-in
10219 (work in progress). You can also use previews for little logos inside you
10220 plug-ins and even for an image of yourself, The Author. Let's go previews!
10222 When Not to Use Previews
10224 Don't use previews for graphs, drawing etc. GDK is much faster for that. Use
10225 previews only for rendered images!
10229 You can stick a preview into just about anything. In a vbox, an hbox, a
10230 table, a button, etc. But they look their best in tight frames around them.
10231 Previews by themselves do not have borders and look flat without them. (Of
10232 course, if the flat look is what you want...) Tight frames provide the
10237 Previews in many ways are like any other widgets in GTK (whatever that
10238 means) except they possess an additional feature: they need to be filled with
10239 some sort of an image! First, we will deal exclusively with the GTK aspect
10240 of previews and then we'll discuss how to fill them.
10242 GtkWidget *preview!
10246 /* Create a preview widget,
10247 set its size, an show it */
10248 GtkWidget *preview;
10249 preview=gtk_preview_new(GTK_PREVIEW_COLOR)
10251 GTK_PREVIEW_GRAYSCALE);*/
10252 gtk_preview_size (GTK_PREVIEW (preview), WIDTH, HEIGHT);
10253 gtk_widget_show(preview);
10254 my_preview_rendering_function(preview);
10256 Oh yeah, like I said, previews look good inside frames, so how about:
10258 GtkWidget *create_a_preview(int Width,
10262 GtkWidget *preview;
10265 frame = gtk_frame_new(NULL);
10266 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
10267 gtk_container_set_border_width (GTK_CONTAINER(frame),0);
10268 gtk_widget_show(frame);
10270 preview=gtk_preview_new (Colorfulness?GTK_PREVIEW_COLOR
10271 :GTK_PREVIEW_GRAYSCALE);
10272 gtk_preview_size (GTK_PREVIEW (preview), Width, Height);
10273 gtk_container_add(GTK_CONTAINER(frame),preview);
10274 gtk_widget_show(preview);
10276 my_preview_rendering_function(preview);
10280 That's my basic preview. This routine returns the "parent" frame so you can
10281 place it somewhere else in your interface. Of course, you can pass the
10282 parent frame to this routine as a parameter. In many situations, however,
10283 the contents of the preview are changed continually by your application. In
10284 this case you may want to pass a pointer to the preview to a
10285 "create_a_preview()" and thus have control of it later.
10287 One more important note that may one day save you a lot of time. Sometimes
10288 it is desirable to label you preview. For example, you may label the preview
10289 containing the original image as "Original" and the one containing the
10290 modified image as "Less Original". It might occur to you to pack the
10291 preview along with the appropriate label into a vbox. The unexpected caveat
10292 is that if the label is wider than the preview (which may happen for a
10293 variety of reasons unforseeable to you, from the dynamic decision on the
10294 size of the preview to the size of the font) the frame expands and no longer
10295 fits tightly over the preview. The same problem can probably arise in other
10296 situations as well.
10300 The solution is to place the preview and the label into a 2x1 table and by
10301 attaching them with the following parameters (this is one possible variations
10302 of course. The key is no GTK_FILL in the second attachment):
10304 gtk_table_attach(GTK_TABLE(table),label,0,1,0,1,
10306 GTK_EXPAND|GTK_FILL,
10308 gtk_table_attach(GTK_TABLE(table),frame,0,1,1,2,
10314 And here's the result:
10320 Making a preview clickable is achieved most easily by placing it in a
10321 button. It also adds a nice border around the preview and you may not even
10322 need to place it in a frame. See the Filter Pack Simulation plug-in for an
10325 This is pretty much it as far as GTK is concerned.
10327 Filling In a Preview
10329 In order to familiarize ourselves with the basics of filling in previews,
10330 let's create the following pattern (contrived by trial and error):
10335 my_preview_rendering_function(GtkWidget *preview)
10338 #define HALF (SIZE/2)
10340 guchar *row=(guchar *) malloc(3*SIZE); /* 3 bits per dot */
10341 gint i, j; /* Coordinates */
10342 double r, alpha, x, y;
10344 if (preview==NULL) return; /* I usually add this when I want */
10345 /* to avoid silly crashes. You */
10346 /* should probably make sure that */
10347 /* everything has been nicely */
10349 for (j=0; j < ABS(cos(2*alpha)) ) { /* Are we inside the shape? */
10350 /* glib.h contains ABS(x). */
10351 row[i*3+0] = sqrt(1-r)*255; /* Define Red */
10352 row[i*3+1] = 128; /* Define Green */
10353 row[i*3+2] = 224; /* Define Blue */
10354 } /* "+0" is for alignment! */
10356 row[i*3+0] = r*255;
10357 row[i*3+1] = ABS(sin((float)i/SIZE*2*PI))*255;
10358 row[i*3+2] = ABS(sin((float)j/SIZE*2*PI))*255;
10361 gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,j,SIZE);
10362 /* Insert "row" into "preview" starting at the point with */
10363 /* coordinates (0,j) first column, j_th row extending SIZE */
10364 /* pixels to the right */
10367 free(row); /* save some space */
10368 gtk_widget_draw(preview,NULL); /* what does this do? */
10369 gdk_flush(); /* or this? */
10372 Non-GIMP users can have probably seen enough to do a lot of things already.
10373 For the GIMP users I have a few pointers to add.
10377 It is probably wise to keep a reduced version of the image around with just
10378 enough pixels to fill the preview. This is done by selecting every n'th
10379 pixel where n is the ratio of the size of the image to the size of the
10380 preview. All further operations (including filling in the previews) are then
10381 performed on the reduced number of pixels only. The following is my
10382 implementation of reducing the image. (Keep in mind that I've had only basic
10385 (UNTESTED CODE ALERT!!!)
10397 SELECTION_IN_CONTEXT,
10401 ReducedImage *Reduce_The_Image(GDrawable *drawable,
10406 /* This function reduced the image down to the the selected preview size */
10407 /* The preview size is determine by LongerSize, i.e. the greater of the */
10408 /* two dimensions. Works for RGB images only! */
10409 gint RH, RW; /* Reduced height and reduced width */
10410 gint width, height; /* Width and Height of the area being reduced */
10411 gint bytes=drawable->bpp;
10412 ReducedImage *temp=(ReducedImage *)malloc(sizeof(ReducedImage));
10414 guchar *tempRGB, *src_row, *tempmask, *src_mask_row,R,G,B;
10415 gint i, j, whichcol, whichrow, x1, x2, y1, y2;
10416 GPixelRgn srcPR, srcMask;
10417 gint NoSelectionMade=TRUE; /* Assume that we're dealing with the entire */
10420 gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
10423 /* If there's a SELECTION, we got its bounds!)
10425 if (width != drawable->width && height != drawable->height)
10426 NoSelectionMade=FALSE;
10427 /* Become aware of whether the user has made an active selection */
10428 /* This will become important later, when creating a reduced mask. */
10430 /* If we want to preview the entire image, overrule the above! */
10431 /* Of course, if no selection has been made, this does nothing! */
10432 if (Selection==ENTIRE_IMAGE) {
10434 x2=drawable->width;
10436 y2=drawable->height;
10439 /* If we want to preview a selection with some surrounding area we */
10440 /* have to expand it a little bit. Consider it a bit of a riddle. */
10441 if (Selection==SELECTION_IN_CONTEXT) {
10442 x1=MAX(0, x1-width/2.0);
10443 x2=MIN(drawable->width, x2+width/2.0);
10444 y1=MAX(0, y1-height/2.0);
10445 y2=MIN(drawable->height, y2+height/2.0);
10448 /* How we can determine the width and the height of the area being */
10453 /* The lines below determine which dimension is to be the longer */
10454 /* side. The idea borrowed from the supernova plug-in. I suspect I */
10455 /* could've thought of it myself, but the truth must be told. */
10456 /* Plagiarism stinks! */
10457 if (width>height) {
10459 RH=(float) height * (float) LongerSize/ (float) width;
10463 RW=(float)width * (float) LongerSize/ (float) height;
10466 /* The entire image is stretched into a string! */
10467 tempRGB = (guchar *) malloc(RW*RH*bytes);
10468 tempmask = (guchar *) malloc(RW*RH);
10470 gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height,
10472 gimp_pixel_rgn_init (&srcMask, mask, x1, y1, width, height,
10475 /* Grab enough to save a row of image and a row of mask. */
10476 src_row = (guchar *) malloc (width*bytes);
10477 src_mask_row = (guchar *) malloc (width);
10479 for (i=0; i < RH; i++) {
10480 whichrow=(float)i*(float)height/(float)RH;
10481 gimp_pixel_rgn_get_row (&srcPR, src_row, x1, y1+whichrow, width);
10482 gimp_pixel_rgn_get_row (&srcMask, src_mask_row, x1, y1+whichrow, width);
10484 for (j=0; j < RW; j++) {
10485 whichcol=(float)j*(float)width/(float)RW;
10487 /* No selection made = each point is completely selected! */
10488 if (NoSelectionMade)
10489 tempmask[i*RW+j]=255;
10491 tempmask[i*RW+j]=src_mask_row[whichcol];
10493 /* Add the row to the one long string which now contains the image! */
10494 tempRGB[i*RW*bytes+j*bytes+0]=src_row[whichcol*bytes+0];
10495 tempRGB[i*RW*bytes+j*bytes+1]=src_row[whichcol*bytes+1];
10496 tempRGB[i*RW*bytes+j*bytes+2]=src_row[whichcol*bytes+2];
10498 /* Hold on to the alpha as well */
10500 tempRGB[i*RW*bytes+j*bytes+3]=src_row[whichcol*bytes+3];
10507 temp->mask=tempmask;
10511 The following is a preview function which used the same ReducedImage type!
10512 Note that it uses fakes transparency (if one is present by means of
10513 fake_transparency which is defined as follows:
10515 gint fake_transparency(gint i, gint j)
10517 if ( ((i%20)- 10) * ((j%20)- 10)>0 )
10523 Now here's the preview function:
10526 my_preview_render_function(GtkWidget *preview,
10530 gint Inten, bytes=drawable->bpp;
10533 gint RW=reduced->width;
10534 gint RH=reduced->height;
10535 guchar *row=malloc(bytes*RW);;
10538 for (i=0; i < RH; i++) {
10539 for (j=0; j < RW; j++) {
10541 row[j*3+0] = reduced->rgb[i*RW*bytes + j*bytes + 0];
10542 row[j*3+1] = reduced->rgb[i*RW*bytes + j*bytes + 1];
10543 row[j*3+2] = reduced->rgb[i*RW*bytes + j*bytes + 2];
10546 for (k=0; k<3; k++) {
10547 float transp=reduced->rgb[i*RW*bytes+j*bytes+3]/255.0;
10548 row[3*j+k]=transp*a[3*j+k]+(1-transp)*fake_transparency(i,j);
10551 gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,i,RW);
10555 gtk_widget_draw(preview,NULL);
10559 Applicable Routines
10561 guint gtk_preview_get_type (void);
10563 void gtk_preview_uninit (void);
10565 GtkWidget* gtk_preview_new (GtkPreviewType type);
10566 /* Described above */
10567 void gtk_preview_size (GtkPreview *preview,
10570 /* Allows you to resize an existing preview. */
10571 /* Apparently there's a bug in GTK which makes */
10572 /* this process messy. A way to clean up a mess */
10573 /* is to manually resize the window containing */
10574 /* the preview after resizing the preview. */
10576 void gtk_preview_put (GtkPreview *preview,
10587 void gtk_preview_put_row (GtkPreview *preview,
10595 void gtk_preview_draw_row (GtkPreview *preview,
10600 /* Described in the text */
10602 void gtk_preview_set_expand (GtkPreview *preview,
10606 /* No clue for any of the below but */
10607 /* should be standard for most widgets */
10608 void gtk_preview_set_gamma (double gamma);
10609 void gtk_preview_set_color_cube (guint nred_shades,
10610 guint ngreen_shades,
10611 guint nblue_shades,
10612 guint ngray_shades);
10613 void gtk_preview_set_install_cmap (gint install_cmap);
10614 void gtk_preview_set_reserved (gint nreserved);
10615 GdkVisual* gtk_preview_get_visual (void);
10616 GdkColormap* gtk_preview_get_cmap (void);
10617 GtkPreviewInfo* gtk_preview_get_info (void);
10625 <!-- ***************************************************************** -->
10626 <sect>Setting Widget Attributes<label id="sec_setting_widget_attributes">
10627 <!-- ***************************************************************** -->
10629 This describes the functions used to operate on widgets. These can be
10630 used to set style, padding, size etc.
10632 (Maybe I should make a whole section on accelerators.)
10635 void gtk_widget_install_accelerator( GtkWidget *widget,
10636 GtkAcceleratorTable *table,
10637 gchar *signal_name,
10639 guint8 modifiers );
10641 void gtk_widget_remove_accelerator ( GtkWidget *widget,
10642 GtkAcceleratorTable *table,
10643 gchar *signal_name);
10645 void gtk_widget_activate( GtkWidget *widget );
10647 void gtk_widget_set_name( GtkWidget *widget,
10650 gchar *gtk_widget_get_name( GtkWidget *widget );
10652 void gtk_widget_set_sensitive( GtkWidget *widget,
10655 void gtk_widget_set_style( GtkWidget *widget,
10658 GtkStyle *gtk_widget_get_style( GtkWidget *widget );
10660 GtkStyle *gtk_widget_get_default_style( void );
10662 void gtk_widget_set_uposition( GtkWidget *widget,
10666 void gtk_widget_set_usize( GtkWidget *widget,
10670 void gtk_widget_grab_focus( GtkWidget *widget );
10672 void gtk_widget_show( GtkWidget *widget );
10674 void gtk_widget_hide( GtkWidget *widget );
10677 <!-- ***************************************************************** -->
10678 <sect>Timeouts, IO and Idle Functions<label id="sec_timeouts">
10679 <!-- ***************************************************************** -->
10681 <!-- ----------------------------------------------------------------- -->
10684 You may be wondering how you make GTK do useful work when in gtk_main.
10685 Well, you have several options. Using the following functions you can
10686 create a timeout function that will be called every "interval"
10690 gint gtk_timeout_add( guint32 interval,
10691 GtkFunction function,
10695 The first argument is the number of milliseconds between calls to your
10696 function. The second argument is the function you wish to have called,
10697 and the third, the data passed to this callback function. The return
10698 value is an integer "tag" which may be used to stop the timeout by
10702 void gtk_timeout_remove( gint tag );
10705 You may also stop the timeout function by returning zero or FALSE from
10706 your callback function. Obviously this means if you want your function
10707 to continue to be called, it should return a non-zero value,
10710 The declaration of your callback should look something like this:
10713 gint timeout_callback( gpointer data );
10716 <!-- ----------------------------------------------------------------- -->
10717 <sect1>Monitoring IO
10719 A nifty feature of GDK (the library that underlies GTK), is the
10720 ability to have it check for data on a file descriptor for you (as
10721 returned by open(2) or socket(2)). This is especially useful for
10722 networking applications. The function:
10725 gint gdk_input_add( gint source,
10726 GdkInputCondition condition,
10727 GdkInputFunction function,
10731 Where the first argument is the file descriptor you wish to have
10732 watched, and the second specifies what you want GDK to look for. This
10736 <item>GDK_INPUT_READ - Call your function when there is data ready for
10737 reading on your file descriptor.
10739 <item>GDK_INPUT_WRITE - Call your function when the file descriptor is
10743 As I'm sure you've figured out already, the third argument is the
10744 function you wish to have called when the above conditions are
10745 satisfied, and the fourth is the data to pass to this function.
10747 The return value is a tag that may be used to stop GDK from monitoring
10748 this file descriptor using the following function.
10751 void gdk_input_remove( gint tag );
10754 The callback function should be declared as:
10757 void input_callback( gpointer data,
10759 GdkInputCondition condition );
10762 Where <tt/source/ and <tt/condition/ are as specified above.
10764 <!-- ----------------------------------------------------------------- -->
10765 <sect1>Idle Functions
10767 <!-- TODO: Need to check on idle priorities - TRG -->
10768 What if you have a function you want called when nothing else is
10772 gint gtk_idle_add( GtkFunction function,
10776 This causes GTK to call the specified function whenever nothing else
10780 void gtk_idle_remove( gint tag );
10783 I won't explain the meaning of the arguments as they follow very much
10784 like the ones above. The function pointed to by the first argument to
10785 gtk_idle_add will be called whenever the opportunity arises. As with
10786 the others, returning FALSE will stop the idle function from being
10789 <!-- ***************************************************************** -->
10790 <sect>Advanced Event and Signal Handling<label id="sec_Adv_Events_and_Signals">
10791 <!-- ***************************************************************** -->
10793 <!-- ----------------------------------------------------------------- -->
10794 <sect1>Signal Functions
10796 <!-- ----------------------------------------------------------------- -->
10797 <sect2>Connecting and Disconnecting Signal Handlers
10801 guint gtk_signal_connect( GtkObject *object,
10803 GtkSignalFunc func,
10804 gpointer func_data );
10806 guint gtk_signal_connect_after( GtkObject *object,
10808 GtkSignalFunc func,
10809 gpointer func_data );
10811 guint gtk_signal_connect_object( GtkObject *object,
10813 GtkSignalFunc func,
10814 GtkObject *slot_object );
10816 guint gtk_signal_connect_object_after( GtkObject *object,
10818 GtkSignalFunc func,
10819 GtkObject *slot_object );
10821 guint gtk_signal_connect_full( GtkObject *object,
10823 GtkSignalFunc func,
10824 GtkCallbackMarshal marshal,
10826 GtkDestroyNotify destroy_func,
10827 gint object_signal,
10830 guint gtk_signal_connect_interp( GtkObject *object,
10832 GtkCallbackMarshal func,
10834 GtkDestroyNotify destroy_func,
10837 void gtk_signal_connect_object_while_alive( GtkObject *object,
10838 const gchar *signal,
10839 GtkSignalFunc func,
10840 GtkObject *alive_object );
10842 void gtk_signal_connect_while_alive( GtkObject *object,
10843 const gchar *signal,
10844 GtkSignalFunc func,
10845 gpointer func_data,
10846 GtkObject *alive_object );
10848 void gtk_signal_disconnect( GtkObject *object,
10849 guint handler_id );
10851 void gtk_signal_disconnect_by_func( GtkObject *object,
10852 GtkSignalFunc func,
10856 <!-- ----------------------------------------------------------------- -->
10857 <sect2>Blocking and Unblocking Signal Handlers
10860 void gtk_signal_handler_block( GtkObject *object,
10863 void gtk_signal_handler_block_by_func( GtkObject *object,
10864 GtkSignalFunc func,
10867 void gtk_signal_handler_block_by_data( GtkObject *object,
10870 void gtk_signal_handler_unblock( GtkObject *object,
10871 guint handler_id );
10873 void gtk_signal_handler_unblock_by_func( GtkObject *object,
10874 GtkSignalFunc func,
10877 void gtk_signal_handler_unblock_by_data( GtkObject *object,
10881 <!-- ----------------------------------------------------------------- -->
10882 <sect2>Emitting and Stopping Signals
10885 void gtk_signal_emit( GtkObject *object,
10889 void gtk_signal_emit_by_name( GtkObject *object,
10893 void gtk_signal_emitv( GtkObject *object,
10897 void gtk_signal_emitv_by_name( GtkObject *object,
10901 guint gtk_signal_n_emissions( GtkObject *object,
10904 guint gtk_signal_n_emissions_by_name( GtkObject *object,
10905 const gchar *name );
10907 void gtk_signal_emit_stop( GtkObject *object,
10910 void gtk_signal_emit_stop_by_name( GtkObject *object,
10911 const gchar *name );
10914 <!-- ----------------------------------------------------------------- -->
10915 <sect1>Signal Emission and Propagation
10917 Signal emission is the process wherby GTK runs all handlers for a
10918 specific object and signal.
10920 First, note that the return value from a signal emission is the return
10921 value of the <em>last</em> handler executed. Since event signals are
10922 all of type GTK_RUN_LAST, this will be the default (GTK supplied)
10923 default handler, unless you connect with gtk_signal_connect_after().
10925 The way an event (say GTK_BUTTON_PRESS) is handled, is:
10927 <item>Start with the widget where the event occured.
10929 <item>Emit the generic "event" signal. If that signal handler returns
10930 a value of TRUE, stop all processing.
10932 <item>Otherwise, emit a specific, "button_press_event" signal. If that
10933 returns TRUE, stop all processing.
10935 <item>Otherwise, go to the widget's parent, and repeat the above steps.
10937 <item>Contimue until some signal handler returns TRUE, or until the
10938 top-level widget is reached.
10941 Some consequences of the above are:
10943 <item>Your handler's return value will have no effect if there is a
10944 default handler, unless you connect with gtk_signal_connect_after().
10946 <item>To prevent the default handler from being run, you need to
10947 connect with gtk_signal_connect() and use
10948 gtk_signal_emit_stop_by_name() - the return value only affects whether
10949 the signal is propagated, not the current emission.
10952 <!-- ***************************************************************** -->
10953 <sect>Managing Selections
10954 <!-- ***************************************************************** -->
10956 <!-- ----------------------------------------------------------------- -->
10959 One type of interprocess communication supported by GTK is
10960 <em>selections</em>. A selection identifies a chunk of data, for
10961 instance, a portion of text, selected by the user in some fashion, for
10962 instance, by dragging with the mouse. Only one application on a
10963 display, (the <em>owner</em>) can own a particular selection at one
10964 time, so when a selection is claimed by one application, the previous
10965 owner must indicate to the user that selection has been
10966 relinquished. Other applications can request the contents of a
10967 selection in different forms, called <em>targets</em>. There can be
10968 any number of selections, but most X applications only handle one, the
10969 <em>primary selection</em>.
10971 In most cases, it isn't necessary for a GTK application to deal with
10972 selections itself. The standard widgets, such as the Entry widget,
10973 already have the capability to claim the selection when appropriate
10974 (e.g., when the user drags over text), and to retrieve the contents of
10975 the selection owned by another widget, or another application (e.g.,
10976 when the user clicks the second mouse button). However, there may be
10977 cases in which you want to give other widgets the ability to supply
10978 the selection, or you wish to retrieve targets not supported by
10981 A fundamental concept needed to understand selection handling is that
10982 of the <em>atom</em>. An atom is an integer that uniquely identifies a
10983 string (on a certain display). Certain atoms are predefined by the X
10984 server, and in some cases there are constants in <tt>gtk.h</tt>
10985 corresponding to these atoms. For instance the constant
10986 <tt>GDK_PRIMARY_SELECTION</tt> corresponds to the string "PRIMARY".
10987 In other cases, you should use the functions
10988 <tt>gdk_atom_intern()</tt>, to get the atom corresponding to a string,
10989 and <tt>gdk_atom_name()</tt>, to get the name of an atom. Both
10990 selections and targets are identified by atoms.
10992 <!-- ----------------------------------------------------------------- -->
10993 <sect1> Retrieving the selection
10995 Retrieving the selection is an asynchronous process. To start the
10999 gint gtk_selection_convert( GtkWidget *widget,
11005 This <em>converts</em> the selection into the form specified by
11006 <tt/target/. If at all possible, the time field should be the time
11007 from the event that triggered the selection. This helps make sure that
11008 events occur in the order that the user requested them. However, if it
11009 is not available (for instance, if the conversion was triggered by a
11010 "clicked" signal), then you can use the constant
11011 <tt>GDK_CURRENT_TIME</tt>.
11013 When the selection owner responds to the request, a
11014 "selection_received" signal is sent to your application. The handler
11015 for this signal receives a pointer to a <tt>GtkSelectionData</tt>
11016 structure, which is defined as:
11019 struct _GtkSelectionData
11030 <tt>selection</tt> and <tt>target</tt> are the values you gave in your
11031 <tt>gtk_selection_convert()</tt> call. <tt>type</tt> is an atom that
11032 identifies the type of data returned by the selection owner. Some
11033 possible values are "STRING", a string of latin-1 characters, "ATOM",
11034 a series of atoms, "INTEGER", an integer, etc. Most targets can only
11035 return one type. <tt/format/ gives the length of the units (for
11036 instance characters) in bits. Usually, you don't care about this when
11037 receiving data. <tt>data</tt> is a pointer to the returned data, and
11038 <tt>length</tt> gives the length of the returned data, in bytes. If
11039 <tt>length</tt> is negative, then an error occurred and the selection
11040 could not be retrieved. This might happen if no application owned the
11041 selection, or if you requested a target that the application didn't
11042 support. The buffer is actually guaranteed to be one byte longer than
11043 <tt>length</tt>; the extra byte will always be zero, so it isn't
11044 necessary to make a copy of strings just to null terminate them.
11046 In the following example, we retrieve the special target "TARGETS",
11047 which is a list of all targets into which the selection can be
11051 /* example-start selection gettargets.c */
11053 #include <gtk/gtk.h>
11055 void selection_received (GtkWidget *widget,
11056 GtkSelectionData *selection_data,
11059 /* Signal handler invoked when user clicks on the "Get Targets" button */
11061 get_targets (GtkWidget *widget, gpointer data)
11063 static GdkAtom targets_atom = GDK_NONE;
11065 /* Get the atom corresponding to the string "TARGETS" */
11066 if (targets_atom == GDK_NONE)
11067 targets_atom = gdk_atom_intern ("TARGETS", FALSE);
11069 /* And request the "TARGETS" target for the primary selection */
11070 gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
11074 /* Signal handler called when the selections owner returns the data */
11076 selection_received (GtkWidget *widget, GtkSelectionData *selection_data,
11083 /* **** IMPORTANT **** Check to see if retrieval succeeded */
11084 if (selection_data->length < 0)
11086 g_print ("Selection retrieval failed\n");
11089 /* Make sure we got the data in the expected form */
11090 if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
11092 g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
11096 /* Print out the atoms we received */
11097 atoms = (GdkAtom *)selection_data->data;
11100 for (i=0; i<selection_data->length/sizeof(GdkAtom); i++)
11103 name = gdk_atom_name (atoms[i]);
11105 g_print ("%s\n",name);
11107 g_print ("(bad atom)\n");
11114 main (int argc, char *argv[])
11119 gtk_init (&argc, &argv);
11121 /* Create the toplevel window */
11123 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11124 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
11125 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
11127 gtk_signal_connect (GTK_OBJECT (window), "destroy",
11128 GTK_SIGNAL_FUNC (gtk_exit), NULL);
11130 /* Create a button the user can click to get targets */
11132 button = gtk_button_new_with_label ("Get Targets");
11133 gtk_container_add (GTK_CONTAINER (window), button);
11135 gtk_signal_connect (GTK_OBJECT(button), "clicked",
11136 GTK_SIGNAL_FUNC (get_targets), NULL);
11137 gtk_signal_connect (GTK_OBJECT(button), "selection_received",
11138 GTK_SIGNAL_FUNC (selection_received), NULL);
11140 gtk_widget_show (button);
11141 gtk_widget_show (window);
11150 <!-- ----------------------------------------------------------------- -->
11151 <sect1> Supplying the selection
11153 Supplying the selection is a bit more complicated. You must register
11154 handlers that will be called when your selection is requested. For
11155 each selection/target pair you will handle, you make a call to:
11158 void gtk_selection_add_handler( GtkWidget *widget,
11161 GtkSelectionFunction function,
11162 GtkRemoveFunction remove_func,
11166 <tt/widget/, <tt/selection/, and <tt/target/ identify the requests
11167 this handler will manage. <tt/remove_func/, if not
11168 NULL, will be called when the signal handler is removed. This is
11169 useful, for instance, for interpreted languages which need to
11170 keep track of a reference count for <tt/data/.
11172 The callback function has the signature:
11175 typedef void (*GtkSelectionFunction)( GtkWidget *widget,
11176 GtkSelectionData *selection_data,
11181 The GtkSelectionData is the same as above, but this time, we're
11182 responsible for filling in the fields <tt/type/, <tt/format/,
11183 <tt/data/, and <tt/length/. (The <tt/format/ field is actually
11184 important here - the X server uses it to figure out whether the data
11185 needs to be byte-swapped or not. Usually it will be 8 - <em/i.e./ a
11186 character - or 32 - <em/i.e./ a. integer.) This is done by calling the
11190 void gtk_selection_data_set( GtkSelectionData *selection_data,
11197 This function takes care of properly making a copy of the data so that
11198 you don't have to worry about keeping it around. (You should not fill
11199 in the fields of the GtkSelectionData structure by hand.)
11201 When prompted by the user, you claim ownership of the selection by
11205 gint gtk_selection_owner_set( GtkWidget *widget,
11210 If another application claims ownership of the selection, you will
11211 receive a "selection_clear_event".
11213 As an example of supplying the selection, the following program adds
11214 selection functionality to a toggle button. When the toggle button is
11215 depressed, the program claims the primary selection. The only target
11216 supported (aside from certain targets like "TARGETS" supplied by GTK
11217 itself), is the "STRING" target. When this target is requested, a
11218 string representation of the time is returned.
11221 /* example-start selection setselection.c */
11223 #include <gtk/gtk.h>
11226 /* Callback when the user toggles the selection */
11228 selection_toggled (GtkWidget *widget, gint *have_selection)
11230 if (GTK_TOGGLE_BUTTON(widget)->active)
11232 *have_selection = gtk_selection_owner_set (widget,
11233 GDK_SELECTION_PRIMARY,
11235 /* if claiming the selection failed, we return the button to
11237 if (!*have_selection)
11238 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), FALSE);
11242 if (*have_selection)
11244 /* Before clearing the selection by setting the owner to NULL,
11245 we check if we are the actual owner */
11246 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
11247 gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
11249 *have_selection = FALSE;
11254 /* Called when another application claims the selection */
11256 selection_clear (GtkWidget *widget, GdkEventSelection *event,
11257 gint *have_selection)
11259 *have_selection = FALSE;
11260 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), FALSE);
11265 /* Supplies the current time as the selection. */
11267 selection_handle (GtkWidget *widget,
11268 GtkSelectionData *selection_data,
11272 time_t current_time;
11274 current_time = time (NULL);
11275 timestr = asctime (localtime(&current_time));
11276 /* When we return a single string, it should not be null terminated.
11277 That will be done for us */
11279 gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
11280 8, timestr, strlen(timestr));
11284 main (int argc, char *argv[])
11288 GtkWidget *selection_button;
11290 static int have_selection = FALSE;
11292 gtk_init (&argc, &argv);
11294 /* Create the toplevel window */
11296 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11297 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
11298 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
11300 gtk_signal_connect (GTK_OBJECT (window), "destroy",
11301 GTK_SIGNAL_FUNC (gtk_exit), NULL);
11303 /* Create a toggle button to act as the selection */
11305 selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
11306 gtk_container_add (GTK_CONTAINER (window), selection_button);
11307 gtk_widget_show (selection_button);
11309 gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
11310 GTK_SIGNAL_FUNC (selection_toggled), &have_selection);
11311 gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
11312 GTK_SIGNAL_FUNC (selection_clear), &have_selection);
11314 gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
11315 GDK_SELECTION_TYPE_STRING,
11316 selection_handle, NULL);
11318 gtk_widget_show (selection_button);
11319 gtk_widget_show (window);
11329 <!-- ***************************************************************** -->
11330 <sect>glib<label id="sec_glib">
11331 <!-- ***************************************************************** -->
11333 glib is a lower-level library that provides many useful definitions
11334 and functions available for use when creating GDK and GTK
11335 applications. These include definitions for basic types and their
11336 limits, standard macros, type conversions, byte order, memory
11337 allocation, warnings and assertions, message logging, timers, string
11338 utilities, hook functions, a lexical scanner, dynamic loading of
11339 modules, and automatic string completion. A number of data structures
11340 (and their related operations) are also defined, including memory
11341 chunks, doubly-linked lists, singly-linked lists, hash tables, strings
11342 (which can grow dynamically), string chunks (groups of strings),
11343 arrays (which can grow in size as elements are added), balanced binary
11344 trees, N-ary trees, quarks (a two-way association of a string and a
11345 unique integer identifier), keyed data lists (lists of data elements
11346 accessible by a string or integer id), relations and tuples (tables of
11347 data which can be indexed on any number of fields), and caches.
11349 A summary of some of glib's capabilities follows; not every function,
11350 data structure, or operation is covered here. For more complete
11351 information about the glib routines, see the glib documentation. One
11352 source of glib documentation is http://www.gtk.org/ <htmlurl
11353 url="http://www.gtk.org/" name="http://www.gtk.org/">.
11355 If you are using a language other than C, you should consult your
11356 language's binding documentation. In some cases your language may
11357 have equivalent functionality built-in, while in other cases it may
11360 <!-- ----------------------------------------------------------------- -->
11363 Definitions for the extremes of many of the standard types are:
11378 Also, the following typedefs. The ones left unspecified are dynamically set
11379 depending on the architecture. Remember to avoid counting on the size of a
11380 pointer if you want to be portable! E.g., a pointer on an Alpha is 8
11381 bytes, but 4 on Intel 80x86 family CPUs.
11390 unsigned char guchar;
11391 unsigned short gushort;
11392 unsigned long gulong;
11393 unsigned int guint;
11397 long double gldouble;
11409 <!-- ----------------------------------------------------------------- -->
11410 <sect1>Doubly Linked Lists
11412 The following functions are used to create, manage, and destroy
11413 standard doubly linked lists. Each element in the list contains a
11414 piece of data, together with pointers which link to the previous and
11415 next elements in the list. This enables easy movement in either
11416 direction through the list. The data item is of type "gpointer",
11417 which means the data can be a pointer to your real data or (through
11418 casting) a numeric value (but do not assume that int and gpointer have
11419 the same size!). These routines internally allocate list elements in
11420 blocks, which is more efficient than allocating elements individually.
11422 There is no function to specifically create a list. Instead, simply
11423 create a variable of type GList* and set its value to NULL; NULL is
11424 considered to be the empty list.
11426 To add elements to a list, use the g_list_append(), g_list_prepend(),
11427 g_list_insert(), or g_list_insert_sorted() routines. In all cases
11428 they accept a pointer to the beginning of the list, and return the
11429 (possibly changed) pointer to the beginning of the list. Thus, for
11430 all of the operations that add or remove elements, be sure to save the
11434 GList *g_list_append( GList *list,
11438 This adds a new element (with value <tt/data/) onto the end of the
11442 GList *g_list_prepend( GList *list,
11446 This adds a new element (with value <tt/data/) to the beginning of the
11450 GList *g_list_insert( GList *list,
11456 This inserts a new element (with value data) into the list at the
11457 given position. If position is 0, this is just like g_list_prepend();
11458 if position is less than 0, this is just like g_list_append().
11461 GList *g_list_remove( GList *list,
11465 This removes the element in the list with the value <tt/data/;
11466 if the element isn't there, the list is unchanged.
11469 void g_list_free( GList *list );
11472 This frees all of the memory used by a GList. If the list elements
11473 refer to dynamically-allocated memory, then they should be freed
11476 There are many other glib functions that support doubly linked lists;
11477 see the glib documentation for more information. Here are a few of
11478 the more useful functions' signatures:
11481 GList *g_list_remove_link( GList *list,
11484 GList *g_list_reverse( GList *list );
11486 GList *g_list_nth( GList *list,
11489 GList *g_list_find( GList *list,
11492 GList *g_list_last( GList *list );
11494 GList *g_list_first( GList *list );
11496 gint g_list_length( GList *list );
11498 void g_list_foreach( GList *list,
11500 gpointer user_data );
11503 <!-- ----------------------------------------------------------------- -->
11504 <sect1>Singly Linked Lists
11506 Many of the above functions for singly linked lists are identical to the
11507 above. Here is a list of some of their operations:
11510 GSList *g_slist_append( GSList *list,
11513 GSList *g_slist_prepend( GSList *list,
11516 GSList *g_slist_insert( GSList *list,
11520 GSList *g_slist_remove( GSList *list,
11523 GSList *g_slist_remove_link( GSList *list,
11526 GSList *g_slist_reverse( GSList *list );
11528 GSList *g_slist_nth( GSList *list,
11531 GSList *g_slist_find( GSList *list,
11534 GSList *g_slist_last( GSList *list );
11536 gint g_slist_length( GSList *list );
11538 void g_slist_foreach( GSList *list,
11540 gpointer user_data );
11544 <!-- ----------------------------------------------------------------- -->
11545 <sect1>Memory Management
11548 gpointer g_malloc( gulong size );
11551 This is a replacement for malloc(). You do not need to check the return
11552 value as it is done for you in this function. If the memory allocation
11553 fails for whatever reasons, your applications will be terminated.
11556 gpointer g_malloc0( gulong size );
11559 Same as above, but zeroes the memory before returning a pointer to it.
11562 gpointer g_realloc( gpointer mem,
11566 Relocates "size" bytes of memory starting at "mem". Obviously, the
11567 memory should have been previously allocated.
11570 void g_free( gpointer mem );
11573 Frees memory. Easy one. If <tt/mem/ is NULL it simply returns.
11576 void g_mem_profile( void );
11579 Dumps a profile of used memory, but requires that you add #define
11580 MEM_PROFILE to the top of glib/gmem.c and re-make and make install.
11583 void g_mem_check( gpointer mem );
11586 Checks that a memory location is valid. Requires you add #define
11587 MEM_CHECK to the top of gmem.c and re-make and make install.
11589 <!-- ----------------------------------------------------------------- -->
11592 Timer functions can be used to time operations (e.g. to see how much
11593 time has elapsed). First, you create a new timer with g_timer_new().
11594 You can then use g_timer_start() to start timing an operation,
11595 g_timer_stop() to stop timing an operation, and g_timer_elapsed() to
11596 determine the elapsed time.
11599 GTimer *g_timer_new( void );
11601 void g_timer_destroy( GTimer *timer );
11603 void g_timer_start( GTimer *timer );
11605 void g_timer_stop( GTimer *timer );
11607 void g_timer_reset( GTimer *timer );
11609 gdouble g_timer_elapsed( GTimer *timer,
11610 gulong *microseconds );
11613 <!-- ----------------------------------------------------------------- -->
11614 <sect1>String Handling
11616 glib defines a new type called a GString, which is similar to a
11617 standard C string but one that grows automatically. Its string data
11618 is null-terminated. What this gives you is protection from buffer
11619 overflow programming errors within your program. This is a very
11620 important feature, and hence I recommend that you make use of
11621 GStrings. GString itself has a simple public definition:
11626 gchar *str; /* Points to the string's current \0-terminated value. */
11627 gint len; /* Current length */
11631 As you might expect, there are a number of operations you can do with
11635 GString *g_string_new( gchar *init );
11638 This constructs a GString, copying the string value of <tt/init/
11639 into the GString and returning a pointer to it. NULL may be given as
11640 the argument for an initially empty GString.
11644 void g_string_free( GString *string,
11645 gint free_segment );
11648 This frees the memory for the given GString. If <tt/free_segment/ is
11649 TRUE, then this also frees its character data.
11653 GString *g_string_assign( GString *lval,
11654 const gchar *rval );
11657 This copies the characters from rval into lval, destroying the
11658 previous contents of lval. Note that lval will be lengthened as
11659 necessary to hold the string's contents, unlike the standard strcpy()
11662 The rest of these functions should be relatively obvious (the _c
11663 versions accept a character instead of a string):
11666 GString *g_string_truncate( GString *string,
11669 GString *g_string_append( GString *string,
11672 GString *g_string_append_c( GString *string,
11675 GString *g_string_prepend( GString *string,
11678 GString *g_string_prepend_c( GString *string,
11681 void g_string_sprintf( GString *string,
11685 void g_string_sprintfa ( GString *string,
11690 <!-- ----------------------------------------------------------------- -->
11691 <sect1>Utility and Error Functions
11694 gchar *g_strdup( const gchar *str );
11697 Replacement strdup function. Copies the original strings contents to
11698 newly allocated memory, and returns a pointer to it.
11701 gchar *g_strerror( gint errnum );
11704 I recommend using this for all error messages. It's much nicer, and more
11705 portable than perror() or others. The output is usually of the form:
11708 program name:function that failed:file or further description:strerror
11711 Here's an example of one such call used in our hello_world program:
11714 g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
11718 void g_error( gchar *format, ... );
11721 Prints an error message. The format is just like printf, but it
11722 prepends "** ERROR **: " to your message, and exits the program.
11723 Use only for fatal errors.
11726 void g_warning( gchar *format, ... );
11729 Same as above, but prepends "** WARNING **: ", and does not exit the
11733 void g_message( gchar *format, ... );
11736 Prints "message: " prepended to the string you pass in.
11739 void g_print( gchar *format, ... );
11742 Replacement for printf().
11744 And our last function:
11747 gchar *g_strsignal( gint signum );
11750 Prints out the name of the Unix system signal given the signal number.
11751 Useful in generic signal handling functions.
11753 All of the above are more or less just stolen from glib.h. If anyone cares
11754 to document any function, just send me an email!
11756 <!-- ***************************************************************** -->
11757 <sect>GTK's rc Files
11758 <!-- ***************************************************************** -->
11760 GTK has its own way of dealing with application defaults, by using rc
11761 files. These can be used to set the colors of just about any widget, and
11762 can also be used to tile pixmaps onto the background of some widgets.
11764 <!-- ----------------------------------------------------------------- -->
11765 <sect1>Functions For rc Files
11767 When your application starts, you should include a call to:
11770 void gtk_rc_parse( char *filename );
11773 Passing in the filename of your rc file. This will cause GTK to parse
11774 this file, and use the style settings for the widget types defined
11777 If you wish to have a special set of widgets that can take on a
11778 different style from others, or any other logical division of widgets,
11782 void gtk_widget_set_name( GtkWidget *widget,
11786 Passing your newly created widget as the first argument, and the name
11787 you wish to give it as the second. This will allow you to change the
11788 attributes of this widget by name through the rc file.
11790 If we use a call something like this:
11793 button = gtk_button_new_with_label ("Special Button");
11794 gtk_widget_set_name (button, "special button");
11797 Then this button is given the name "special button" and may be addressed by
11798 name in the rc file as "special button.GtkButton". [<--- Verify ME!]
11800 The example rc file below, sets the properties of the main window, and lets
11801 all children of that main window inherit the style described by the "main
11802 button" style. The code used in the application is:
11805 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11806 gtk_widget_set_name (window, "main window");
11809 And then the style is defined in the rc file using:
11812 widget "main window.*GtkButton*" style "main_button"
11815 Which sets all the GtkButton widgets in the "main window" to the
11816 "main_buttons" style as defined in the rc file.
11818 As you can see, this is a fairly powerful and flexible system. Use your
11819 imagination as to how best to take advantage of this.
11821 <!-- ----------------------------------------------------------------- -->
11822 <sect1>GTK's rc File Format
11824 The format of the GTK file is illustrated in the example below. This is
11825 the testgtkrc file from the GTK distribution, but I've added a
11826 few comments and things. You may wish to include this explanation
11827 your application to allow the user to fine tune his application.
11829 There are several directives to change the attributes of a widget.
11832 <item>fg - Sets the foreground color of a widget.
11833 <item>bg - Sets the background color of a widget.
11834 <item>bg_pixmap - Sets the background of a widget to a tiled pixmap.
11835 <item>font - Sets the font to be used with the given widget.
11838 In addition to this, there are several states a widget can be in, and you
11839 can set different colors, pixmaps and fonts for each state. These states are:
11842 <item>NORMAL - The normal state of a widget, without the mouse over top of
11843 it, and not being pressed etc.
11844 <item>PRELIGHT - When the mouse is over top of the widget, colors defined
11845 using this state will be in effect.
11846 <item>ACTIVE - When the widget is pressed or clicked it will be active, and
11847 the attributes assigned by this tag will be in effect.
11848 <item>INSENSITIVE - When a widget is set insensitive, and cannot be
11849 activated, it will take these attributes.
11850 <item>SELECTED - When an object is selected, it takes these attributes.
11853 When using the "fg" and "bg" keywords to set the colors of widgets, the
11857 fg[<STATE>] = { Red, Green, Blue }
11860 Where STATE is one of the above states (PRELIGHT, ACTIVE etc), and the Red,
11861 Green and Blue are values in the range of 0 - 1.0, { 1.0, 1.0, 1.0 } being
11862 white. They must be in float form, or they will register as 0, so a straight
11863 "1" will not work, it must be "1.0". A straight "0" is fine because it
11864 doesn't matter if it's not recognized. Unrecognized values are set to 0.
11866 bg_pixmap is very similar to the above, except the colors are replaced by a
11869 pixmap_path is a list of paths separated by ":"'s. These paths will be
11870 searched for any pixmap you specify.
11872 The font directive is simply:
11874 font = "<font name>"
11877 Where the only hard part is figuring out the font string. Using xfontsel or
11878 similar utility should help.
11880 The "widget_class" sets the style of a class of widgets. These classes are
11881 listed in the widget overview on the class hierarchy.
11883 The "widget" directive sets a specifically named set of widgets to a
11884 given style, overriding any style set for the given widget class.
11885 These widgets are registered inside the application using the
11886 gtk_widget_set_name() call. This allows you to specify the attributes of a
11887 widget on a per widget basis, rather than setting the attributes of an
11888 entire widget class. I urge you to document any of these special widgets so
11889 users may customize them.
11891 When the keyword <tt>parent</> is used as an attribute, the widget will take on
11892 the attributes of its parent in the application.
11894 When defining a style, you may assign the attributes of a previously defined
11895 style to this new one.
11898 style "main_button" = "button"
11900 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
11901 bg[PRELIGHT] = { 0.75, 0, 0 }
11905 This example takes the "button" style, and creates a new "main_button" style
11906 simply by changing the font and prelight background color of the "button"
11909 Of course, many of these attributes don't apply to all widgets. It's a
11910 simple matter of common sense really. Anything that could apply, should.
11912 <!-- ----------------------------------------------------------------- -->
11913 <sect1>Example rc file
11917 # pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
11919 pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
11921 # style <name> [= <name>]
11926 # widget <widget_set> style <style_name>
11927 # widget_class <widget_class_set> style <style_name>
11930 # Here is a list of all the possible states. Note that some do not apply to
11933 # NORMAL - The normal state of a widget, without the mouse over top of
11934 # it, and not being pressed etc.
11936 # PRELIGHT - When the mouse is over top of the widget, colors defined
11937 # using this state will be in effect.
11939 # ACTIVE - When the widget is pressed or clicked it will be active, and
11940 # the attributes assigned by this tag will be in effect.
11942 # INSENSITIVE - When a widget is set insensitive, and cannot be
11943 # activated, it will take these attributes.
11945 # SELECTED - When an object is selected, it takes these attributes.
11947 # Given these states, we can set the attributes of the widgets in each of
11948 # these states using the following directives.
11950 # fg - Sets the foreground color of a widget.
11951 # fg - Sets the background color of a widget.
11952 # bg_pixmap - Sets the background of a widget to a tiled pixmap.
11953 # font - Sets the font to be used with the given widget.
11956 # This sets a style called "button". The name is not really important, as
11957 # it is assigned to the actual widgets at the bottom of the file.
11961 #This sets the padding around the window to the pixmap specified.
11962 #bg_pixmap[<STATE>] = "<pixmap filename>"
11963 bg_pixmap[NORMAL] = "warning.xpm"
11968 #Sets the foreground color (font color) to red when in the "NORMAL"
11971 fg[NORMAL] = { 1.0, 0, 0 }
11973 #Sets the background pixmap of this widget to that of its parent.
11974 bg_pixmap[NORMAL] = "<parent>"
11979 # This shows all the possible states for a button. The only one that
11980 # doesn't apply is the SELECTED state.
11982 fg[PRELIGHT] = { 0, 1.0, 1.0 }
11983 bg[PRELIGHT] = { 0, 0, 1.0 }
11984 bg[ACTIVE] = { 1.0, 0, 0 }
11985 fg[ACTIVE] = { 0, 1.0, 0 }
11986 bg[NORMAL] = { 1.0, 1.0, 0 }
11987 fg[NORMAL] = { .99, 0, .99 }
11988 bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
11989 fg[INSENSITIVE] = { 1.0, 0, 1.0 }
11992 # In this example, we inherit the attributes of the "button" style and then
11993 # override the font and background color when prelit to create a new
11994 # "main_button" style.
11996 style "main_button" = "button"
11998 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
11999 bg[PRELIGHT] = { 0.75, 0, 0 }
12002 style "toggle_button" = "button"
12004 fg[NORMAL] = { 1.0, 0, 0 }
12005 fg[ACTIVE] = { 1.0, 0, 0 }
12007 # This sets the background pixmap of the toggle_button to that of its
12008 # parent widget (as defined in the application).
12009 bg_pixmap[NORMAL] = "<parent>"
12014 bg_pixmap[NORMAL] = "marble.xpm"
12015 fg[NORMAL] = { 1.0, 1.0, 1.0 }
12020 font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
12023 # pixmap_path "~/.pixmaps"
12025 # These set the widget types to use the styles defined above.
12026 # The widget types are listed in the class hierarchy, but could probably be
12027 # just listed in this document for the users reference.
12029 widget_class "GtkWindow" style "window"
12030 widget_class "GtkDialog" style "window"
12031 widget_class "GtkFileSelection" style "window"
12032 widget_class "*Gtk*Scale" style "scale"
12033 widget_class "*GtkCheckButton*" style "toggle_button"
12034 widget_class "*GtkRadioButton*" style "toggle_button"
12035 widget_class "*GtkButton*" style "button"
12036 widget_class "*Ruler" style "ruler"
12037 widget_class "*GtkText" style "text"
12039 # This sets all the buttons that are children of the "main window" to
12040 # the main_button style. These must be documented to be taken advantage of.
12041 widget "main window.*GtkButton*" style "main_button"
12044 <!-- ***************************************************************** -->
12045 <sect>Writing Your Own Widgets
12046 <!-- ***************************************************************** -->
12048 <!-- ----------------------------------------------------------------- -->
12051 Although the GTK distribution comes with many types of widgets that
12052 should cover most basic needs, there may come a time when you need to
12053 create your own new widget type. Since GTK uses widget inheritance
12054 extensively, and there is already a widget that is close to what you want,
12055 it is often possible to make a useful new widget type in
12056 just a few lines of code. But before starting work on a new widget, check
12057 around first to make sure that someone has not already written
12058 it. This will prevent duplication of effort and keep the number of
12059 GTK widgets out there to a minimum, which will help keep both the code
12060 and the interface of different applications consistent. As a flip side
12061 to this, once you finish your widget, announce it to the world so
12062 other people can benefit. The best place to do this is probably the
12065 Complete sources for the example widgets are available at the place you
12066 got this tutorial, or from:
12068 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
12069 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
12072 <!-- ----------------------------------------------------------------- -->
12073 <sect1> The Anatomy Of A Widget
12075 In order to create a new widget, it is important to have an
12076 understanding of how GTK objects work. This section is just meant as a
12077 brief overview. See the reference documentation for the details.
12079 GTK widgets are implemented in an object oriented fashion. However,
12080 they are implemented in standard C. This greatly improves portability
12081 and stability over using current generation C++ compilers; however,
12082 it does mean that the widget writer has to pay attention to some of
12083 the implementation details. The information common to all instances of
12084 one class of widgets (e.g., to all Button widgets) is stored in the
12085 <em>class structure</em>. There is only one copy of this in
12086 which is stored information about the class's signals
12087 (which act like virtual functions in C). To support inheritance, the
12088 first field in the class structure must be a copy of the parent's
12089 class structure. The declaration of the class structure of GtkButtton
12093 struct _GtkButtonClass
12095 GtkContainerClass parent_class;
12097 void (* pressed) (GtkButton *button);
12098 void (* released) (GtkButton *button);
12099 void (* clicked) (GtkButton *button);
12100 void (* enter) (GtkButton *button);
12101 void (* leave) (GtkButton *button);
12105 When a button is treated as a container (for instance, when it is
12106 resized), its class structure can be cast to GtkContainerClass, and
12107 the relevant fields used to handle the signals.
12109 There is also a structure for each widget that is created on a
12110 per-instance basis. This structure has fields to store information that
12111 is different for each instance of the widget. We'll call this
12112 structure the <em>object structure</em>. For the Button class, it looks
12118 GtkContainer container;
12122 guint in_button : 1;
12123 guint button_down : 1;
12127 Note that, similar to the class structure, the first field is the
12128 object structure of the parent class, so that this structure can be
12129 cast to the parent class's object structure as needed.
12131 <!-- ----------------------------------------------------------------- -->
12132 <sect1> Creating a Composite widget
12134 <!-- ----------------------------------------------------------------- -->
12135 <sect2> Introduction
12137 One type of widget that you may be interested in creating is a
12138 widget that is merely an aggregate of other GTK widgets. This type of
12139 widget does nothing that couldn't be done without creating new
12140 widgets, but provides a convenient way of packaging user interface
12141 elements for reuse. The FileSelection and ColorSelection widgets in
12142 the standard distribution are examples of this type of widget.
12144 The example widget that we'll create in this section is the Tictactoe
12145 widget, a 3x3 array of toggle buttons which triggers a signal when all
12146 three buttons in a row, column, or on one of the diagonals are
12149 <!-- ----------------------------------------------------------------- -->
12150 <sect2> Choosing a parent class
12152 The parent class for a composite widget is typically the container
12153 class that holds all of the elements of the composite widget. For
12154 example, the parent class of the FileSelection widget is the
12155 Dialog class. Since our buttons will be arranged in a table, it
12156 might seem natural to make our parent class the GtkTable
12157 class. Unfortunately, this turns out not to work. The creation of a
12158 widget is divided among two functions - a <tt/WIDGETNAME_new()/
12159 function that the user calls, and a <tt/WIDGETNAME_init()/ function
12160 which does the basic work of initializing the widget which is
12161 independent of the arguments passed to the <tt/_new()/
12162 function. Descendent widgets only call the <tt/_init/ function of
12163 their parent widget. But this division of labor doesn't work well for
12164 tables, which when created, need to know the number of rows and
12165 columns in the table. Unless we want to duplicate most of the
12166 functionality of <tt/gtk_table_new()/ in our Tictactoe widget, we had
12167 best avoid deriving it from GtkTable. For that reason, we derive it
12168 from GtkVBox instead, and stick our table inside the VBox.
12170 <!-- ----------------------------------------------------------------- -->
12171 <sect2> The header file
12173 Each widget class has a header file which declares the object and
12174 class structures for that widget, along with public functions.
12175 A couple of features are worth pointing out. To prevent duplicate
12176 definitions, we wrap the entire header file in:
12179 #ifndef __TICTACTOE_H__
12180 #define __TICTACTOE_H__
12184 #endif /* __TICTACTOE_H__ */
12187 And to keep C++ programs that include the header file happy, in:
12192 #endif /* __cplusplus */
12198 #endif /* __cplusplus */
12201 Along with the functions and structures, we declare three standard
12202 macros in our header file, <tt/TICTACTOE(obj)/,
12203 <tt/TICTACTOE_CLASS(klass)/, and <tt/IS_TICTACTOE(obj)/, which cast a
12204 pointer into a pointer to the object or class structure, and check
12205 if an object is a Tictactoe widget respectively.
12207 Here is the complete header file:
12212 #ifndef __TICTACTOE_H__
12213 #define __TICTACTOE_H__
12215 #include <gdk/gdk.h>
12216 #include <gtk/gtkvbox.h>
12220 #endif /* __cplusplus */
12222 #define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
12223 #define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
12224 #define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
12227 typedef struct _Tictactoe Tictactoe;
12228 typedef struct _TictactoeClass TictactoeClass;
12234 GtkWidget *buttons[3][3];
12237 struct _TictactoeClass
12239 GtkVBoxClass parent_class;
12241 void (* tictactoe) (Tictactoe *ttt);
12244 guint tictactoe_get_type (void);
12245 GtkWidget* tictactoe_new (void);
12246 void tictactoe_clear (Tictactoe *ttt);
12250 #endif /* __cplusplus */
12252 #endif /* __TICTACTOE_H__ */
12256 <!-- ----------------------------------------------------------------- -->
12257 <sect2> The <tt/_get_type()/ function.
12259 We now continue on to the implementation of our widget. A core
12260 function for every widget is the function
12261 <tt/WIDGETNAME_get_type()/. This function, when first called, tells
12262 GTK about the widget class, and gets an ID that uniquely identifies
12263 the widget class. Upon subsequent calls, it just returns the ID.
12267 tictactoe_get_type ()
12269 static guint ttt_type = 0;
12273 GtkTypeInfo ttt_info =
12276 sizeof (Tictactoe),
12277 sizeof (TictactoeClass),
12278 (GtkClassInitFunc) tictactoe_class_init,
12279 (GtkObjectInitFunc) tictactoe_init,
12280 (GtkArgSetFunc) NULL,
12281 (GtkArgGetFunc) NULL
12284 ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
12291 The GtkTypeInfo structure has the following definition:
12294 struct _GtkTypeInfo
12299 GtkClassInitFunc class_init_func;
12300 GtkObjectInitFunc object_init_func;
12301 GtkArgSetFunc arg_set_func;
12302 GtkArgGetFunc arg_get_func;
12306 The fields of this structure are pretty self-explanatory. We'll ignore
12307 the <tt/arg_set_func/ and <tt/arg_get_func/ fields here: they have an important,
12309 unimplemented, role in allowing widget options to be conveniently set
12310 from interpreted languages. Once GTK has a correctly filled in copy of
12311 this structure, it knows how to create objects of a particular widget
12314 <!-- ----------------------------------------------------------------- -->
12315 <sect2> The <tt/_class_init()/ function
12317 The <tt/WIDGETNAME_class_init()/ function initializes the fields of
12318 the widget's class structure, and sets up any signals for the
12319 class. For our Tictactoe widget it looks like:
12328 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
12331 tictactoe_class_init (TictactoeClass *class)
12333 GtkObjectClass *object_class;
12335 object_class = (GtkObjectClass*) class;
12337 tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
12339 object_class->type,
12340 GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
12341 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
12344 gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
12346 class->tictactoe = NULL;
12350 Our widget has just one signal, the <tt/tictactoe/ signal that is
12351 invoked when a row, column, or diagonal is completely filled in. Not
12352 every composite widget needs signals, so if you are reading this for
12353 the first time, you may want to skip to the next section now, as
12354 things are going to get a bit complicated.
12359 gint gtk_signal_new( const gchar *name,
12360 GtkSignalRunType run_type,
12361 GtkType object_type,
12362 gint function_offset,
12363 GtkSignalMarshaller marshaller,
12364 GtkType return_val,
12369 Creates a new signal. The parameters are:
12372 <item> <tt/name/: The name of the signal.
12373 <item> <tt/run_type/: Whether the default handler runs before or after
12374 user handlers. Usually this will be <tt/GTK_RUN_FIRST/, or <tt/GTK_RUN_LAST/,
12375 although there are other possibilities.
12376 <item> <tt/object_type/: The ID of the object that this signal applies
12377 to. (It will also apply to that objects descendents)
12378 <item> <tt/function_offset/: The offset within the class structure of
12379 a pointer to the default handler.
12380 <item> <tt/marshaller/: A function that is used to invoke the signal
12381 handler. For signal handlers that have no arguments other than the
12382 object that emitted the signal and user data, we can use the
12383 pre-supplied marshaller function <tt/gtk_signal_default_marshaller/.
12384 <item> <tt/return_val/: The type of the return val.
12385 <item> <tt/nparams/: The number of parameters of the signal handler
12386 (other than the two default ones mentioned above)
12387 <item> <tt/.../: The types of the parameters.
12390 When specifying types, the <tt/GtkType/ enumeration is used:
12415 /* it'd be great if the next two could be removed eventually */
12417 GTK_TYPE_C_CALLBACK,
12421 } GtkFundamentalType;
12424 <tt/gtk_signal_new()/ returns a unique integer identifier for the
12425 signal, that we store in the <tt/tictactoe_signals/ array, which we
12426 index using an enumeration. (Conventionally, the enumeration elements
12427 are the signal name, uppercased, but here there would be a conflict
12428 with the <tt/TICTACTOE()/ macro, so we called it <tt/TICTACTOE_SIGNAL/
12431 After creating our signals, we need to tell GTK to associate our
12432 signals with the Tictactoe class. We do that by calling
12433 <tt/gtk_object_class_add_signals()/. We then set the pointer which
12434 points to the default handler for the `tictactoe' signal to NULL,
12435 indicating that there is no default action.
12437 <!-- ----------------------------------------------------------------- -->
12438 <sect2> The <tt/_init()/ function.
12440 Each widget class also needs a function to initialize the object
12441 structure. Usually, this function has the fairly limited role of
12442 setting the fields of the structure to default values. For composite
12443 widgets, however, this function also creates the component widgets.
12447 tictactoe_init (Tictactoe *ttt)
12452 table = gtk_table_new (3, 3, TRUE);
12453 gtk_container_add (GTK_CONTAINER(ttt), table);
12454 gtk_widget_show (table);
12459 ttt->buttons[i][j] = gtk_toggle_button_new ();
12460 gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
12462 gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
12463 GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
12464 gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
12465 gtk_widget_show (ttt->buttons[i][j]);
12470 <!-- ----------------------------------------------------------------- -->
12471 <sect2> And the rest...
12473 There is one more function that every widget (except for base widget
12474 types like GtkBin that cannot be instantiated) needs to have - the
12475 function that the user calls to create an object of that type. This is
12476 conventionally called <tt/WIDGETNAME_new()/. In some
12477 widgets, though not for the Tictactoe widgets, this function takes
12478 arguments, and does some setup based on the arguments. The other two
12479 functions are specific to the Tictactoe widget.
12481 <tt/tictactoe_clear()/ is a public function that resets all the
12482 buttons in the widget to the up position. Note the use of
12483 <tt/gtk_signal_handler_block_by_data()/ to keep our signal handler for
12484 button toggles from being triggered unnecessarily.
12486 <tt/tictactoe_toggle()/ is the signal handler that is invoked when the
12487 user clicks on a button. It checks to see if there are any winning
12488 combinations that involve the toggled button, and if so, emits
12489 the "tictactoe" signal.
12495 return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
12499 tictactoe_clear (Tictactoe *ttt)
12506 gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
12507 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
12509 gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
12514 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
12518 static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
12519 { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
12520 { 0, 1, 2 }, { 0, 1, 2 } };
12521 static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
12522 { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
12523 { 0, 1, 2 }, { 2, 1, 0 } };
12525 int success, found;
12527 for (k=0; k<8; k++)
12534 success = success &&
12535 GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
12537 ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
12540 if (success && found)
12542 gtk_signal_emit (GTK_OBJECT (ttt),
12543 tictactoe_signals[TICTACTOE_SIGNAL]);
12550 And finally, an example program using our Tictactoe widget:
12553 #include <gtk/gtk.h>
12554 #include "tictactoe.h"
12556 /* Invoked when a row, column or diagonal is completed */
12558 win (GtkWidget *widget, gpointer data)
12560 g_print ("Yay!\n");
12561 tictactoe_clear (TICTACTOE (widget));
12565 main (int argc, char *argv[])
12570 gtk_init (&argc, &argv);
12572 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
12574 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
12576 gtk_signal_connect (GTK_OBJECT (window), "destroy",
12577 GTK_SIGNAL_FUNC (gtk_exit), NULL);
12579 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
12581 /* Create a new Tictactoe widget */
12582 ttt = tictactoe_new ();
12583 gtk_container_add (GTK_CONTAINER (window), ttt);
12584 gtk_widget_show (ttt);
12586 /* And attach to its "tictactoe" signal */
12587 gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
12588 GTK_SIGNAL_FUNC (win), NULL);
12590 gtk_widget_show (window);
12599 <!-- ----------------------------------------------------------------- -->
12600 <sect1> Creating a widget from scratch.
12602 <!-- ----------------------------------------------------------------- -->
12603 <sect2> Introduction
12605 In this section, we'll learn more about how widgets display themselves
12606 on the screen and interact with events. As an example of this, we'll
12607 create an analog dial widget with a pointer that the user can drag to
12610 <!-- ----------------------------------------------------------------- -->
12611 <sect2> Displaying a widget on the screen
12613 There are several steps that are involved in displaying on the screen.
12614 After the widget is created with a call to <tt/WIDGETNAME_new()/,
12615 several more functions are needed:
12618 <item> <tt/WIDGETNAME_realize()/ is responsible for creating an X
12619 window for the widget if it has one.
12620 <item> <tt/WIDGETNAME_map()/ is invoked after the user calls
12621 <tt/gtk_widget_show()/. It is responsible for making sure the widget
12622 is actually drawn on the screen (<em/mapped/). For a container class,
12623 it must also make calls to <tt/map()/> functions of any child widgets.
12624 <item> <tt/WIDGETNAME_draw()/ is invoked when <tt/gtk_widget_draw()/
12625 is called for the widget or one of its ancestors. It makes the actual
12626 calls to the drawing functions to draw the widget on the screen. For
12627 container widgets, this function must make calls to
12628 <tt/gtk_widget_draw()/ for its child widgets.
12629 <item> <tt/WIDGETNAME_expose()/ is a handler for expose events for the
12630 widget. It makes the necessary calls to the drawing functions to draw
12631 the exposed portion on the screen. For container widgets, this
12632 function must generate expose events for its child widgets which don't
12633 have their own windows. (If they have their own windows, then X will
12634 generate the necessary expose events)
12637 You might notice that the last two functions are quite similar - each
12638 is responsible for drawing the widget on the screen. In fact many
12639 types of widgets don't really care about the difference between the
12640 two. The default <tt/draw()/ function in the widget class simply
12641 generates a synthetic expose event for the redrawn area. However, some
12642 types of widgets can save work by distinguishing between the two
12643 functions. For instance, if a widget has multiple X windows, then
12644 since expose events identify the exposed window, it can redraw only
12645 the affected window, which is not possible for calls to <tt/draw()/.
12647 Container widgets, even if they don't care about the difference for
12648 themselves, can't simply use the default <tt/draw()/ function because
12649 their child widgets might care about the difference. However,
12650 it would be wasteful to duplicate the drawing code between the two
12651 functions. The convention is that such widgets have a function called
12652 <tt/WIDGETNAME_paint()/ that does the actual work of drawing the
12653 widget, that is then called by the <tt/draw()/ and <tt/expose()/
12656 In our example approach, since the dial widget is not a container
12657 widget, and only has a single window, we can take the simplest
12658 approach and use the default <tt/draw()/ function and only implement
12659 an <tt/expose()/ function.
12661 <!-- ----------------------------------------------------------------- -->
12662 <sect2> The origins of the Dial Widget
12664 Just as all land animals are just variants on the first amphibian that
12665 crawled up out of the mud, Gtk widgets tend to start off as variants
12666 of some other, previously written widget. Thus, although this section
12667 is entitled `Creating a Widget from Scratch', the Dial widget really
12668 began with the source code for the Range widget. This was picked as a
12669 starting point because it would be nice if our Dial had the same
12670 interface as the Scale widgets which are just specialized descendents
12671 of the Range widget. So, though the source code is presented below in
12672 finished form, it should not be implied that it was written, <em>deus
12673 ex machina</em> in this fashion. Also, if you aren't yet familiar with
12674 how scale widgets work from the application writer's point of view, it
12675 would be a good idea to look them over before continuing.
12677 <!-- ----------------------------------------------------------------- -->
12680 Quite a bit of our widget should look pretty familiar from the
12681 Tictactoe widget. First, we have a header file:
12684 /* GTK - The GIMP Toolkit
12685 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
12687 * This library is free software; you can redistribute it and/or
12688 * modify it under the terms of the GNU Library General Public
12689 * License as published by the Free Software Foundation; either
12690 * version 2 of the License, or (at your option) any later version.
12692 * This library is distributed in the hope that it will be useful,
12693 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12694 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12695 * Library General Public License for more details.
12697 * You should have received a copy of the GNU Library General Public
12698 * License along with this library; if not, write to the Free
12699 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
12702 #ifndef __GTK_DIAL_H__
12703 #define __GTK_DIAL_H__
12705 #include <gdk/gdk.h>
12706 #include <gtk/gtkadjustment.h>
12707 #include <gtk/gtkwidget.h>
12712 #endif /* __cplusplus */
12715 #define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
12716 #define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
12717 #define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
12720 typedef struct _GtkDial GtkDial;
12721 typedef struct _GtkDialClass GtkDialClass;
12727 /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
12730 /* Button currently pressed or 0 if none */
12733 /* Dimensions of dial components */
12735 gint pointer_width;
12737 /* ID of update timer, or 0 if none */
12740 /* Current angle */
12743 /* Old values from adjustment stored so we know when something changes */
12748 /* The adjustment object that stores the data for this dial */
12749 GtkAdjustment *adjustment;
12752 struct _GtkDialClass
12754 GtkWidgetClass parent_class;
12758 GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
12759 guint gtk_dial_get_type (void);
12760 GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
12761 void gtk_dial_set_update_policy (GtkDial *dial,
12762 GtkUpdateType policy);
12764 void gtk_dial_set_adjustment (GtkDial *dial,
12765 GtkAdjustment *adjustment);
12768 #endif /* __cplusplus */
12771 #endif /* __GTK_DIAL_H__ */
12774 Since there is quite a bit more going on in this widget, than the last
12775 one, we have more fields in the data structure, but otherwise things
12776 are pretty similar.
12778 Next, after including header files, and declaring a few constants,
12779 we have some functions to provide information about the widget
12785 #include <gtk/gtkmain.h>
12786 #include <gtk/gtksignal.h>
12788 #include "gtkdial.h"
12790 #define SCROLL_DELAY_LENGTH 300
12791 #define DIAL_DEFAULT_SIZE 100
12793 /* Forward declarations */
12795 [ omitted to save space ]
12799 static GtkWidgetClass *parent_class = NULL;
12802 gtk_dial_get_type ()
12804 static guint dial_type = 0;
12808 GtkTypeInfo dial_info =
12812 sizeof (GtkDialClass),
12813 (GtkClassInitFunc) gtk_dial_class_init,
12814 (GtkObjectInitFunc) gtk_dial_init,
12815 (GtkArgSetFunc) NULL,
12816 (GtkArgGetFunc) NULL,
12819 dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info);
12826 gtk_dial_class_init (GtkDialClass *class)
12828 GtkObjectClass *object_class;
12829 GtkWidgetClass *widget_class;
12831 object_class = (GtkObjectClass*) class;
12832 widget_class = (GtkWidgetClass*) class;
12834 parent_class = gtk_type_class (gtk_widget_get_type ());
12836 object_class->destroy = gtk_dial_destroy;
12838 widget_class->realize = gtk_dial_realize;
12839 widget_class->expose_event = gtk_dial_expose;
12840 widget_class->size_request = gtk_dial_size_request;
12841 widget_class->size_allocate = gtk_dial_size_allocate;
12842 widget_class->button_press_event = gtk_dial_button_press;
12843 widget_class->button_release_event = gtk_dial_button_release;
12844 widget_class->motion_notify_event = gtk_dial_motion_notify;
12848 gtk_dial_init (GtkDial *dial)
12851 dial->policy = GTK_UPDATE_CONTINUOUS;
12854 dial->pointer_width = 0;
12856 dial->old_value = 0.0;
12857 dial->old_lower = 0.0;
12858 dial->old_upper = 0.0;
12859 dial->adjustment = NULL;
12863 gtk_dial_new (GtkAdjustment *adjustment)
12867 dial = gtk_type_new (gtk_dial_get_type ());
12870 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
12872 gtk_dial_set_adjustment (dial, adjustment);
12874 return GTK_WIDGET (dial);
12878 gtk_dial_destroy (GtkObject *object)
12882 g_return_if_fail (object != NULL);
12883 g_return_if_fail (GTK_IS_DIAL (object));
12885 dial = GTK_DIAL (object);
12887 if (dial->adjustment)
12888 gtk_object_unref (GTK_OBJECT (dial->adjustment));
12890 if (GTK_OBJECT_CLASS (parent_class)->destroy)
12891 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
12895 Note that this <tt/init()/ function does less than for the Tictactoe
12896 widget, since this is not a composite widget, and the <tt/new()/
12897 function does more, since it now has an argument. Also, note that when
12898 we store a pointer to the Adjustment object, we increment its
12899 reference count, (and correspondingly decrement when we no longer use
12900 it) so that GTK can keep track of when it can be safely destroyed.
12903 Also, there are a few function to manipulate the widget's options:
12907 gtk_dial_get_adjustment (GtkDial *dial)
12909 g_return_val_if_fail (dial != NULL, NULL);
12910 g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
12912 return dial->adjustment;
12916 gtk_dial_set_update_policy (GtkDial *dial,
12917 GtkUpdateType policy)
12919 g_return_if_fail (dial != NULL);
12920 g_return_if_fail (GTK_IS_DIAL (dial));
12922 dial->policy = policy;
12926 gtk_dial_set_adjustment (GtkDial *dial,
12927 GtkAdjustment *adjustment)
12929 g_return_if_fail (dial != NULL);
12930 g_return_if_fail (GTK_IS_DIAL (dial));
12932 if (dial->adjustment)
12934 gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
12935 gtk_object_unref (GTK_OBJECT (dial->adjustment));
12938 dial->adjustment = adjustment;
12939 gtk_object_ref (GTK_OBJECT (dial->adjustment));
12941 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
12942 (GtkSignalFunc) gtk_dial_adjustment_changed,
12944 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
12945 (GtkSignalFunc) gtk_dial_adjustment_value_changed,
12948 dial->old_value = adjustment->value;
12949 dial->old_lower = adjustment->lower;
12950 dial->old_upper = adjustment->upper;
12952 gtk_dial_update (dial);
12956 <sect2> <tt/gtk_dial_realize()/
12959 Now we come to some new types of functions. First, we have a function
12960 that does the work of creating the X window. Notice that a mask is
12961 passed to the function <tt/gdk_window_new()/ which specifies which fields of
12962 the GdkWindowAttr structure actually have data in them (the remaining
12963 fields will be given default values). Also worth noting is the way the
12964 event mask of the widget is created. We call
12965 <tt/gtk_widget_get_events()/ to retrieve the event mask that the user
12966 has specified for this widget (with <tt/gtk_widget_set_events()/, and
12967 add the events that we are interested in ourselves.
12970 After creating the window, we set its style and background, and put a
12971 pointer to the widget in the user data field of the GdkWindow. This
12972 last step allows GTK to dispatch events for this window to the correct
12977 gtk_dial_realize (GtkWidget *widget)
12980 GdkWindowAttr attributes;
12981 gint attributes_mask;
12983 g_return_if_fail (widget != NULL);
12984 g_return_if_fail (GTK_IS_DIAL (widget));
12986 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
12987 dial = GTK_DIAL (widget);
12989 attributes.x = widget->allocation.x;
12990 attributes.y = widget->allocation.y;
12991 attributes.width = widget->allocation.width;
12992 attributes.height = widget->allocation.height;
12993 attributes.wclass = GDK_INPUT_OUTPUT;
12994 attributes.window_type = GDK_WINDOW_CHILD;
12995 attributes.event_mask = gtk_widget_get_events (widget) |
12996 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
12997 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
12998 GDK_POINTER_MOTION_HINT_MASK;
12999 attributes.visual = gtk_widget_get_visual (widget);
13000 attributes.colormap = gtk_widget_get_colormap (widget);
13002 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
13003 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
13005 widget->style = gtk_style_attach (widget->style, widget->window);
13007 gdk_window_set_user_data (widget->window, widget);
13009 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
13013 <sect2> Size negotiation
13016 Before the first time that the window containing a widget is
13017 displayed, and whenever the layout of the window changes, GTK asks
13018 each child widget for its desired size. This request is handled by the
13019 function, <tt/gtk_dial_size_request()/. Since our widget isn't a
13020 container widget, and has no real constraints on its size, we just
13021 return a reasonable default value.
13025 gtk_dial_size_request (GtkWidget *widget,
13026 GtkRequisition *requisition)
13028 requisition->width = DIAL_DEFAULT_SIZE;
13029 requisition->height = DIAL_DEFAULT_SIZE;
13034 After all the widgets have requested an ideal size, the layout of the
13035 window is computed and each child widget is notified of its actual
13036 size. Usually, this will at least as large as the requested size, but
13037 if for instance, the user has resized the window, it may occasionally
13038 be smaller than the requested size. The size notification is handled
13039 by the function <tt/gtk_dial_size_allocate()/. Notice that as well as
13040 computing the sizes of some component pieces for future use, this
13041 routine also does the grunt work of moving the widgets X window into
13042 the new position and size.
13046 gtk_dial_size_allocate (GtkWidget *widget,
13047 GtkAllocation *allocation)
13051 g_return_if_fail (widget != NULL);
13052 g_return_if_fail (GTK_IS_DIAL (widget));
13053 g_return_if_fail (allocation != NULL);
13055 widget->allocation = *allocation;
13056 if (GTK_WIDGET_REALIZED (widget))
13058 dial = GTK_DIAL (widget);
13060 gdk_window_move_resize (widget->window,
13061 allocation->x, allocation->y,
13062 allocation->width, allocation->height);
13064 dial->radius = MAX(allocation->width,allocation->height) * 0.45;
13065 dial->pointer_width = dial->radius / 5;
13070 <!-- ----------------------------------------------------------------- -->
13071 <sect2> <tt/gtk_dial_expose()/
13074 As mentioned above, all the drawing of this widget is done in the
13075 handler for expose events. There's not much to remark on here except
13076 the use of the function <tt/gtk_draw_polygon/ to draw the pointer with
13077 three dimensional shading according to the colors stored in the
13082 gtk_dial_expose (GtkWidget *widget,
13083 GdkEventExpose *event)
13086 GdkPoint points[3];
13093 g_return_val_if_fail (widget != NULL, FALSE);
13094 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13095 g_return_val_if_fail (event != NULL, FALSE);
13097 if (event->count > 0)
13100 dial = GTK_DIAL (widget);
13102 gdk_window_clear_area (widget->window,
13104 widget->allocation.width,
13105 widget->allocation.height);
13107 xc = widget->allocation.width/2;
13108 yc = widget->allocation.height/2;
13112 for (i=0; i<25; i++)
13114 theta = (i*M_PI/18. - M_PI/6.);
13118 tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
13120 gdk_draw_line (widget->window,
13121 widget->style->fg_gc[widget->state],
13122 xc + c*(dial->radius - tick_length),
13123 yc - s*(dial->radius - tick_length),
13124 xc + c*dial->radius,
13125 yc - s*dial->radius);
13130 s = sin(dial->angle);
13131 c = cos(dial->angle);
13134 points[0].x = xc + s*dial->pointer_width/2;
13135 points[0].y = yc + c*dial->pointer_width/2;
13136 points[1].x = xc + c*dial->radius;
13137 points[1].y = yc - s*dial->radius;
13138 points[2].x = xc - s*dial->pointer_width/2;
13139 points[2].y = yc - c*dial->pointer_width/2;
13141 gtk_draw_polygon (widget->style,
13152 <!-- ----------------------------------------------------------------- -->
13153 <sect2> Event handling
13155 The rest of the widget's code handles various types of events, and
13156 isn't too different from what would be found in many GTK
13157 applications. Two types of events can occur - either the user can
13158 click on the widget with the mouse and drag to move the pointer, or
13159 the value of the Adjustment object can change due to some external
13162 When the user clicks on the widget, we check to see if the click was
13163 appropriately near the pointer, and if so, store then button that the
13164 user clicked with in the <tt/button/ field of the widget
13165 structure, and grab all mouse events with a call to
13166 <tt/gtk_grab_add()/. Subsequent motion of the mouse causes the
13167 value of the control to be recomputed (by the function
13168 <tt/gtk_dial_update_mouse/). Depending on the policy that has been
13169 set, "value_changed" events are either generated instantly
13170 (<tt/GTK_UPDATE_CONTINUOUS/), after a delay in a timer added with
13171 <tt/gtk_timeout_add()/ (<tt/GTK_UPDATE_DELAYED/), or only when the
13172 button is released (<tt/GTK_UPDATE_DISCONTINUOUS/).
13176 gtk_dial_button_press (GtkWidget *widget,
13177 GdkEventButton *event)
13183 double d_perpendicular;
13185 g_return_val_if_fail (widget != NULL, FALSE);
13186 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13187 g_return_val_if_fail (event != NULL, FALSE);
13189 dial = GTK_DIAL (widget);
13191 /* Determine if button press was within pointer region - we
13192 do this by computing the parallel and perpendicular distance of
13193 the point where the mouse was pressed from the line passing through
13196 dx = event->x - widget->allocation.width / 2;
13197 dy = widget->allocation.height / 2 - event->y;
13199 s = sin(dial->angle);
13200 c = cos(dial->angle);
13202 d_parallel = s*dy + c*dx;
13203 d_perpendicular = fabs(s*dx - c*dy);
13205 if (!dial->button &&
13206 (d_perpendicular < dial->pointer_width/2) &&
13207 (d_parallel > - dial->pointer_width))
13209 gtk_grab_add (widget);
13211 dial->button = event->button;
13213 gtk_dial_update_mouse (dial, event->x, event->y);
13220 gtk_dial_button_release (GtkWidget *widget,
13221 GdkEventButton *event)
13225 g_return_val_if_fail (widget != NULL, FALSE);
13226 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13227 g_return_val_if_fail (event != NULL, FALSE);
13229 dial = GTK_DIAL (widget);
13231 if (dial->button == event->button)
13233 gtk_grab_remove (widget);
13237 if (dial->policy == GTK_UPDATE_DELAYED)
13238 gtk_timeout_remove (dial->timer);
13240 if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
13241 (dial->old_value != dial->adjustment->value))
13242 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13249 gtk_dial_motion_notify (GtkWidget *widget,
13250 GdkEventMotion *event)
13253 GdkModifierType mods;
13256 g_return_val_if_fail (widget != NULL, FALSE);
13257 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13258 g_return_val_if_fail (event != NULL, FALSE);
13260 dial = GTK_DIAL (widget);
13262 if (dial->button != 0)
13267 if (event->is_hint || (event->window != widget->window))
13268 gdk_window_get_pointer (widget->window, &x, &y, &mods);
13270 switch (dial->button)
13273 mask = GDK_BUTTON1_MASK;
13276 mask = GDK_BUTTON2_MASK;
13279 mask = GDK_BUTTON3_MASK;
13287 gtk_dial_update_mouse (dial, x,y);
13294 gtk_dial_timer (GtkDial *dial)
13296 g_return_val_if_fail (dial != NULL, FALSE);
13297 g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
13299 if (dial->policy == GTK_UPDATE_DELAYED)
13300 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13306 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
13311 g_return_if_fail (dial != NULL);
13312 g_return_if_fail (GTK_IS_DIAL (dial));
13314 xc = GTK_WIDGET(dial)->allocation.width / 2;
13315 yc = GTK_WIDGET(dial)->allocation.height / 2;
13317 old_value = dial->adjustment->value;
13318 dial->angle = atan2(yc-y, x-xc);
13320 if (dial->angle < -M_PI/2.)
13321 dial->angle += 2*M_PI;
13323 if (dial->angle < -M_PI/6)
13324 dial->angle = -M_PI/6;
13326 if (dial->angle > 7.*M_PI/6.)
13327 dial->angle = 7.*M_PI/6.;
13329 dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
13330 (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
13332 if (dial->adjustment->value != old_value)
13334 if (dial->policy == GTK_UPDATE_CONTINUOUS)
13336 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13340 gtk_widget_draw (GTK_WIDGET(dial), NULL);
13342 if (dial->policy == GTK_UPDATE_DELAYED)
13345 gtk_timeout_remove (dial->timer);
13347 dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
13348 (GtkFunction) gtk_dial_timer,
13356 Changes to the Adjustment by external means are communicated to our
13357 widget by the `changed' and `value_changed' signals. The handlers
13358 for these functions call <tt/gtk_dial_update()/ to validate the
13359 arguments, compute the new pointer angle, and redraw the widget (by
13360 calling <tt/gtk_widget_draw()/).
13364 gtk_dial_update (GtkDial *dial)
13368 g_return_if_fail (dial != NULL);
13369 g_return_if_fail (GTK_IS_DIAL (dial));
13371 new_value = dial->adjustment->value;
13373 if (new_value < dial->adjustment->lower)
13374 new_value = dial->adjustment->lower;
13376 if (new_value > dial->adjustment->upper)
13377 new_value = dial->adjustment->upper;
13379 if (new_value != dial->adjustment->value)
13381 dial->adjustment->value = new_value;
13382 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13385 dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
13386 (dial->adjustment->upper - dial->adjustment->lower);
13388 gtk_widget_draw (GTK_WIDGET(dial), NULL);
13392 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
13397 g_return_if_fail (adjustment != NULL);
13398 g_return_if_fail (data != NULL);
13400 dial = GTK_DIAL (data);
13402 if ((dial->old_value != adjustment->value) ||
13403 (dial->old_lower != adjustment->lower) ||
13404 (dial->old_upper != adjustment->upper))
13406 gtk_dial_update (dial);
13408 dial->old_value = adjustment->value;
13409 dial->old_lower = adjustment->lower;
13410 dial->old_upper = adjustment->upper;
13415 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
13420 g_return_if_fail (adjustment != NULL);
13421 g_return_if_fail (data != NULL);
13423 dial = GTK_DIAL (data);
13425 if (dial->old_value != adjustment->value)
13427 gtk_dial_update (dial);
13429 dial->old_value = adjustment->value;
13434 <!-- ----------------------------------------------------------------- -->
13435 <sect2> Possible Enhancements
13437 The Dial widget as we've described it so far runs about 670 lines of
13438 code. Although that might sound like a fair bit, we've really
13439 accomplished quite a bit with that much code, especially since much of
13440 that length is headers and boilerplate. However, there are quite a few
13441 more enhancements that could be made to this widget:
13444 <item> If you try this widget out, you'll find that there is some
13445 flashing as the pointer is dragged around. This is because the entire
13446 widget is erased every time the pointer is moved before being
13447 redrawn. Often, the best way to handle this problem is to draw to an
13448 offscreen pixmap, then copy the final results onto the screen in one
13449 step. (The ProgressBar widget draws itself in this fashion.)
13451 <item> The user should be able to use the up and down arrow keys to
13452 increase and decrease the value.
13454 <item> It would be nice if the widget had buttons to increase and
13455 decrease the value in small or large steps. Although it would be
13456 possible to use embedded Button widgets for this, we would also like
13457 the buttons to auto-repeat when held down, as the arrows on a
13458 scrollbar do. Most of the code to implement this type of behavior can
13459 be found in the GtkRange widget.
13461 <item> The Dial widget could be made into a container widget with a
13462 single child widget positioned at the bottom between the buttons
13463 mentioned above. The user could then add their choice of a label or
13464 entry widget to display the current value of the dial.
13468 <!-- ----------------------------------------------------------------- -->
13469 <sect1> Learning More
13472 Only a small part of the many details involved in creating widgets
13473 could be described above. If you want to write your own widgets, the
13474 best source of examples is the GTK source itself. Ask yourself some
13475 questions about the widget you want to write: is it a Container
13476 widget? does it have its own window? is it a modification of an
13477 existing widget? Then find a similar widget, and start making changes.
13480 <!-- ***************************************************************** -->
13481 <sect>Scribble, A Simple Example Drawing Program
13482 <!-- ***************************************************************** -->
13484 <!-- ----------------------------------------------------------------- -->
13487 In this section, we will build a simple drawing program. In the
13488 process, we will examine how to handle mouse events, how to draw in a
13489 window, and how to do drawing better by using a backing pixmap. After
13490 creating the simple drawing program, we will extend it by adding
13491 support for XInput devices, such as drawing tablets. GTK provides
13492 support routines which makes getting extended information, such as
13493 pressure and tilt, from such devices quite easy.
13495 <!-- ----------------------------------------------------------------- -->
13496 <sect1> Event Handling
13498 The GTK signals we have already discussed are for high-level actions,
13499 such as a menu item being selected. However, sometimes it is useful to
13500 learn about lower-level occurrences, such as the mouse being moved, or
13501 a key being pressed. There are also GTK signals corresponding to these
13502 low-level <em>events</em>. The handlers for these signals have an
13503 extra parameter which is a pointer to a structure containing
13504 information about the event. For instance, motion events handlers are
13505 passed a pointer to a GdkEventMotion structure which looks (in part)
13509 struct _GdkEventMotion
13522 <tt/type/ will be set to the event type, in this case
13523 <tt/GDK_MOTION_NOTIFY/, window is the window in which the event
13524 occurred. <tt/x/ and <tt/y/ give the coordinates of the event,
13525 and <tt/state/ specifies the modifier state when the event
13526 occurred (that is, it specifies which modifier keys and mouse buttons
13527 were pressed.) It is the bitwise OR of some of the following:
13545 As for other signals, to determine what happens when an event occurs
13546 we call <tt>gtk_signal_connect()</tt>. But we also need let GTK
13547 know which events we want to be notified about. To do this, we call
13551 void gtk_widget_set_events (GtkWidget *widget,
13555 The second field specifies the events we are interested in. It
13556 is the bitwise OR of constants that specify different types
13557 of events. For future reference the event types are:
13561 GDK_POINTER_MOTION_MASK
13562 GDK_POINTER_MOTION_HINT_MASK
13563 GDK_BUTTON_MOTION_MASK
13564 GDK_BUTTON1_MOTION_MASK
13565 GDK_BUTTON2_MOTION_MASK
13566 GDK_BUTTON3_MOTION_MASK
13567 GDK_BUTTON_PRESS_MASK
13568 GDK_BUTTON_RELEASE_MASK
13570 GDK_KEY_RELEASE_MASK
13571 GDK_ENTER_NOTIFY_MASK
13572 GDK_LEAVE_NOTIFY_MASK
13573 GDK_FOCUS_CHANGE_MASK
13575 GDK_PROPERTY_CHANGE_MASK
13576 GDK_PROXIMITY_IN_MASK
13577 GDK_PROXIMITY_OUT_MASK
13580 There are a few subtle points that have to be observed when calling
13581 <tt/gtk_widget_set_events()/. First, it must be called before the X window
13582 for a GTK widget is created. In practical terms, this means you
13583 should call it immediately after creating the widget. Second, the
13584 widget must have an associated X window. For efficiency, many widget
13585 types do not have their own window, but draw in their parent's window.
13608 To capture events for these widgets, you need to use an EventBox
13609 widget. See the section on the <ref id="sec_EventBox"
13610 name="EventBox"> widget for details.
13612 For our drawing program, we want to know when the mouse button is
13613 pressed and when the mouse is moved, so we specify
13614 <tt/GDK_POINTER_MOTION_MASK/ and <tt/GDK_BUTTON_PRESS_MASK/. We also
13615 want to know when we need to redraw our window, so we specify
13616 <tt/GDK_EXPOSURE_MASK/. Although we want to be notified via a
13617 Configure event when our window size changes, we don't have to specify
13618 the corresponding <tt/GDK_STRUCTURE_MASK/ flag, because it is
13619 automatically specified for all windows.
13621 It turns out, however, that there is a problem with just specifying
13622 <tt/GDK_POINTER_MOTION_MASK/. This will cause the server to add a new
13623 motion event to the event queue every time the user moves the mouse.
13624 Imagine that it takes us 0.1 seconds to handle a motion event, but the
13625 X server queues a new motion event every 0.05 seconds. We will soon
13626 get way behind the users drawing. If the user draws for 5 seconds,
13627 it will take us another 5 seconds to catch up after they release
13628 the mouse button! What we would like is to only get one motion
13629 event for each event we process. The way to do this is to
13630 specify <tt/GDK_POINTER_MOTION_HINT_MASK/.
13632 When we specify <tt/GDK_POINTER_MOTION_HINT_MASK/, the server sends
13633 us a motion event the first time the pointer moves after entering
13634 our window, or after a button press or release event. Subsequent
13635 motion events will be suppressed until we explicitly ask for
13636 the position of the pointer using the function:
13639 GdkWindow* gdk_window_get_pointer (GdkWindow *window,
13642 GdkModifierType *mask);
13645 (There is another function, <tt>gtk_widget_get_pointer()</tt> which
13646 has a simpler interface, but turns out not to be very useful, since
13647 it only retrieves the position of the mouse, not whether the buttons
13650 The code to set the events for our window then looks like:
13653 gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
13654 (GtkSignalFunc) expose_event, NULL);
13655 gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
13656 (GtkSignalFunc) configure_event, NULL);
13657 gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
13658 (GtkSignalFunc) motion_notify_event, NULL);
13659 gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
13660 (GtkSignalFunc) button_press_event, NULL);
13662 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
13663 | GDK_LEAVE_NOTIFY_MASK
13664 | GDK_BUTTON_PRESS_MASK
13665 | GDK_POINTER_MOTION_MASK
13666 | GDK_POINTER_MOTION_HINT_MASK);
13669 We'll save the "expose_event" and "configure_event" handlers for
13670 later. The "motion_notify_event" and "button_press_event" handlers
13675 button_press_event (GtkWidget *widget, GdkEventButton *event)
13677 if (event->button == 1 && pixmap != NULL)
13678 draw_brush (widget, event->x, event->y);
13684 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
13687 GdkModifierType state;
13689 if (event->is_hint)
13690 gdk_window_get_pointer (event->window, &x, &y, &state);
13695 state = event->state;
13698 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
13699 draw_brush (widget, x, y);
13705 <!-- ----------------------------------------------------------------- -->
13706 <sect1> The DrawingArea Widget, And Drawing
13708 We know turn to the process of drawing on the screen. The
13709 widget we use for this is the DrawingArea widget. A drawing area
13710 widget is essentially an X window and nothing more. It is a blank
13711 canvas in which we can draw whatever we like. A drawing area
13712 is created using the call:
13715 GtkWidget* gtk_drawing_area_new (void);
13718 A default size for the widget can be specified by calling:
13721 void gtk_drawing_area_size (GtkDrawingArea *darea,
13726 This default size can be overridden, as is true for all widgets,
13727 by calling <tt>gtk_widget_set_usize()</tt>, and that, in turn, can
13728 be overridden if the user manually resizes the the window containing
13731 It should be noted that when we create a DrawingArea widget, we are,
13732 <em>completely</em> responsible for drawing the contents. If our
13733 window is obscured then uncovered, we get an exposure event and must
13734 redraw what was previously hidden.
13736 Having to remember everything that was drawn on the screen so we
13737 can properly redraw it can, to say the least, be a nuisance. In
13738 addition, it can be visually distracting if portions of the
13739 window are cleared, then redrawn step by step. The solution to
13740 this problem is to use an offscreen <em>backing pixmap</em>.
13741 Instead of drawing directly to the screen, we draw to an image
13742 stored in server memory but not displayed, then when the image
13743 changes or new portions of the image are displayed, we copy the
13744 relevant portions onto the screen.
13746 To create an offscreen pixmap, we call the function:
13749 GdkPixmap* gdk_pixmap_new (GdkWindow *window,
13755 The <tt>window</tt> parameter specifies a GDK window that this pixmap
13756 takes some of its properties from. <tt>width</tt> and <tt>height</tt>
13757 specify the size of the pixmap. <tt>depth</tt> specifies the <em>color
13758 depth</em>, that is the number of bits per pixel, for the new window.
13759 If the depth is specified as <tt>-1</tt>, it will match the depth
13760 of <tt>window</tt>.
13762 We create the pixmap in our "configure_event" handler. This event
13763 is generated whenever the window changes size, including when it
13764 is originally created.
13767 /* Backing pixmap for drawing area */
13768 static GdkPixmap *pixmap = NULL;
13770 /* Create a new backing pixmap of the appropriate size */
13772 configure_event (GtkWidget *widget, GdkEventConfigure *event)
13775 gdk_pixmap_unref(pixmap);
13777 pixmap = gdk_pixmap_new(widget->window,
13778 widget->allocation.width,
13779 widget->allocation.height,
13781 gdk_draw_rectangle (pixmap,
13782 widget->style->white_gc,
13785 widget->allocation.width,
13786 widget->allocation.height);
13792 The call to <tt>gdk_draw_rectangle()</tt> clears the pixmap
13793 initially to white. We'll say more about that in a moment.
13795 Our exposure event handler then simply copies the relevant portion
13796 of the pixmap onto the screen (we determine the area we need
13797 to redraw by using the event->area field of the exposure event):
13800 /* Redraw the screen from the backing pixmap */
13802 expose_event (GtkWidget *widget, GdkEventExpose *event)
13804 gdk_draw_pixmap(widget->window,
13805 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
13807 event->area.x, event->area.y,
13808 event->area.x, event->area.y,
13809 event->area.width, event->area.height);
13815 We've now seen how to keep the screen up to date with our pixmap, but
13816 how do we actually draw interesting stuff on our pixmap? There are a
13817 large number of calls in GTK's GDK library for drawing on
13818 <em>drawables</em>. A drawable is simply something that can be drawn
13819 upon. It can be a window, a pixmap, or a bitmap (a black and white
13820 image). We've already seen two such calls above,
13821 <tt>gdk_draw_rectangle()</tt> and <tt>gdk_draw_pixmap()</tt>. The
13826 gdk_draw_rectangle ()
13828 gdk_draw_polygon ()
13835 gdk_draw_segments ()
13838 See the reference documentation or the header file
13839 <tt><gdk/gdk.h></tt> for further details on these functions.
13840 These functions all share the same first two arguments. The first
13841 argument is the drawable to draw upon, the second argument is a
13842 <em>graphics context</em> (GC).
13844 A graphics context encapsulates information about things such as
13845 foreground and background color and line width. GDK has a full set of
13846 functions for creating and modifying graphics contexts, but to keep
13847 things simple we'll just use predefined graphics contexts. Each widget
13848 has an associated style. (Which can be modified in a gtkrc file, see
13849 the section GTK's rc file.) This, among other things, stores a number
13850 of graphics contexts. Some examples of accessing these graphics
13854 widget->style->white_gc
13855 widget->style->black_gc
13856 widget->style->fg_gc[GTK_STATE_NORMAL]
13857 widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
13860 The fields <tt>fg_gc</tt>, <tt>bg_gc</tt>, <tt>dark_gc</tt>, and
13861 <tt>light_gc</tt> are indexed by a parameter of type
13862 <tt>GtkStateType</tt> which can take on the values:
13867 GTK_STATE_PRELIGHT,
13868 GTK_STATE_SELECTED,
13869 GTK_STATE_INSENSITIVE
13872 For instance, the for <tt/GTK_STATE_SELECTED/ the default foreground
13873 color is white and the default background color, dark blue.
13875 Our function <tt>draw_brush()</tt>, which does the actual drawing
13876 on the screen, is then:
13879 /* Draw a rectangle on the screen */
13881 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
13883 GdkRectangle update_rect;
13885 update_rect.x = x - 5;
13886 update_rect.y = y - 5;
13887 update_rect.width = 10;
13888 update_rect.height = 10;
13889 gdk_draw_rectangle (pixmap,
13890 widget->style->black_gc,
13892 update_rect.x, update_rect.y,
13893 update_rect.width, update_rect.height);
13894 gtk_widget_draw (widget, &update_rect);
13898 After we draw the rectangle representing the brush onto the pixmap,
13899 we call the function:
13902 void gtk_widget_draw (GtkWidget *widget,
13903 GdkRectangle *area);
13906 which notifies X that the area given by the <tt>area</tt> parameter
13907 needs to be updated. X will eventually generate an expose event
13908 (possibly combining the areas passed in several calls to
13909 <tt>gtk_widget_draw()</tt>) which will cause our expose event handler
13910 to copy the relevant portions to the screen.
13912 We have now covered the entire drawing program except for a few
13913 mundane details like creating the main window. The complete
13914 source code is available from the location from which you got
13915 this tutorial, or from:
13917 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
13918 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
13921 <!-- ----------------------------------------------------------------- -->
13922 <sect1> Adding XInput support
13924 It is now possible to buy quite inexpensive input devices such
13925 as drawing tablets, which allow drawing with a much greater
13926 ease of artistic expression than does a mouse. The simplest way
13927 to use such devices is simply as a replacement for the mouse,
13928 but that misses out many of the advantages of these devices,
13932 <item> Pressure sensitivity
13933 <item> Tilt reporting
13934 <item> Sub-pixel positioning
13935 <item> Multiple inputs (for example, a stylus with a point and eraser)
13938 For information about the XInput extension, see the <htmlurl
13939 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
13940 name="XInput-HOWTO">.
13942 If we examine the full definition of, for example, the GdkEventMotion
13943 structure, we see that it has fields to support extended device
13947 struct _GdkEventMotion
13959 GdkInputSource source;
13964 <tt/pressure/ gives the pressure as a floating point number between
13965 0 and 1. <tt/xtilt/ and <tt/ytilt/ can take on values between
13966 -1 and 1, corresponding to the degree of tilt in each direction.
13967 <tt/source/ and <tt/deviceid/ specify the device for which the
13968 event occurred in two different ways. <tt/source/ gives some simple
13969 information about the type of device. It can take the enumeration
13979 <tt/deviceid/ specifies a unique numeric ID for the device. This can
13980 be used to find out further information about the device using the
13981 <tt/gdk_input_list_devices()/ call (see below). The special value
13982 <tt/GDK_CORE_POINTER/ is used for the core pointer device. (Usually
13985 <sect2> Enabling extended device information
13987 To let GTK know about our interest in the extended device information,
13988 we merely have to add a single line to our program:
13991 gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
13994 By giving the value <tt/GDK_EXTENSION_EVENTS_CURSOR/ we say that
13995 we are interested in extension events, but only if we don't have
13996 to draw our own cursor. See the section <ref
13997 id="sec_Further_Sophistications" name="Further Sophistications"> below
13998 for more information about drawing the cursor. We could also
13999 give the values <tt/GDK_EXTENSION_EVENTS_ALL/ if we were willing
14000 to draw our own cursor, or <tt/GDK_EXTENSION_EVENTS_NONE/ to revert
14001 back to the default condition.
14003 This is not completely the end of the story however. By default,
14004 no extension devices are enabled. We need a mechanism to allow
14005 users to enable and configure their extension devices. GTK provides
14006 the InputDialog widget to automate this process. The following
14007 procedure manages an InputDialog widget. It creates the dialog if
14008 it isn't present, and raises it to the top otherwise.
14012 input_dialog_destroy (GtkWidget *w, gpointer data)
14014 *((GtkWidget **)data) = NULL;
14018 create_input_dialog ()
14020 static GtkWidget *inputd = NULL;
14024 inputd = gtk_input_dialog_new();
14026 gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
14027 (GtkSignalFunc)input_dialog_destroy, &inputd);
14028 gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
14030 (GtkSignalFunc)gtk_widget_hide,
14031 GTK_OBJECT(inputd));
14032 gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
14034 gtk_widget_show (inputd);
14038 if (!GTK_WIDGET_MAPPED(inputd))
14039 gtk_widget_show(inputd);
14041 gdk_window_raise(inputd->window);
14046 (You might want to take note of the way we handle this dialog. By
14047 connecting to the "destroy" signal, we make sure that we don't keep a
14048 pointer to dialog around after it is destroyed - that could lead to a
14051 The InputDialog has two buttons "Close" and "Save", which by default
14052 have no actions assigned to them. In the above function we make
14053 "Close" hide the dialog, hide the "Save" button, since we don't
14054 implement saving of XInput options in this program.
14056 <sect2> Using extended device information
14058 Once we've enabled the device, we can just use the extended
14059 device information in the extra fields of the event structures.
14060 In fact, it is always safe to use this information since these
14061 fields will have reasonable default values even when extended
14062 events are not enabled.
14064 Once change we do have to make is to call
14065 <tt/gdk_input_window_get_pointer()/ instead of
14066 <tt/gdk_window_get_pointer/. This is necessary because
14067 <tt/gdk_window_get_pointer/ doesn't return the extended device
14071 void gdk_input_window_get_pointer( GdkWindow *window,
14078 GdkModifierType *mask);
14081 When calling this function, we need to specify the device ID as
14082 well as the window. Usually, we'll get the device ID from the
14083 <tt/deviceid/ field of an event structure. Again, this function
14084 will return reasonable values when extension events are not
14085 enabled. (In this case, <tt/event->deviceid/ will have the value
14086 <tt/GDK_CORE_POINTER/).
14088 So the basic structure of our button-press and motion event handlers,
14089 doesn't change much - we just need to add code to deal with the
14090 extended information.
14094 button_press_event (GtkWidget *widget, GdkEventButton *event)
14096 print_button_press (event->deviceid);
14098 if (event->button == 1 && pixmap != NULL)
14099 draw_brush (widget, event->source, event->x, event->y, event->pressure);
14105 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
14109 GdkModifierType state;
14111 if (event->is_hint)
14112 gdk_input_window_get_pointer (event->window, event->deviceid,
14113 &x, &y, &pressure, NULL, NULL, &state);
14118 pressure = event->pressure;
14119 state = event->state;
14122 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
14123 draw_brush (widget, event->source, x, y, pressure);
14129 We also need to do something with the new information. Our new
14130 <tt/draw_brush()/ function draws with a different color for
14131 each <tt/event->source/ and changes the brush size depending
14135 /* Draw a rectangle on the screen, size depending on pressure,
14136 and color on the type of device */
14138 draw_brush (GtkWidget *widget, GdkInputSource source,
14139 gdouble x, gdouble y, gdouble pressure)
14142 GdkRectangle update_rect;
14146 case GDK_SOURCE_MOUSE:
14147 gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
14149 case GDK_SOURCE_PEN:
14150 gc = widget->style->black_gc;
14152 case GDK_SOURCE_ERASER:
14153 gc = widget->style->white_gc;
14156 gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
14159 update_rect.x = x - 10 * pressure;
14160 update_rect.y = y - 10 * pressure;
14161 update_rect.width = 20 * pressure;
14162 update_rect.height = 20 * pressure;
14163 gdk_draw_rectangle (pixmap, gc, TRUE,
14164 update_rect.x, update_rect.y,
14165 update_rect.width, update_rect.height);
14166 gtk_widget_draw (widget, &update_rect);
14170 <sect2> Finding out more about a device
14172 As an example of how to find out more about a device, our program
14173 will print the name of the device that generates each button
14174 press. To find out the name of a device, we call the function:
14177 GList *gdk_input_list_devices (void);
14180 which returns a GList (a linked list type from the glib library)
14181 of GdkDeviceInfo structures. The GdkDeviceInfo structure is defined
14185 struct _GdkDeviceInfo
14189 GdkInputSource source;
14195 GdkDeviceKey *keys;
14199 Most of these fields are configuration information that you
14200 can ignore unless you are implemented XInput configuration
14201 saving. The we are interested in here is <tt/name/ which is
14202 simply the name that X assigns to the device. The other field
14203 that isn't configuration information is <tt/has_cursor/. If
14204 <tt/has_cursor/ is false, then we we need to draw our own
14205 cursor. But since we've specified <tt/GDK_EXTENSION_EVENTS_CURSOR/,
14206 we don't have to worry about this.
14208 Our <tt/print_button_press()/ function simply iterates through
14209 the returned list until it finds a match, then prints out
14210 the name of the device.
14214 print_button_press (guint32 deviceid)
14218 /* gdk_input_list_devices returns an internal list, so we shouldn't
14219 free it afterwards */
14220 tmp_list = gdk_input_list_devices();
14224 GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
14226 if (info->deviceid == deviceid)
14228 printf("Button press on device '%s'\n", info->name);
14232 tmp_list = tmp_list->next;
14237 That completes the changes to `XInputize' our program. As with
14238 the first version, the complete source is available at the location
14239 from which you got this tutorial, or from:
14241 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
14242 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
14245 <sect2> Further sophistications <label id="sec_Further_Sophistications">
14247 Although our program now supports XInput quite well, it lacks some
14248 features we would want in a full-featured application. First, the user
14249 probably doesn't want to have to configure their device each time they
14250 run the program, so we should allow them to save the device
14251 configuration. This is done by iterating through the return of
14252 <tt/gdk_input_list_devices()/ and writing out the configuration to a
14255 To restore the state next time the program is run, GDK provides
14256 functions to change device configuration:
14259 gdk_input_set_extension_events()
14260 gdk_input_set_source()
14261 gdk_input_set_mode()
14262 gdk_input_set_axes()
14263 gdk_input_set_key()
14266 (The list returned from <tt/gdk_input_list_devices()/ should not be
14267 modified directly.) An example of doing this can be found in the
14268 drawing program gsumi. (Available from <htmlurl
14269 url="http://www.msc.cornell.edu/~otaylor/gsumi/"
14270 name="http://www.msc.cornell.edu/~otaylor/gsumi/">) Eventually, it
14271 would be nice to have a standard way of doing this for all
14272 applications. This probably belongs at a slightly higher level than
14273 GTK, perhaps in the GNOME library.
14275 Another major omission that we have mentioned above is the lack of
14276 cursor drawing. Platforms other than XFree86 currently do not allow
14277 simultaneously using a device as both the core pointer and directly by
14278 an application. See the <url
14279 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
14280 name="XInput-HOWTO"> for more information about this. This means that
14281 applications that want to support the widest audience need to draw
14284 An application that draws its own cursor needs to do two things:
14285 determine if the current device needs a cursor drawn or not, and
14286 determine if the current device is in proximity. (If the current
14287 device is a drawing tablet, it's a nice touch to make the cursor
14288 disappear when the stylus is lifted from the tablet. When the
14289 device is touching the stylus, that is called "in proximity.")
14290 The first is done by searching the device list, as we did
14291 to find out the device name. The second is achieved by selecting
14292 "proximity_out" events. An example of drawing one's own cursor is
14293 found in the 'testinput' program found in the GTK distribution.
14295 <!-- ***************************************************************** -->
14296 <sect>Tips For Writing GTK Applications
14297 <!-- ***************************************************************** -->
14299 This section is simply a gathering of wisdom, general style guidelines
14300 and hints to creating good GTK applications. Currently this section
14301 is very short, but hopefully it will get longer in future editions of
14304 Use GNU autoconf and automake! They are your friends :) Automake
14305 examines C files, determines how they depend on each other, and
14306 generates a Makefile so the files can be compiled in the correct
14307 order. Autoconf permits automatic configuration of software
14308 installation, handling a large number of system quirks to increase
14309 portability. I am planning to make a quick intro on them here.
14311 When writing C code, use only C comments (beginning with "/*" and
14312 ending with "*/"), and don't use C++-style comments ("//"). Although
14313 many C compilers understand C++ comments, others don't, and the ANSI C
14314 standard does not require that C++-style comments be processed as
14317 <!-- ***************************************************************** -->
14318 <sect>Contributing <label id="sec_Contributing">
14319 <!-- ***************************************************************** -->
14321 This document, like so much other great software out there, was
14322 created for free by volunteers. If you are at all knowledgeable about
14323 any aspect of GTK that does not already have documentation, please
14324 consider contributing to this document.
14326 If you do decide to contribute, please mail your text to Tony Gale,
14327 <tt><htmlurl url="mailto:gale@gtk.org"
14328 name="gale@gtk.org"></tt>. Also, be aware that the entirety of this
14329 document is free, and any addition by you provide must also be
14330 free. That is, people may use any portion of your examples in their
14331 programs, and copies of this document may be distributed at will etc.
14335 <!-- ***************************************************************** -->
14337 <!-- ***************************************************************** -->
14339 I would like to thank the following for their contributions to this text.
14342 <item>Bawer Dagdeviren, <tt><htmlurl url="mailto:chamele0n@geocities.com"
14343 name="chamele0n@geocities.com"></tt> for the menus tutorial.
14345 <item>Raph Levien, <tt><htmlurl url="mailto:raph@acm.org"
14346 name="raph@acm.org"></tt>
14347 for hello world ala GTK, widget packing, and general all around wisdom.
14348 He's also generously donated a home for this tutorial.
14350 <item>Peter Mattis, <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
14351 name="petm@xcf.berkeley.edu"></tt> for the simplest GTK program..
14352 and the ability to make it :)
14354 <item>Werner Koch <tt><htmlurl url="mailto:werner.koch@guug.de"
14355 name="werner.koch@guug.de"></tt> for converting the original plain text to
14356 SGML, and the widget class hierarchy.
14358 <item>Mark Crichton <tt><htmlurl
14359 url="mailto:crichton@expert.cc.purdue.edu"
14360 name="crichton@expert.cc.purdue.edu"></tt> for the menu factory code,
14361 and the table packing tutorial.
14363 <item>Owen Taylor <tt><htmlurl url="mailto:owt1@cornell.edu"
14364 name="owt1@cornell.edu"></tt> for the EventBox widget section (and the
14365 patch to the distro). He's also responsible for the selections code
14366 and tutorial, as well as the sections on writing your own GTK widgets,
14367 and the example application. Thanks a lot Owen for all you help!
14369 <item>Mark VanderBoom <tt><htmlurl url="mailto:mvboom42@calvin.edu"
14370 name="mvboom42@calvin.edu"></tt> for his wonderful work on the
14371 Notebook, Progress Bar, Dialogs, and File selection widgets. Thanks a
14372 lot Mark! You've been a great help.
14374 <item>Tim Janik <tt><htmlurl url="mailto:timj@gtk.org"
14375 name="timj@psynet.net"></tt> for his great job on the Lists
14376 Widget. His excellent work on automatically extracting the widget tree
14377 and signal information from GTK. Thanks Tim :)
14379 <item>Rajat Datta <tt><htmlurl url="mailto:rajat@ix.netcom.com"
14380 name="rajat@ix.netcom.com"</tt> for the excellent job on the Pixmap
14383 <item>Michael K. Johnson <tt><htmlurl url="mailto:johnsonm@redhat.com"
14384 name="johnsonm@redhat.com"></tt> for info and code for popup menus.
14386 <item>David Huggins-Daines <tt><htmlurl
14387 url="mailto:bn711@freenet.carleton.ca"
14388 name="bn711@freenet.carleton.ca"></tt> for the Range Widgets and Tree
14391 <item>Stefan Mars <tt><htmlurl url="mailto:mars@lysator.liu.se"
14392 name="mars@lysator.liu.se"></tt> for the GtkCList section.
14394 <item>David A. Wheeler <tt><htmlurl url="mailto:dwheeler@ida.org"
14395 name="dwheeler@ida.org"></tt> for portions of the text on glib
14396 and various tutorial fixups and improvements.
14397 The glib text was in turn based on material developed by Damon Chaplin
14398 <tt><htmlurl url="mailto:DAChaplin@msn.com" name="DAChaplin@msn.com"></tt>
14401 And to all of you who commented and helped refine this document.
14405 <!-- ***************************************************************** -->
14406 <sect> Tutorial Copyright and Permissions Notice
14407 <!-- ***************************************************************** -->
14410 The GTK Tutorial is Copyright (C) 1997 Ian Main.
14412 Copyright (C) 1998-1999 Tony Gale.
14414 Permission is granted to make and distribute verbatim copies of this
14415 manual provided the copyright notice and this permission notice are
14416 preserved on all copies.
14418 Permission is granted to copy and distribute modified versions of
14419 this document under the conditions for verbatim copying, provided that
14420 this copyright notice is included exactly as in the original,
14421 and that the entire resulting derived work is distributed under
14422 the terms of a permission notice identical to this one.
14423 <P>Permission is granted to copy and distribute translations of this
14424 document into another language, under the above conditions for modified
14427 If you are intending to incorporate this document into a published
14428 work, please contact the maintainer, and we will make an effort
14429 to ensure that you have the most up to date information available.
14431 There is no guarantee that this document lives up to its intended
14432 purpose. This is simply provided as a free resource. As such,
14433 the authors and maintainers of the information provided within can
14434 not make any guarantee that the information is even accurate.
14436 <!-- ***************************************************************** -->
14438 <!-- ***************************************************************** -->
14440 <!-- ***************************************************************** -->
14441 <sect> GTK Signals <label id="sec_GTK_Signals">
14442 <!-- ***************************************************************** -->
14444 As GTK is an object oriented widget set, it has a hierarchy of
14445 inheritance. This inheritance mechanism applies for
14446 signals. Therefore, you should refer to the widget hierarchy tree when
14447 using the signals listed in this section.
14449 <!-- ----------------------------------------------------------------- -->
14451 <!-- ----------------------------------------------------------------- -->
14454 void GtkObject::destroy (GtkObject *,
14458 <!-- ----------------------------------------------------------------- -->
14460 <!-- ----------------------------------------------------------------- -->
14464 void GtkWidget::show (GtkWidget *,
14466 void GtkWidget::hide (GtkWidget *,
14468 void GtkWidget::map (GtkWidget *,
14470 void GtkWidget::unmap (GtkWidget *,
14472 void GtkWidget::realize (GtkWidget *,
14474 void GtkWidget::unrealize (GtkWidget *,
14476 void GtkWidget::draw (GtkWidget *,
14479 void GtkWidget::draw-focus (GtkWidget *,
14481 void GtkWidget::draw-default (GtkWidget *,
14483 void GtkWidget::size-request (GtkWidget *,
14486 void GtkWidget::size-allocate (GtkWidget *,
14489 void GtkWidget::state-changed (GtkWidget *,
14492 void GtkWidget::parent-set (GtkWidget *,
14495 void GtkWidget::style-set (GtkWidget *,
14498 void GtkWidget::add-accelerator (GtkWidget *,
14505 void GtkWidget::remove-accelerator (GtkWidget *,
14510 gboolean GtkWidget::event (GtkWidget *,
14513 gboolean GtkWidget::button-press-event (GtkWidget *,
14516 gboolean GtkWidget::button-release-event (GtkWidget *,
14519 gboolean GtkWidget::motion-notify-event (GtkWidget *,
14522 gboolean GtkWidget::delete-event (GtkWidget *,
14525 gboolean GtkWidget::destroy-event (GtkWidget *,
14528 gboolean GtkWidget::expose-event (GtkWidget *,
14531 gboolean GtkWidget::key-press-event (GtkWidget *,
14534 gboolean GtkWidget::key-release-event (GtkWidget *,
14537 gboolean GtkWidget::enter-notify-event (GtkWidget *,
14540 gboolean GtkWidget::leave-notify-event (GtkWidget *,
14543 gboolean GtkWidget::configure-event (GtkWidget *,
14546 gboolean GtkWidget::focus-in-event (GtkWidget *,
14549 gboolean GtkWidget::focus-out-event (GtkWidget *,
14552 gboolean GtkWidget::map-event (GtkWidget *,
14555 gboolean GtkWidget::unmap-event (GtkWidget *,
14558 gboolean GtkWidget::property-notify-event (GtkWidget *,
14561 gboolean GtkWidget::selection-clear-event (GtkWidget *,
14564 gboolean GtkWidget::selection-request-event (GtkWidget *,
14567 gboolean GtkWidget::selection-notify-event (GtkWidget *,
14570 void GtkWidget::selection-get (GtkWidget *,
14571 GtkSelectionData *,
14574 void GtkWidget::selection-received (GtkWidget *,
14575 GtkSelectionData *,
14578 gboolean GtkWidget::proximity-in-event (GtkWidget *,
14581 gboolean GtkWidget::proximity-out-event (GtkWidget *,
14584 void GtkWidget::drag-begin (GtkWidget *,
14587 void GtkWidget::drag-end (GtkWidget *,
14590 void GtkWidget::drag-data-delete (GtkWidget *,
14593 void GtkWidget::drag-leave (GtkWidget *,
14597 gboolean GtkWidget::drag-motion (GtkWidget *,
14603 gboolean GtkWidget::drag-drop (GtkWidget *,
14609 void GtkWidget::drag-data-get (GtkWidget *,
14611 GtkSelectionData *,
14615 void GtkWidget::drag-data-received (GtkWidget *,
14619 GtkSelectionData *,
14623 gboolean GtkWidget::client-event (GtkWidget *,
14626 gboolean GtkWidget::no-expose-event (GtkWidget *,
14629 gboolean GtkWidget::visibility-notify-event (GtkWidget *,
14632 void GtkWidget::debug-msg (GtkWidget *,
14637 <!-- ----------------------------------------------------------------- -->
14639 <!-- ----------------------------------------------------------------- -->
14642 void GtkData::disconnect (GtkData *,
14646 <!-- ----------------------------------------------------------------- -->
14647 <sect1>GtkContainer
14648 <!-- ----------------------------------------------------------------- -->
14651 void GtkContainer::add (GtkContainer *,
14654 void GtkContainer::remove (GtkContainer *,
14657 void GtkContainer::check-resize (GtkContainer *,
14659 GtkDirectionType GtkContainer::focus (GtkContainer *,
14662 void GtkContainer::set-focus-child (GtkContainer *,
14667 <!-- ----------------------------------------------------------------- -->
14669 <!-- ----------------------------------------------------------------- -->
14672 void GtkCalendar::month-changed (GtkCalendar *,
14674 void GtkCalendar::day-selected (GtkCalendar *,
14676 void GtkCalendar::day-selected-double-click (GtkCalendar *,
14678 void GtkCalendar::prev-month (GtkCalendar *,
14680 void GtkCalendar::next-month (GtkCalendar *,
14682 void GtkCalendar::prev-year (GtkCalendar *,
14684 void GtkCalendar::next-year (GtkCalendar *,
14688 <!-- ----------------------------------------------------------------- -->
14690 <!-- ----------------------------------------------------------------- -->
14693 void GtkEditable::changed (GtkEditable *,
14695 void GtkEditable::insert-text (GtkEditable *,
14700 void GtkEditable::delete-text (GtkEditable *,
14704 void GtkEditable::activate (GtkEditable *,
14706 void GtkEditable::set-editable (GtkEditable *,
14709 void GtkEditable::move-cursor (GtkEditable *,
14713 void GtkEditable::move-word (GtkEditable *,
14716 void GtkEditable::move-page (GtkEditable *,
14720 void GtkEditable::move-to-row (GtkEditable *,
14723 void GtkEditable::move-to-column (GtkEditable *,
14726 void GtkEditable::kill-char (GtkEditable *,
14729 void GtkEditable::kill-word (GtkEditable *,
14732 void GtkEditable::kill-line (GtkEditable *,
14735 void GtkEditable::cut-clipboard (GtkEditable *,
14737 void GtkEditable::copy-clipboard (GtkEditable *,
14739 void GtkEditable::paste-clipboard (GtkEditable *,
14743 <!-- ----------------------------------------------------------------- -->
14744 <sect1>GtkTipsQuery
14745 <!-- ----------------------------------------------------------------- -->
14748 void GtkTipsQuery::start-query (GtkTipsQuery *,
14750 void GtkTipsQuery::stop-query (GtkTipsQuery *,
14752 void GtkTipsQuery::widget-entered (GtkTipsQuery *,
14757 gboolean GtkTipsQuery::widget-selected (GtkTipsQuery *,
14765 <!-- ----------------------------------------------------------------- -->
14767 <!-- ----------------------------------------------------------------- -->
14770 void GtkCList::select-row (GtkCList *,
14775 void GtkCList::unselect-row (GtkCList *,
14780 void GtkCList::row-move (GtkCList *,
14784 void GtkCList::click-column (GtkCList *,
14787 void GtkCList::resize-column (GtkCList *,
14791 void GtkCList::toggle-focus-row (GtkCList *,
14793 void GtkCList::select-all (GtkCList *,
14795 void GtkCList::unselect-all (GtkCList *,
14797 void GtkCList::undo-selection (GtkCList *,
14799 void GtkCList::start-selection (GtkCList *,
14801 void GtkCList::end-selection (GtkCList *,
14803 void GtkCList::toggle-add-mode (GtkCList *,
14805 void GtkCList::extend-selection (GtkCList *,
14810 void GtkCList::scroll-vertical (GtkCList *,
14814 void GtkCList::scroll-horizontal (GtkCList *,
14818 void GtkCList::abort-column-resize (GtkCList *,
14822 <!-- ----------------------------------------------------------------- -->
14824 <!-- ----------------------------------------------------------------- -->
14827 void GtkNotebook::switch-page (GtkNotebook *,
14834 <!-- ----------------------------------------------------------------- -->
14836 <!-- ----------------------------------------------------------------- -->
14839 void GtkList::selection-changed (GtkList *,
14841 void GtkList::select-child (GtkList *,
14844 void GtkList::unselect-child (GtkList *,
14849 <!-- ----------------------------------------------------------------- -->
14850 <sect1>GtkMenuShell
14851 <!-- ----------------------------------------------------------------- -->
14854 void GtkMenuShell::deactivate (GtkMenuShell *,
14856 void GtkMenuShell::selection-done (GtkMenuShell *,
14858 void GtkMenuShell::move-current (GtkMenuShell *,
14859 GtkMenuDirectionType,
14861 void GtkMenuShell::activate-current (GtkMenuShell *,
14864 void GtkMenuShell::cancel (GtkMenuShell *,
14868 <!-- ----------------------------------------------------------------- -->
14870 <!-- ----------------------------------------------------------------- -->
14873 void GtkToolbar::orientation-changed (GtkToolbar *,
14876 void GtkToolbar::style-changed (GtkToolbar *,
14881 <!-- ----------------------------------------------------------------- -->
14883 <!-- ----------------------------------------------------------------- -->
14886 void GtkTree::selection-changed (GtkTree *,
14888 void GtkTree::select-child (GtkTree *,
14891 void GtkTree::unselect-child (GtkTree *,
14896 <!-- ----------------------------------------------------------------- -->
14898 <!-- ----------------------------------------------------------------- -->
14901 void GtkButton::pressed (GtkButton *,
14903 void GtkButton::released (GtkButton *,
14905 void GtkButton::clicked (GtkButton *,
14907 void GtkButton::enter (GtkButton *,
14909 void GtkButton::leave (GtkButton *,
14913 <!-- ----------------------------------------------------------------- -->
14915 <!-- ----------------------------------------------------------------- -->
14918 void GtkItem::select (GtkItem *,
14920 void GtkItem::deselect (GtkItem *,
14922 void GtkItem::toggle (GtkItem *,
14926 <!-- ----------------------------------------------------------------- -->
14928 <!-- ----------------------------------------------------------------- -->
14931 void GtkWindow::set-focus (GtkWindow *,
14936 <!-- ----------------------------------------------------------------- -->
14937 <sect1>GtkHandleBox
14938 <!-- ----------------------------------------------------------------- -->
14941 void GtkHandleBox::child-attached (GtkHandleBox *,
14944 void GtkHandleBox::child-detached (GtkHandleBox *,
14949 <!-- ----------------------------------------------------------------- -->
14950 <sect1>GtkToggleButton
14951 <!-- ----------------------------------------------------------------- -->
14954 void GtkToggleButton::toggled (GtkToggleButton *,
14959 <!-- ----------------------------------------------------------------- -->
14961 <!-- ----------------------------------------------------------------- -->
14964 void GtkMenuItem::activate (GtkMenuItem *,
14966 void GtkMenuItem::activate-item (GtkMenuItem *,
14970 <!-- ----------------------------------------------------------------- -->
14972 <!-- ----------------------------------------------------------------- -->
14975 void GtkListItem::toggle-focus-row (GtkListItem *,
14977 void GtkListItem::select-all (GtkListItem *,
14979 void GtkListItem::unselect-all (GtkListItem *,
14981 void GtkListItem::undo-selection (GtkListItem *,
14983 void GtkListItem::start-selection (GtkListItem *,
14985 void GtkListItem::end-selection (GtkListItem *,
14987 void GtkListItem::toggle-add-mode (GtkListItem *,
14989 void GtkListItem::extend-selection (GtkListItem *,
14994 void GtkListItem::scroll-vertical (GtkListItem *,
14998 void GtkListItem::scroll-horizontal (GtkListItem *,
15004 <!-- ----------------------------------------------------------------- -->
15006 <!-- ----------------------------------------------------------------- -->
15009 void GtkTreeItem::collapse (GtkTreeItem *,
15011 void GtkTreeItem::expand (GtkTreeItem *,
15015 <!-- ----------------------------------------------------------------- -->
15016 <sect1>GtkCheckMenuItem
15017 <!-- ----------------------------------------------------------------- -->
15020 void GtkCheckMenuItem::toggled (GtkCheckMenuItem *,
15024 <!-- ----------------------------------------------------------------- -->
15025 <sect1>GtkInputDialog
15026 <!-- ----------------------------------------------------------------- -->
15029 void GtkInputDialog::enable-device (GtkInputDialog *,
15032 void GtkInputDialog::disable-device (GtkInputDialog *,
15037 <!-- ----------------------------------------------------------------- -->
15038 <sect1>GtkColorSelection
15039 <!-- ----------------------------------------------------------------- -->
15042 void GtkColorSelection::color-changed (GtkColorSelection *,
15046 <!-- ----------------------------------------------------------------- -->
15047 <sect1>GtkStatusBar
15048 <!-- ----------------------------------------------------------------- -->
15051 void GtkStatusbar::text-pushed (GtkStatusbar *,
15055 void GtkStatusbar::text-popped (GtkStatusbar *,
15061 <!-- ----------------------------------------------------------------- -->
15063 <!-- ----------------------------------------------------------------- -->
15066 void GtkCTree::tree-select-row (GtkCTree *,
15070 void GtkCTree::tree-unselect-row (GtkCTree *,
15074 void GtkCTree::tree-expand (GtkCTree *,
15077 void GtkCTree::tree-collapse (GtkCTree *,
15080 void GtkCTree::tree-move (GtkCTree *,
15085 void GtkCTree::change-focus-row-expansion (GtkCTree *,
15086 GtkCTreeExpansionType,
15090 <!-- ----------------------------------------------------------------- -->
15092 <!-- ----------------------------------------------------------------- -->
15095 void GtkCurve::curve-type-changed (GtkCurve *,
15099 <!-- ----------------------------------------------------------------- -->
15100 <sect1>GtkAdjustment
15101 <!-- ----------------------------------------------------------------- -->
15104 void GtkAdjustment::changed (GtkAdjustment *,
15106 void GtkAdjustment::value-changed (GtkAdjustment *,
15110 <!-- ***************************************************************** -->
15111 <sect> GDK Event Types<label id="sec_GDK_Event_Types">
15112 <!-- ***************************************************************** -->
15114 The follwing data types are passed into event handlers by GTK+. For
15115 each data type listed, the signals that use this data type are listed.
15120 <item>drag_end_event
15123 <item> GdkEventType
15128 <item>destroy_event
15131 <item>no_expose_event
15134 <item> GdkEventExpose
15139 <item> GdkEventNoExpose
15141 <item> GdkEventVisibility
15143 <item> GdkEventMotion
15145 <item>motion_notify_event
15148 <item> GdkEventButton
15150 <item>button_press_event
15151 <item>button_release_event
15156 <item>key_press_event
15157 <item>key_release_event
15160 <item> GdkEventCrossing
15162 <item>enter_notify_event
15163 <item>leave_notify_event
15166 <item> GdkEventFocus
15168 <item>focus_in_event
15169 <item>focus_out_event
15172 <item> GdkEventConfigure
15174 <item>configure_event
15177 <item> GdkEventProperty
15179 <item>property_notify_event
15182 <item> GdkEventSelection
15184 <item>selection_clear_event
15185 <item>selection_request_event
15186 <item>selection_notify_event
15189 <item> GdkEventProximity
15191 <item>proximity_in_event
15192 <item>proximity_out_event
15195 <item> GdkEventDragBegin
15197 <item>drag_begin_event
15200 <item> GdkEventDragRequest
15202 <item>drag_request_event
15205 <item> GdkEventDropEnter
15207 <item>drop_enter_event
15210 <item> GdkEventDropLeave
15212 <item>drop_leave_event
15215 <item> GdkEventDropDataAvailable
15217 <item>drop_data_available_event
15220 <item> GdkEventClient
15225 <item> GdkEventOther
15231 The data type <tt/GdkEventType/ is a special data type that is used by
15232 all the other data types as an indicator of the data type being passed
15233 to the signal handler. As you will see below, each of the event data
15234 structures has a member of this type. It is defined as an enumeration
15244 GDK_MOTION_NOTIFY = 3,
15245 GDK_BUTTON_PRESS = 4,
15246 GDK_2BUTTON_PRESS = 5,
15247 GDK_3BUTTON_PRESS = 6,
15248 GDK_BUTTON_RELEASE = 7,
15250 GDK_KEY_RELEASE = 9,
15251 GDK_ENTER_NOTIFY = 10,
15252 GDK_LEAVE_NOTIFY = 11,
15253 GDK_FOCUS_CHANGE = 12,
15254 GDK_CONFIGURE = 13,
15257 GDK_PROPERTY_NOTIFY = 16,
15258 GDK_SELECTION_CLEAR = 17,
15259 GDK_SELECTION_REQUEST = 18,
15260 GDK_SELECTION_NOTIFY = 19,
15261 GDK_PROXIMITY_IN = 20,
15262 GDK_PROXIMITY_OUT = 21,
15263 GDK_DRAG_BEGIN = 22,
15264 GDK_DRAG_REQUEST = 23,
15265 GDK_DROP_ENTER = 24,
15266 GDK_DROP_LEAVE = 25,
15267 GDK_DROP_DATA_AVAIL = 26,
15268 GDK_CLIENT_EVENT = 27,
15269 GDK_VISIBILITY_NOTIFY = 28,
15270 GDK_NO_EXPOSE = 29,
15271 GDK_OTHER_EVENT = 9999 /* Deprecated, use filters instead */
15275 The other event type that is different from the others is
15276 <tt/GdkEvent/ itself. This is a union of all the other
15277 data types, which allows it to be cast to a specific
15278 event data type within a signal handler.
15280 <!-- Just a big list for now, needs expanding upon - TRG -->
15281 So, the event data types are defined as follows:
15284 struct _GdkEventAny
15291 struct _GdkEventExpose
15297 gint count; /* If non-zero, how many more events follow. */
15300 struct _GdkEventNoExpose
15305 /* XXX: does anyone need the X major_code or minor_code fields? */
15308 struct _GdkEventVisibility
15313 GdkVisibilityState state;
15316 struct _GdkEventMotion
15329 GdkInputSource source;
15331 gdouble x_root, y_root;
15334 struct _GdkEventButton
15347 GdkInputSource source;
15349 gdouble x_root, y_root;
15352 struct _GdkEventKey
15364 struct _GdkEventCrossing
15369 GdkWindow *subwindow;
15370 GdkNotifyType detail;
15373 struct _GdkEventFocus
15381 struct _GdkEventConfigure
15391 struct _GdkEventProperty
15401 struct _GdkEventSelection
15413 /* This event type will be used pretty rarely. It only is important
15414 for XInput aware programs that are drawing their own cursor */
15416 struct _GdkEventProximity
15422 GdkInputSource source;
15426 struct _GdkEventDragRequest
15434 guint protocol_version:4;
15436 guint willaccept:1;
15437 guint delete_data:1; /* Do *not* delete if link is sent, only
15444 guint8 isdrop; /* This gdk event can be generated by a couple of
15445 X events - this lets the app know whether the
15446 drop really occurred or we just set the data */
15448 GdkPoint drop_coords;
15453 struct _GdkEventDragBegin
15460 guint protocol_version:4;
15467 struct _GdkEventDropEnter
15475 guint protocol_version:4;
15477 guint extended_typelist:1;
15484 struct _GdkEventDropLeave
15492 guint protocol_version:4;
15499 struct _GdkEventDropDataAvailable
15507 guint protocol_version:4;
15513 gchar *data_type; /* MIME type */
15514 gulong data_numbytes;
15520 struct _GdkEventClient
15525 GdkAtom message_type;
15526 gushort data_format;
15534 struct _GdkEventOther
15543 <!-- ***************************************************************** -->
15544 <sect> Code Examples
15545 <!-- ***************************************************************** -->
15547 Below are the code examples that are used in the above text
15548 which are not included in complete form elsewhere.
15550 <!-- ----------------------------------------------------------------- -->
15552 <!-- ----------------------------------------------------------------- -->
15556 /* example-start tictactoe tictactoe.h */
15558 /* GTK - The GIMP Toolkit
15559 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15561 * This library is free software; you can redistribute it and/or
15562 * modify it under the terms of the GNU Library General Public
15563 * License as published by the Free Software Foundation; either
15564 * version 2 of the License, or (at your option) any later version.
15566 * This library is distributed in the hope that it will be useful,
15567 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15568 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15569 * Library General Public License for more details.
15571 * You should have received a copy of the GNU Library General Public
15572 * License along with this library; if not, write to the
15573 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15574 * Boston, MA 02111-1307, USA.
15576 #ifndef __TICTACTOE_H__
15577 #define __TICTACTOE_H__
15580 #include <gdk/gdk.h>
15581 #include <gtk/gtkvbox.h>
15586 #endif /* __cplusplus */
15588 #define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
15589 #define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
15590 #define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
15593 typedef struct _Tictactoe Tictactoe;
15594 typedef struct _TictactoeClass TictactoeClass;
15600 GtkWidget *buttons[3][3];
15603 struct _TictactoeClass
15605 GtkVBoxClass parent_class;
15607 void (* tictactoe) (Tictactoe *ttt);
15610 guint tictactoe_get_type (void);
15611 GtkWidget* tictactoe_new (void);
15612 void tictactoe_clear (Tictactoe *ttt);
15616 #endif /* __cplusplus */
15618 #endif /* __TICTACTOE_H__ */
15623 <!-- ----------------------------------------------------------------- -->
15627 /* example-start tictactoe tictactoe.c */
15629 /* GTK - The GIMP Toolkit
15630 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15632 * This library is free software; you can redistribute it and/or
15633 * modify it under the terms of the GNU Library General Public
15634 * License as published by the Free Software Foundation; either
15635 * version 2 of the License, or (at your option) any later version.
15637 * This library is distributed in the hope that it will be useful,
15638 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15639 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15640 * Library General Public License for more details.
15642 * You should have received a copy of the GNU Library General Public
15643 * License along with this library; if not, write to the
15644 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15645 * Boston, MA 02111-1307, USA.
15647 #include "gtk/gtksignal.h"
15648 #include "gtk/gtktable.h"
15649 #include "gtk/gtktogglebutton.h"
15650 #include "tictactoe.h"
15657 static void tictactoe_class_init (TictactoeClass *klass);
15658 static void tictactoe_init (Tictactoe *ttt);
15659 static void tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt);
15661 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
15664 tictactoe_get_type ()
15666 static guint ttt_type = 0;
15670 GtkTypeInfo ttt_info =
15673 sizeof (Tictactoe),
15674 sizeof (TictactoeClass),
15675 (GtkClassInitFunc) tictactoe_class_init,
15676 (GtkObjectInitFunc) tictactoe_init,
15677 (GtkArgSetFunc) NULL,
15678 (GtkArgGetFunc) NULL
15681 ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
15688 tictactoe_class_init (TictactoeClass *class)
15690 GtkObjectClass *object_class;
15692 object_class = (GtkObjectClass*) class;
15694 tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
15696 object_class->type,
15697 GTK_SIGNAL_OFFSET (TictactoeClass,
15699 gtk_signal_default_marshaller,
15703 gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
15705 class->tictactoe = NULL;
15709 tictactoe_init (Tictactoe *ttt)
15714 table = gtk_table_new (3, 3, TRUE);
15715 gtk_container_add (GTK_CONTAINER(ttt), table);
15716 gtk_widget_show (table);
15721 ttt->buttons[i][j] = gtk_toggle_button_new ();
15722 gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
15724 gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
15725 GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
15726 gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
15727 gtk_widget_show (ttt->buttons[i][j]);
15734 return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
15738 tictactoe_clear (Tictactoe *ttt)
15745 gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
15746 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
15748 gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
15753 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
15757 static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
15758 { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
15759 { 0, 1, 2 }, { 0, 1, 2 } };
15760 static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
15761 { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
15762 { 0, 1, 2 }, { 2, 1, 0 } };
15764 int success, found;
15766 for (k=0; k<8; k++)
15773 success = success &&
15774 GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
15776 ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
15779 if (success && found)
15781 gtk_signal_emit (GTK_OBJECT (ttt),
15782 tictactoe_signals[TICTACTOE_SIGNAL]);
15791 <!-- ----------------------------------------------------------------- -->
15795 /* example-start tictactoe ttt_test.c */
15797 #include <gtk/gtk.h>
15798 #include "tictactoe.h"
15801 win (GtkWidget *widget, gpointer data)
15803 g_print ("Yay!\n");
15804 tictactoe_clear (TICTACTOE (widget));
15808 main (int argc, char *argv[])
15813 gtk_init (&argc, &argv);
15815 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
15817 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
15819 gtk_signal_connect (GTK_OBJECT (window), "destroy",
15820 GTK_SIGNAL_FUNC (gtk_exit), NULL);
15822 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
15824 ttt = tictactoe_new ();
15826 gtk_container_add (GTK_CONTAINER (window), ttt);
15827 gtk_widget_show (ttt);
15829 gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
15830 GTK_SIGNAL_FUNC (win), NULL);
15832 gtk_widget_show (window);
15842 <!-- ----------------------------------------------------------------- -->
15845 <!-- ----------------------------------------------------------------- -->
15849 /* example-start gtkdial gtkdial.h */
15851 /* GTK - The GIMP Toolkit
15852 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15854 * This library is free software; you can redistribute it and/or
15855 * modify it under the terms of the GNU Library General Public
15856 * License as published by the Free Software Foundation; either
15857 * version 2 of the License, or (at your option) any later version.
15859 * This library is distributed in the hope that it will be useful,
15860 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15861 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15862 * Library General Public License for more details.
15864 * You should have received a copy of the GNU Library General Public
15865 * License along with this library; if not, write to the
15866 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15867 * Boston, MA 02111-1307, USA.
15869 #ifndef __GTK_DIAL_H__
15870 #define __GTK_DIAL_H__
15873 #include <gdk/gdk.h>
15874 #include <gtk/gtkadjustment.h>
15875 #include <gtk/gtkwidget.h>
15880 #endif /* __cplusplus */
15883 #define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
15884 #define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
15885 #define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
15888 typedef struct _GtkDial GtkDial;
15889 typedef struct _GtkDialClass GtkDialClass;
15895 /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
15898 /* Button currently pressed or 0 if none */
15901 /* Dimensions of dial components */
15903 gint pointer_width;
15905 /* ID of update timer, or 0 if none */
15908 /* Current angle */
15911 /* Old values from adjustment stored so we know when something changes */
15916 /* The adjustment object that stores the data for this dial */
15917 GtkAdjustment *adjustment;
15920 struct _GtkDialClass
15922 GtkWidgetClass parent_class;
15926 GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
15927 guint gtk_dial_get_type (void);
15928 GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
15929 void gtk_dial_set_update_policy (GtkDial *dial,
15930 GtkUpdateType policy);
15932 void gtk_dial_set_adjustment (GtkDial *dial,
15933 GtkAdjustment *adjustment);
15936 #endif /* __cplusplus */
15939 #endif /* __GTK_DIAL_H__ */
15943 <!-- ----------------------------------------------------------------- -->
15947 /* example-start gtkdial gtkdial.c */
15949 /* GTK - The GIMP Toolkit
15950 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15952 * This library is free software; you can redistribute it and/or
15953 * modify it under the terms of the GNU Library General Public
15954 * License as published by the Free Software Foundation; either
15955 * version 2 of the License, or (at your option) any later version.
15957 * This library is distributed in the hope that it will be useful,
15958 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15959 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15960 * Library General Public License for more details.
15962 * You should have received a copy of the GNU Library General Public
15963 * License along with this library; if not, write to the
15964 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15965 * Boston, MA 02111-1307, USA.
15969 #include <gtk/gtkmain.h>
15970 #include <gtk/gtksignal.h>
15972 #include "gtkdial.h"
15974 #define SCROLL_DELAY_LENGTH 300
15975 #define DIAL_DEFAULT_SIZE 100
15977 /* Forward declarations */
15979 static void gtk_dial_class_init (GtkDialClass *klass);
15980 static void gtk_dial_init (GtkDial *dial);
15981 static void gtk_dial_destroy (GtkObject *object);
15982 static void gtk_dial_realize (GtkWidget *widget);
15983 static void gtk_dial_size_request (GtkWidget *widget,
15984 GtkRequisition *requisition);
15985 static void gtk_dial_size_allocate (GtkWidget *widget,
15986 GtkAllocation *allocation);
15987 static gint gtk_dial_expose (GtkWidget *widget,
15988 GdkEventExpose *event);
15989 static gint gtk_dial_button_press (GtkWidget *widget,
15990 GdkEventButton *event);
15991 static gint gtk_dial_button_release (GtkWidget *widget,
15992 GdkEventButton *event);
15993 static gint gtk_dial_motion_notify (GtkWidget *widget,
15994 GdkEventMotion *event);
15995 static gint gtk_dial_timer (GtkDial *dial);
15997 static void gtk_dial_update_mouse (GtkDial *dial, gint x, gint y);
15998 static void gtk_dial_update (GtkDial *dial);
15999 static void gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
16001 static void gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
16006 static GtkWidgetClass *parent_class = NULL;
16009 gtk_dial_get_type ()
16011 static guint dial_type = 0;
16015 GtkTypeInfo dial_info =
16019 sizeof (GtkDialClass),
16020 (GtkClassInitFunc) gtk_dial_class_init,
16021 (GtkObjectInitFunc) gtk_dial_init,
16022 (GtkArgSetFunc) NULL,
16023 (GtkArgGetFunc) NULL,
16026 dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info);
16033 gtk_dial_class_init (GtkDialClass *class)
16035 GtkObjectClass *object_class;
16036 GtkWidgetClass *widget_class;
16038 object_class = (GtkObjectClass*) class;
16039 widget_class = (GtkWidgetClass*) class;
16041 parent_class = gtk_type_class (gtk_widget_get_type ());
16043 object_class->destroy = gtk_dial_destroy;
16045 widget_class->realize = gtk_dial_realize;
16046 widget_class->expose_event = gtk_dial_expose;
16047 widget_class->size_request = gtk_dial_size_request;
16048 widget_class->size_allocate = gtk_dial_size_allocate;
16049 widget_class->button_press_event = gtk_dial_button_press;
16050 widget_class->button_release_event = gtk_dial_button_release;
16051 widget_class->motion_notify_event = gtk_dial_motion_notify;
16055 gtk_dial_init (GtkDial *dial)
16058 dial->policy = GTK_UPDATE_CONTINUOUS;
16061 dial->pointer_width = 0;
16063 dial->old_value = 0.0;
16064 dial->old_lower = 0.0;
16065 dial->old_upper = 0.0;
16066 dial->adjustment = NULL;
16070 gtk_dial_new (GtkAdjustment *adjustment)
16074 dial = gtk_type_new (gtk_dial_get_type ());
16077 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0,
16080 gtk_dial_set_adjustment (dial, adjustment);
16082 return GTK_WIDGET (dial);
16086 gtk_dial_destroy (GtkObject *object)
16090 g_return_if_fail (object != NULL);
16091 g_return_if_fail (GTK_IS_DIAL (object));
16093 dial = GTK_DIAL (object);
16095 if (dial->adjustment)
16096 gtk_object_unref (GTK_OBJECT (dial->adjustment));
16098 if (GTK_OBJECT_CLASS (parent_class)->destroy)
16099 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
16103 gtk_dial_get_adjustment (GtkDial *dial)
16105 g_return_val_if_fail (dial != NULL, NULL);
16106 g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
16108 return dial->adjustment;
16112 gtk_dial_set_update_policy (GtkDial *dial,
16113 GtkUpdateType policy)
16115 g_return_if_fail (dial != NULL);
16116 g_return_if_fail (GTK_IS_DIAL (dial));
16118 dial->policy = policy;
16122 gtk_dial_set_adjustment (GtkDial *dial,
16123 GtkAdjustment *adjustment)
16125 g_return_if_fail (dial != NULL);
16126 g_return_if_fail (GTK_IS_DIAL (dial));
16128 if (dial->adjustment)
16130 gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment),
16132 gtk_object_unref (GTK_OBJECT (dial->adjustment));
16135 dial->adjustment = adjustment;
16136 gtk_object_ref (GTK_OBJECT (dial->adjustment));
16138 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
16139 (GtkSignalFunc) gtk_dial_adjustment_changed,
16141 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
16142 (GtkSignalFunc) gtk_dial_adjustment_value_changed,
16145 dial->old_value = adjustment->value;
16146 dial->old_lower = adjustment->lower;
16147 dial->old_upper = adjustment->upper;
16149 gtk_dial_update (dial);
16153 gtk_dial_realize (GtkWidget *widget)
16156 GdkWindowAttr attributes;
16157 gint attributes_mask;
16159 g_return_if_fail (widget != NULL);
16160 g_return_if_fail (GTK_IS_DIAL (widget));
16162 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
16163 dial = GTK_DIAL (widget);
16165 attributes.x = widget->allocation.x;
16166 attributes.y = widget->allocation.y;
16167 attributes.width = widget->allocation.width;
16168 attributes.height = widget->allocation.height;
16169 attributes.wclass = GDK_INPUT_OUTPUT;
16170 attributes.window_type = GDK_WINDOW_CHILD;
16171 attributes.event_mask = gtk_widget_get_events (widget) |
16172 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
16173 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
16174 GDK_POINTER_MOTION_HINT_MASK;
16175 attributes.visual = gtk_widget_get_visual (widget);
16176 attributes.colormap = gtk_widget_get_colormap (widget);
16178 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
16179 widget->window = gdk_window_new (widget->parent->window,
16183 widget->style = gtk_style_attach (widget->style, widget->window);
16185 gdk_window_set_user_data (widget->window, widget);
16187 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
16191 gtk_dial_size_request (GtkWidget *widget,
16192 GtkRequisition *requisition)
16194 requisition->width = DIAL_DEFAULT_SIZE;
16195 requisition->height = DIAL_DEFAULT_SIZE;
16199 gtk_dial_size_allocate (GtkWidget *widget,
16200 GtkAllocation *allocation)
16204 g_return_if_fail (widget != NULL);
16205 g_return_if_fail (GTK_IS_DIAL (widget));
16206 g_return_if_fail (allocation != NULL);
16208 widget->allocation = *allocation;
16209 dial = GTK_DIAL (widget);
16211 if (GTK_WIDGET_REALIZED (widget))
16214 gdk_window_move_resize (widget->window,
16215 allocation->x, allocation->y,
16216 allocation->width, allocation->height);
16219 dial->radius = MIN(allocation->width,allocation->height) * 0.45;
16220 dial->pointer_width = dial->radius / 5;
16224 gtk_dial_expose (GtkWidget *widget,
16225 GdkEventExpose *event)
16228 GdkPoint points[3];
16235 g_return_val_if_fail (widget != NULL, FALSE);
16236 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16237 g_return_val_if_fail (event != NULL, FALSE);
16239 if (event->count > 0)
16242 dial = GTK_DIAL (widget);
16244 gdk_window_clear_area (widget->window,
16246 widget->allocation.width,
16247 widget->allocation.height);
16249 xc = widget->allocation.width/2;
16250 yc = widget->allocation.height/2;
16254 for (i=0; i<25; i++)
16256 theta = (i*M_PI/18. - M_PI/6.);
16260 tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
16262 gdk_draw_line (widget->window,
16263 widget->style->fg_gc[widget->state],
16264 xc + c*(dial->radius - tick_length),
16265 yc - s*(dial->radius - tick_length),
16266 xc + c*dial->radius,
16267 yc - s*dial->radius);
16272 s = sin(dial->angle);
16273 c = cos(dial->angle);
16276 points[0].x = xc + s*dial->pointer_width/2;
16277 points[0].y = yc + c*dial->pointer_width/2;
16278 points[1].x = xc + c*dial->radius;
16279 points[1].y = yc - s*dial->radius;
16280 points[2].x = xc - s*dial->pointer_width/2;
16281 points[2].y = yc - c*dial->pointer_width/2;
16283 gtk_draw_polygon (widget->style,
16294 gtk_dial_button_press (GtkWidget *widget,
16295 GdkEventButton *event)
16301 double d_perpendicular;
16303 g_return_val_if_fail (widget != NULL, FALSE);
16304 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16305 g_return_val_if_fail (event != NULL, FALSE);
16307 dial = GTK_DIAL (widget);
16309 /* Determine if button press was within pointer region - we
16310 do this by computing the parallel and perpendicular distance of
16311 the point where the mouse was pressed from the line passing through
16314 dx = event->x - widget->allocation.width / 2;
16315 dy = widget->allocation.height / 2 - event->y;
16317 s = sin(dial->angle);
16318 c = cos(dial->angle);
16320 d_parallel = s*dy + c*dx;
16321 d_perpendicular = fabs(s*dx - c*dy);
16323 if (!dial->button &&
16324 (d_perpendicular < dial->pointer_width/2) &&
16325 (d_parallel > - dial->pointer_width))
16327 gtk_grab_add (widget);
16329 dial->button = event->button;
16331 gtk_dial_update_mouse (dial, event->x, event->y);
16338 gtk_dial_button_release (GtkWidget *widget,
16339 GdkEventButton *event)
16343 g_return_val_if_fail (widget != NULL, FALSE);
16344 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16345 g_return_val_if_fail (event != NULL, FALSE);
16347 dial = GTK_DIAL (widget);
16349 if (dial->button == event->button)
16351 gtk_grab_remove (widget);
16355 if (dial->policy == GTK_UPDATE_DELAYED)
16356 gtk_timeout_remove (dial->timer);
16358 if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
16359 (dial->old_value != dial->adjustment->value))
16360 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment),
16368 gtk_dial_motion_notify (GtkWidget *widget,
16369 GdkEventMotion *event)
16372 GdkModifierType mods;
16375 g_return_val_if_fail (widget != NULL, FALSE);
16376 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16377 g_return_val_if_fail (event != NULL, FALSE);
16379 dial = GTK_DIAL (widget);
16381 if (dial->button != 0)
16386 if (event->is_hint || (event->window != widget->window))
16387 gdk_window_get_pointer (widget->window, &x, &y, &mods);
16389 switch (dial->button)
16392 mask = GDK_BUTTON1_MASK;
16395 mask = GDK_BUTTON2_MASK;
16398 mask = GDK_BUTTON3_MASK;
16405 if (mods & mask)
16406 gtk_dial_update_mouse (dial, x,y);
16413 gtk_dial_timer (GtkDial *dial)
16415 g_return_val_if_fail (dial != NULL, FALSE);
16416 g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
16418 if (dial->policy == GTK_UPDATE_DELAYED)
16419 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment),
16426 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
16431 g_return_if_fail (dial != NULL);
16432 g_return_if_fail (GTK_IS_DIAL (dial));
16434 xc = GTK_WIDGET(dial)->allocation.width / 2;
16435 yc = GTK_WIDGET(dial)->allocation.height / 2;
16437 old_value = dial->adjustment->value;
16438 dial->angle = atan2(yc-y, x-xc);
16440 if (dial->angle < -M_PI/2.)
16441 dial->angle += 2*M_PI;
16443 if (dial->angle < -M_PI/6)
16444 dial->angle = -M_PI/6;
16446 if (dial->angle > 7.*M_PI/6.)
16447 dial->angle = 7.*M_PI/6.;
16449 dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
16450 (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
16452 if (dial->adjustment->value != old_value)
16454 if (dial->policy == GTK_UPDATE_CONTINUOUS)
16456 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment),
16461 gtk_widget_draw (GTK_WIDGET(dial), NULL);
16463 if (dial->policy == GTK_UPDATE_DELAYED)
16466 gtk_timeout_remove (dial->timer);
16468 dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
16469 (GtkFunction) gtk_dial_timer,
16477 gtk_dial_update (GtkDial *dial)
16481 g_return_if_fail (dial != NULL);
16482 g_return_if_fail (GTK_IS_DIAL (dial));
16484 new_value = dial->adjustment->value;
16486 if (new_value < dial->adjustment->lower)
16487 new_value = dial->adjustment->lower;
16489 if (new_value > dial->adjustment->upper)
16490 new_value = dial->adjustment->upper;
16492 if (new_value != dial->adjustment->value)
16494 dial->adjustment->value = new_value;
16495 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
16498 dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) *
16500 (dial->adjustment->upper - dial->adjustment->lower);
16502 gtk_widget_draw (GTK_WIDGET(dial), NULL);
16506 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
16511 g_return_if_fail (adjustment != NULL);
16512 g_return_if_fail (data != NULL);
16514 dial = GTK_DIAL (data);
16516 if ((dial->old_value != adjustment->value) ||
16517 (dial->old_lower != adjustment->lower) ||
16518 (dial->old_upper != adjustment->upper))
16520 gtk_dial_update (dial);
16522 dial->old_value = adjustment->value;
16523 dial->old_lower = adjustment->lower;
16524 dial->old_upper = adjustment->upper;
16529 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
16534 g_return_if_fail (adjustment != NULL);
16535 g_return_if_fail (data != NULL);
16537 dial = GTK_DIAL (data);
16539 if (dial->old_value != adjustment->value)
16541 gtk_dial_update (dial);
16543 dial->old_value = adjustment->value;
16549 <!-- ----------------------------------------------------------------- -->
16553 /* example-start scribble-simple scribble-simple.c */
16555 /* GTK - The GIMP Toolkit
16556 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
16558 * This library is free software; you can redistribute it and/or
16559 * modify it under the terms of the GNU Library General Public
16560 * License as published by the Free Software Foundation; either
16561 * version 2 of the License, or (at your option) any later version.
16563 * This library is distributed in the hope that it will be useful,
16564 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16565 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16566 * Library General Public License for more details.
16568 * You should have received a copy of the GNU Library General Public
16569 * License along with this library; if not, write to the
16570 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16571 * Boston, MA 02111-1307, USA.
16574 #include <gtk/gtk.h>
16576 /* Backing pixmap for drawing area */
16577 static GdkPixmap *pixmap = NULL;
16579 /* Create a new backing pixmap of the appropriate size */
16581 configure_event (GtkWidget *widget, GdkEventConfigure *event)
16584 gdk_pixmap_unref(pixmap);
16586 pixmap = gdk_pixmap_new(widget->window,
16587 widget->allocation.width,
16588 widget->allocation.height,
16590 gdk_draw_rectangle (pixmap,
16591 widget->style->white_gc,
16594 widget->allocation.width,
16595 widget->allocation.height);
16600 /* Redraw the screen from the backing pixmap */
16602 expose_event (GtkWidget *widget, GdkEventExpose *event)
16604 gdk_draw_pixmap(widget->window,
16605 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
16607 event->area.x, event->area.y,
16608 event->area.x, event->area.y,
16609 event->area.width, event->area.height);
16614 /* Draw a rectangle on the screen */
16616 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
16618 GdkRectangle update_rect;
16620 update_rect.x = x - 5;
16621 update_rect.y = y - 5;
16622 update_rect.width = 10;
16623 update_rect.height = 10;
16624 gdk_draw_rectangle (pixmap,
16625 widget->style->black_gc,
16627 update_rect.x, update_rect.y,
16628 update_rect.width, update_rect.height);
16629 gtk_widget_draw (widget, &update_rect);
16633 button_press_event (GtkWidget *widget, GdkEventButton *event)
16635 if (event->button == 1 && pixmap != NULL)
16636 draw_brush (widget, event->x, event->y);
16642 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
16645 GdkModifierType state;
16647 if (event->is_hint)
16648 gdk_window_get_pointer (event->window, &x, &y, &state);
16653 state = event->state;
16656 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
16657 draw_brush (widget, x, y);
16669 main (int argc, char *argv[])
16672 GtkWidget *drawing_area;
16677 gtk_init (&argc, &argv);
16679 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
16680 gtk_widget_set_name (window, "Test Input");
16682 vbox = gtk_vbox_new (FALSE, 0);
16683 gtk_container_add (GTK_CONTAINER (window), vbox);
16684 gtk_widget_show (vbox);
16686 gtk_signal_connect (GTK_OBJECT (window), "destroy",
16687 GTK_SIGNAL_FUNC (quit), NULL);
16689 /* Create the drawing area */
16691 drawing_area = gtk_drawing_area_new ();
16692 gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200);
16693 gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
16695 gtk_widget_show (drawing_area);
16697 /* Signals used to handle backing pixmap */
16699 gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
16700 (GtkSignalFunc) expose_event, NULL);
16701 gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
16702 (GtkSignalFunc) configure_event, NULL);
16704 /* Event signals */
16706 gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
16707 (GtkSignalFunc) motion_notify_event, NULL);
16708 gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
16709 (GtkSignalFunc) button_press_event, NULL);
16711 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
16712 | GDK_LEAVE_NOTIFY_MASK
16713 | GDK_BUTTON_PRESS_MASK
16714 | GDK_POINTER_MOTION_MASK
16715 | GDK_POINTER_MOTION_HINT_MASK);
16717 /* .. And a quit button */
16718 button = gtk_button_new_with_label ("Quit");
16719 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
16721 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
16722 GTK_SIGNAL_FUNC (gtk_widget_destroy),
16723 GTK_OBJECT (window));
16724 gtk_widget_show (button);
16726 gtk_widget_show (window);
16735 <!-- ***************************************************************** -->
16737 <!-- ***************************************************************** -->
16739 NOTE: The GtkList widget has been superseded by the GtkCList
16740 widget. It is detailed here just for completeness.
16742 The GtkList widget is designed to act as a vertical container for
16743 widgets that should be of the type GtkListItem.
16745 A GtkList widget has its own window to receive events and its own
16746 background color which is usually white. As it is directly derived
16747 from a GtkContainer it can be treated as such by using the
16748 GTK_CONTAINER(List) macro, see the GtkContainer widget for more on
16749 this. One should already be familiar with the usage of a GList and
16750 its related functions g_list_*() to be able to use the GtkList widget
16753 There is one field inside the structure definition of the GtkList
16754 widget that will be of greater interest to us, this is:
16761 guint selection_mode;
16766 The selection field of a GtkList points to a linked list of all items
16767 that are currently selected, or NULL if the selection is empty. So to
16768 learn about the current selection we read the GTK_LIST()->selection
16769 field, but do not modify it since the internal fields are maintained
16770 by the gtk_list_*() functions.
16772 The selection_mode of the GtkList determines the selection facilities
16773 of a GtkList and therefore the contents of the GTK_LIST()->selection
16774 field. The selection_mode may be one of the following:
16777 <item> GTK_SELECTION_SINGLE - The selection is either NULL
16778 or contains a GList pointer
16779 for a single selected item.
16781 <item> GTK_SELECTION_BROWSE - The selection is NULL if the list
16782 contains no widgets or insensitive
16783 ones only, otherwise it contains
16784 a GList pointer for one GList
16785 structure, and therefore exactly
16788 <item> GTK_SELECTION_MULTIPLE - The selection is NULL if no list
16789 items are selected or a GList pointer
16790 for the first selected item. That
16791 in turn points to a GList structure
16792 for the second selected item and so
16795 <item> GTK_SELECTION_EXTENDED - The selection is always NULL.
16798 The default is GTK_SELECTION_MULTIPLE.
16800 <!-- ----------------------------------------------------------------- -->
16804 void selection_changed( GtkList *list );
16807 This signal will be invoked whenever the selection field of a GtkList
16808 has changed. This happens when a child of the GtkList got selected or
16812 void select_child( GtkList *list,
16816 This signal is invoked when a child of the GtkList is about to get
16817 selected. This happens mainly on calls to gtk_list_select_item(),
16818 gtk_list_select_child(), button presses and sometimes indirectly
16819 triggered on some else occasions where children get added to or
16820 removed from the GtkList.
16823 void unselect_child( GtkList *list,
16824 GtkWidget *child );
16827 This signal is invoked when a child of the GtkList is about to get
16828 deselected. This happens mainly on calls to gtk_list_unselect_item(),
16829 gtk_list_unselect_child(), button presses and sometimes indirectly
16830 triggered on some else occasions where children get added to or
16831 removed from the GtkList.
16833 <!-- ----------------------------------------------------------------- -->
16837 guint gtk_list_get_type( void );
16840 Returns the `GtkList' type identifier.
16843 GtkWidget *gtk_list_new( void );
16846 Create a new GtkList object. The new widget is returned as a pointer
16847 to a GtkWidget object. NULL is returned on failure.
16850 void gtk_list_insert_items( GtkList *list,
16855 Insert list items into the list, starting at <tt/position/.
16856 <tt/items/ is a doubly linked list where each nodes data pointer is
16857 expected to point to a newly created GtkListItem. The GList nodes of
16858 <tt/items/ are taken over by the list.
16861 void gtk_list_append_items( GtkList *list,
16865 Insert list items just like gtk_list_insert_items() at the end of the
16866 list. The GList nodes of <tt/items/ are taken over by the list.
16869 void gtk_list_prepend_items( GtkList *list,
16873 Insert list items just like gtk_list_insert_items() at the very
16874 beginning of the list. The GList nodes of <tt/items/ are taken over by
16878 void gtk_list_remove_items( GtkList *list,
16882 Remove list items from the list. <tt/items/ is a doubly linked list
16883 where each nodes data pointer is expected to point to a direct child
16884 of list. It is the callers responsibility to make a call to
16885 g_list_free(items) afterwards. Also the caller has to destroy the list
16889 void gtk_list_clear_items( GtkList *list,
16894 Remove and destroy list items from the list. A widget is affected if
16895 its current position within the list is in the range specified by
16896 <tt/start/ and <tt/end/.
16899 void gtk_list_select_item( GtkList *list,
16903 Invoke the select_child signal for a list item specified through its
16904 current position within the list.
16907 void gtk_list_unselect_item( GtkList *list,
16911 Invoke the unselect_child signal for a list item specified through its
16912 current position within the list.
16915 void gtk_list_select_child( GtkList *list,
16919 Invoke the select_child signal for the specified child.
16922 void gtk_list_unselect_child( GtkList *list,
16926 Invoke the unselect_child signal for the specified child.
16929 gint gtk_list_child_position( GtkList *list,
16933 Return the position of <tt/child/ within the list. "-1" is returned on
16937 void gtk_list_set_selection_mode( GtkList *list,
16938 GtkSelectionMode mode );
16941 Set the selection mode MODE which can be of GTK_SELECTION_SINGLE,
16942 GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE or
16943 GTK_SELECTION_EXTENDED.
16946 GtkList *GTK_LIST( gpointer obj );
16949 Cast a generic pointer to `GtkList *'. *Note Standard Macros::, for
16953 GtkListClass *GTK_LIST_CLASS( gpointer class);
16956 Cast a generic pointer to `GtkListClass*'. *Note Standard Macros::,
16960 gint GTK_IS_LIST( gpointer obj);
16963 Determine if a generic pointer refers to a `GtkList' object. *Note
16964 Standard Macros::, for more info.
16966 <!-- ----------------------------------------------------------------- -->
16969 Following is an example program that will print out the changes of the
16970 selection of a GtkList, and lets you "arrest" list items into a prison
16971 by selecting them with the rightmost mouse button.
16974 /* example-start list list.c */
16976 /* Include the gtk+ header files
16977 * Include stdio.h, we need that for the printf() function
16979 #include <gtk/gtk.h>
16982 /* This is our data identification string to store
16983 * data in list items
16985 const gchar *list_item_data_key="list_item_data";
16988 /* prototypes for signal handler that we are going to connect
16989 * to the GtkList widget
16991 static void sigh_print_selection( GtkWidget *gtklist,
16992 gpointer func_data);
16994 static void sigh_button_event( GtkWidget *gtklist,
16995 GdkEventButton *event,
16996 GtkWidget *frame );
16999 /* Main function to set up the user interface */
17001 gint main (int argc,
17004 GtkWidget *separator;
17007 GtkWidget *scrolled_window;
17009 GtkWidget *gtklist;
17011 GtkWidget *list_item;
17017 /* Initialize gtk+ (and subsequently gdk) */
17019 gtk_init(&argc, &argv);
17022 /* Create a window to put all the widgets in
17023 * connect gtk_main_quit() to the "destroy" event of
17024 * the window to handle window manager close-window-events
17026 window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
17027 gtk_window_set_title(GTK_WINDOW(window), "GtkList Example");
17028 gtk_signal_connect(GTK_OBJECT(window),
17030 GTK_SIGNAL_FUNC(gtk_main_quit),
17034 /* Inside the window we need a box to arrange the widgets
17036 vbox=gtk_vbox_new(FALSE, 5);
17037 gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
17038 gtk_container_add(GTK_CONTAINER(window), vbox);
17039 gtk_widget_show(vbox);
17041 /* This is the scrolled window to put the GtkList widget inside */
17042 scrolled_window=gtk_scrolled_window_new(NULL, NULL);
17043 gtk_widget_set_usize(scrolled_window, 250, 150);
17044 gtk_container_add(GTK_CONTAINER(vbox), scrolled_window);
17045 gtk_widget_show(scrolled_window);
17047 /* Create the GtkList widget.
17048 * Connect the sigh_print_selection() signal handler
17049 * function to the "selection_changed" signal of the GtkList
17050 * to print out the selected items each time the selection
17052 gtklist=gtk_list_new();
17053 gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(scrolled_window),
17055 gtk_widget_show(gtklist);
17056 gtk_signal_connect(GTK_OBJECT(gtklist),
17057 "selection_changed",
17058 GTK_SIGNAL_FUNC(sigh_print_selection),
17061 /* We create a "Prison" to put a list item in ;) */
17062 frame=gtk_frame_new("Prison");
17063 gtk_widget_set_usize(frame, 200, 50);
17064 gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
17065 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
17066 gtk_container_add(GTK_CONTAINER(vbox), frame);
17067 gtk_widget_show(frame);
17069 /* Connect the sigh_button_event() signal handler to the GtkList
17070 * which will handle the "arresting" of list items
17072 gtk_signal_connect(GTK_OBJECT(gtklist),
17073 "button_release_event",
17074 GTK_SIGNAL_FUNC(sigh_button_event),
17077 /* Create a separator */
17078 separator=gtk_hseparator_new();
17079 gtk_container_add(GTK_CONTAINER(vbox), separator);
17080 gtk_widget_show(separator);
17082 /* Finally create a button and connect its "clicked" signal
17083 * to the destruction of the window */
17084 button=gtk_button_new_with_label("Close");
17085 gtk_container_add(GTK_CONTAINER(vbox), button);
17086 gtk_widget_show(button);
17087 gtk_signal_connect_object(GTK_OBJECT(button),
17089 GTK_SIGNAL_FUNC(gtk_widget_destroy),
17090 GTK_OBJECT(window));
17093 /* Now we create 5 list items, each having its own
17094 * label and add them to the GtkList using gtk_container_add()
17095 * Also we query the text string from the label and
17096 * associate it with the list_item_data_key for each list item
17098 for (i=0; i<5; i++) {
17102 sprintf(buffer, "ListItemContainer with Label #%d", i);
17103 label=gtk_label_new(buffer);
17104 list_item=gtk_list_item_new();
17105 gtk_container_add(GTK_CONTAINER(list_item), label);
17106 gtk_widget_show(label);
17107 gtk_container_add(GTK_CONTAINER(gtklist), list_item);
17108 gtk_widget_show(list_item);
17109 gtk_label_get(GTK_LABEL(label), &string);
17110 gtk_object_set_data(GTK_OBJECT(list_item),
17111 list_item_data_key,
17114 /* Here, we are creating another 5 labels, this time
17115 * we use gtk_list_item_new_with_label() for the creation
17116 * we can't query the text string from the label because
17117 * we don't have the labels pointer and therefore
17118 * we just associate the list_item_data_key of each
17119 * list item with the same text string.
17120 * For adding of the list items we put them all into a doubly
17121 * linked list (GList), and then add them by a single call to
17122 * gtk_list_append_items().
17123 * Because we use g_list_prepend() to put the items into the
17124 * doubly linked list, their order will be descending (instead
17125 * of ascending when using g_list_append())
17128 for (; i<10; i++) {
17129 sprintf(buffer, "List Item with Label %d", i);
17130 list_item=gtk_list_item_new_with_label(buffer);
17131 dlist=g_list_prepend(dlist, list_item);
17132 gtk_widget_show(list_item);
17133 gtk_object_set_data(GTK_OBJECT(list_item),
17134 list_item_data_key,
17135 "ListItem with integrated Label");
17137 gtk_list_append_items(GTK_LIST(gtklist), dlist);
17139 /* Finally we want to see the window, don't we? ;) */
17140 gtk_widget_show(window);
17142 /* Fire up the main event loop of gtk */
17145 /* We get here after gtk_main_quit() has been called which
17146 * happens if the main window gets destroyed
17151 /* This is the signal handler that got connected to button
17152 * press/release events of the GtkList
17154 void sigh_button_event( GtkWidget *gtklist,
17155 GdkEventButton *event,
17158 /* We only do something if the third (rightmost mouse button
17161 if (event->type==GDK_BUTTON_RELEASE &&
17162 event->button==3) {
17163 GList *dlist, *free_list;
17164 GtkWidget *new_prisoner;
17166 /* Fetch the currently selected list item which
17167 * will be our next prisoner ;)
17169 dlist=GTK_LIST(gtklist)->selection;
17171 new_prisoner=GTK_WIDGET(dlist->data);
17175 /* Look for already imprisoned list items, we
17176 * will put them back into the list.
17177 * Remember to free the doubly linked list that
17178 * gtk_container_children() returns
17180 dlist=gtk_container_children(GTK_CONTAINER(frame));
17183 GtkWidget *list_item;
17185 list_item=dlist->data;
17187 gtk_widget_reparent(list_item, gtklist);
17191 g_list_free(free_list);
17193 /* If we have a new prisoner, remove him from the
17194 * GtkList and put him into the frame "Prison".
17195 * We need to unselect the item first.
17197 if (new_prisoner) {
17198 GList static_dlist;
17200 static_dlist.data=new_prisoner;
17201 static_dlist.next=NULL;
17202 static_dlist.prev=NULL;
17204 gtk_list_unselect_child(GTK_LIST(gtklist),
17206 gtk_widget_reparent(new_prisoner, frame);
17211 /* This is the signal handler that gets called if GtkList
17212 * emits the "selection_changed" signal
17214 void sigh_print_selection( GtkWidget *gtklist,
17215 gpointer func_data)
17219 /* Fetch the doubly linked list of selected items
17220 * of the GtkList, remember to treat this as read-only!
17222 dlist=GTK_LIST(gtklist)->selection;
17224 /* If there are no selected items there is nothing more
17225 * to do than just telling the user so
17228 g_print("Selection cleared\n");
17231 /* Ok, we got a selection and so we print it
17233 g_print("The selection is a ");
17235 /* Get the list item from the doubly linked list
17236 * and then query the data associated with list_item_data_key.
17237 * We then just print it */
17239 GtkObject *list_item;
17240 gchar *item_data_string;
17242 list_item=GTK_OBJECT(dlist->data);
17243 item_data_string=gtk_object_get_data(list_item,
17244 list_item_data_key);
17245 g_print("%s ", item_data_string);
17254 <!-- ----------------------------------------------------------------- -->
17255 <sect1> List Item Widget
17257 The GtkListItem widget is designed to act as a container holding up to
17258 one child, providing functions for selection/deselection just like the
17259 GtkList widget requires them for its children.
17261 A GtkListItem has its own window to receive events and has its own
17262 background color which is usually white.
17264 As it is directly derived from a GtkItem it can be treated as such by
17265 using the GTK_ITEM(ListItem) macro, see the GtkItem widget for more on
17266 this. Usually a GtkListItem just holds a label to identify e.g. a
17267 filename within a GtkList -- therefore the convenience function
17268 gtk_list_item_new_with_label() is provided. The same effect can be
17269 achieved by creating a GtkLabel on its own, setting its alignment to
17270 xalign=0 and yalign=0.5 with a subsequent container addition to the
17273 As one is not forced to add a GtkLabel to a GtkListItem, you could
17274 also add a GtkVBox or a GtkArrow etc. to the GtkListItem.
17276 <!-- ----------------------------------------------------------------- -->
17279 A GtkListItem does not create new signals on its own, but inherits
17280 the signals of a GtkItem. *Note GtkItem::, for more info.
17282 <!-- ----------------------------------------------------------------- -->
17286 guint gtk_list_item_get_type( void );
17289 Returns the `GtkListItem' type identifier.
17292 GtkWidget *gtk_list_item_new( void );
17295 Create a new GtkListItem object. The new widget is returned as a
17296 pointer to a GtkWidget object. NULL is returned on failure.
17299 GtkWidget *gtk_list_item_new_with_label( gchar *label );
17302 Create a new GtkListItem object, having a single GtkLabel as the sole
17303 child. The new widget is returned as a pointer to a GtkWidget
17304 object. NULL is returned on failure.
17307 void gtk_list_item_select( GtkListItem *list_item );
17310 This function is basically a wrapper around a call to gtk_item_select
17311 (GTK_ITEM (list_item)) which will emit the select signal. *Note
17312 GtkItem::, for more info.
17315 void gtk_list_item_deselect( GtkListItem *list_item );
17318 This function is basically a wrapper around a call to
17319 gtk_item_deselect (GTK_ITEM (list_item)) which will emit the deselect
17320 signal. *Note GtkItem::, for more info.
17323 GtkListItem *GTK_LIST_ITEM( gpointer obj );
17326 Cast a generic pointer to `GtkListItem*'. *Note Standard Macros::, for
17330 GtkListItemClass *GTK_LIST_ITEM_CLASS( gpointer class );
17333 Cast a generic pointer to GtkListItemClass*. *Note Standard Macros::,
17337 gint GTK_IS_LIST_ITEM( gpointer obj );
17340 Determine if a generic pointer refers to a `GtkListItem' object.
17341 *Note Standard Macros::, for more info.
17343 <!-- ----------------------------------------------------------------- -->
17346 Please see the GtkList example on this, which covers the usage of a
17347 GtkListItem as well.