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 23rd, 2000
16 This is a tutorial on how to use GTK (the GTK+ 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 (GTK+ 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 GNU 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 (GTK+ Drawing Kit) which is basically a wrapper around the
40 low-level functions for accessing the underlying windowing functions
41 (Xlib in the case of the X windows system). The primary authors of GTK
45 <item> Peter Mattis <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
46 name="petm@xcf.berkeley.edu"></tt>
47 <item> Spencer Kimball <tt><htmlurl url="mailto:spencer@xcf.berkeley.edu"
48 name="spencer@xcf.berkeley.edu"></tt>
49 <item> Josh MacDonald <tt><htmlurl url="mailto:jmacd@xcf.berkeley.edu"
50 name="jmacd@xcf.berkeley.edu"></tt>
53 GTK is essentially an object oriented application programmers
54 interface (API). Although written completely in C, it is implemented
55 using the idea of classes and callback functions (pointers to
58 There is also a third component called GLib which contains a few
59 replacements for some standard calls, as well as some additional
60 functions for handling linked lists, etc. The replacement functions
61 are used to increase GTK's portability, as some of the functions
62 implemented here are not available or are nonstandard on other unixes
63 such as g_strerror(). Some also contain enhancements to the libc
64 versions, such as g_malloc that has enhanced debugging utilities.
66 This tutorial describes the C interface to GTK. There are GTK
67 bindings for many other languages including C++, Guile, Perl, Python,
68 TOM, Ada95, Objective C, Free Pascal, and Eiffel. If you intend to
69 use another language's bindings to GTK, look at that binding's
70 documentation first. In some cases that documentation may describe
71 some important conventions (which you should know first) and then
72 refer you back to this tutorial. There are also some cross-platform
73 APIs (such as wxWindows and V) which use GTK as one of their target
74 platforms; again, consult their documentation first.
76 If you're developing your GTK application in C++, a few extra notes
77 are in order. There's a C++ binding to GTK called GTK--, which
78 provides a more C++-like interface to GTK; you should probably look
79 into this instead. If you don't like that approach for whatever
80 reason, there are two alternatives for using GTK. First, you can use
81 only the C subset of C++ when interfacing with GTK and then use the C
82 interface as described in this tutorial. Second, you can use GTK and
83 C++ together by declaring all callbacks as static functions in C++
84 classes, and again calling GTK using its C interface. If you choose
85 this last approach, you can include as the callback's data value a
86 pointer to the object to be manipulated (the so-called "this" value).
87 Selecting between these options is simply a matter of preference,
88 since in all three approaches you get C++ and GTK. None of these
89 approaches requires the use of a specialized preprocessor, so no
90 matter what you choose you can use standard C++ with GTK.
92 This tutorial is an attempt to document as much as possible of GTK,
93 but it is by no means complete. This tutorial assumes a good
94 understanding of C, and how to create C programs. It would be a great
95 benefit for the reader to have previous X programming experience, but
96 it shouldn't be necessary. If you are learning GTK as your first
97 widget set, please comment on how you found this tutorial, and what
98 you had trouble with. There are also C++, Objective C, ADA, Guile and
99 other language bindings available, but I don't follow these.
101 This document is a "work in progress". Please look for updates on
102 <htmlurl url="http://www.gtk.org/" name="http://www.gtk.org/">.
104 I would very much like to hear of any problems you have learning GTK
105 from this document, and would appreciate input as to how it may be
106 improved. Please see the section on <ref id="sec_Contributing"
107 name="Contributing"> for further information.
109 <!-- ***************************************************************** -->
110 <sect>Getting Started
111 <!-- ***************************************************************** -->
114 The first thing to do, of course, is download the GTK source and
115 install it. You can always get the latest version from ftp.gtk.org in
116 /pub/gtk. You can also view other sources of GTK information on
117 <htmlurl url="http://www.gtk.org/" name="http://www.gtk.org/">. GTK
118 uses GNU autoconf for configuration. Once untar'd, type ./configure
119 --help to see a list of options.
121 The GTK source distribution also contains the complete source to all
122 of the examples used in this tutorial, along with Makefiles to aid
125 To begin our introduction to GTK, we'll start with the simplest
126 program possible. This program will create a 200x200 pixel window and
127 has no way of exiting except to be killed by using the shell.
130 /* example-start base base.c */
139 gtk_init (&argc, &argv);
141 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
142 gtk_widget_show (window);
151 You can compile the above program with gcc using:
153 gcc base.c -o base `gtk-config --cflags --libs`
156 The meaning of the unusual compilation options is explained below in
157 <ref id="sec_compiling" name="Compiling Hello World">.
159 All programs will of course include gtk/gtk.h which declares the
160 variables, functions, structures, etc. that will be used in your GTK
166 gtk_init (&argc, &argv);
169 calls the function gtk_init(gint *argc, gchar ***argv) which will be
170 called in all GTK applications. This sets up a few things for us such
171 as the default visual and color map and then proceeds to call
172 gdk_init(gint *argc, gchar ***argv). This function initializes the
173 library for use, sets up default signal handlers, and checks the
174 arguments passed to your application on the command line, looking for
175 one of the following:
178 <item> <tt/--gtk-module/
179 <item> <tt/--g-fatal-warnings/
180 <item> <tt/--gtk-debug/
181 <item> <tt/--gtk-no-debug/
182 <item> <tt/--gdk-debug/
183 <item> <tt/--gdk-no-debug/
184 <item> <tt/--display/
186 <item> <tt/--no-xshm/
191 It removes these from the argument list, leaving anything it does not
192 recognize for your application to parse or ignore. This creates a set
193 of standard arguments accepted by all GTK applications.
195 The next two lines of code create and display a window.
198 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
199 gtk_widget_show (window);
202 The <tt/GTK_WINDOW_TOPLEVEL/ argument specifies that we want the
203 window to undergo window manager decoration and placement. Rather than
204 create a window of 0x0 size, a window without children is set to
205 200x200 by default so you can still manipulate it.
207 The gtk_widget_show() function lets GTK know that we are done setting
208 the attributes of this widget, and that it can display it.
210 The last line enters the GTK main processing loop.
216 gtk_main() is another call you will see in every GTK application.
217 When control reaches this point, GTK will sleep waiting for X events
218 (such as button or key presses), timeouts, or file IO notifications to
219 occur. In our simple example, however, events are ignored.
221 <!-- ----------------------------------------------------------------- -->
222 <sect1>Hello World in GTK
224 Now for a program with a widget (a button). It's the classic
225 hello world a la GTK.
228 /* example-start helloworld helloworld.c */
232 /* This is a callback function. The data arguments are ignored
233 * in this example. More on callbacks below. */
234 void hello( GtkWidget *widget,
237 g_print ("Hello World\n");
240 gint delete_event( GtkWidget *widget,
244 /* If you return FALSE in the "delete_event" signal handler,
245 * GTK will emit the "destroy" signal. Returning TRUE means
246 * you don't want the window to be destroyed.
247 * This is useful for popping up 'are you sure you want to quit?'
250 g_print ("delete event occurred\n");
252 /* Change TRUE to FALSE and the main window will be destroyed with
253 * a "delete_event". */
258 /* Another callback */
259 void destroy( GtkWidget *widget,
268 /* GtkWidget is the storage type for widgets */
272 /* This is called in all GTK applications. Arguments are parsed
273 * from the command line and are returned to the application. */
274 gtk_init(&argc, &argv);
276 /* create a new window */
277 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
279 /* When the window is given the "delete_event" signal (this is given
280 * by the window manager, usually by the "close" option, or on the
281 * titlebar), we ask it to call the delete_event () function
282 * as defined above. The data passed to the callback
283 * function is NULL and is ignored in the callback function. */
284 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
285 GTK_SIGNAL_FUNC (delete_event), NULL);
287 /* Here we connect the "destroy" event to a signal handler.
288 * This event occurs when we call gtk_widget_destroy() on the window,
289 * or if we return FALSE in the "delete_event" callback. */
290 gtk_signal_connect (GTK_OBJECT (window), "destroy",
291 GTK_SIGNAL_FUNC (destroy), NULL);
293 /* Sets the border width of the window. */
294 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
296 /* Creates a new button with the label "Hello World". */
297 button = gtk_button_new_with_label ("Hello World");
299 /* When the button receives the "clicked" signal, it will call the
300 * function hello() passing it NULL as its argument. The hello()
301 * function is defined above. */
302 gtk_signal_connect (GTK_OBJECT (button), "clicked",
303 GTK_SIGNAL_FUNC (hello), NULL);
305 /* This will cause the window to be destroyed by calling
306 * gtk_widget_destroy(window) when "clicked". Again, the destroy
307 * signal could come from here, or the window manager. */
308 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
309 GTK_SIGNAL_FUNC (gtk_widget_destroy),
310 GTK_OBJECT (window));
312 /* This packs the button into the window (a gtk container). */
313 gtk_container_add (GTK_CONTAINER (window), button);
315 /* The final step is to display this newly created widget. */
316 gtk_widget_show (button);
319 gtk_widget_show (window);
321 /* All GTK applications must have a gtk_main(). Control ends here
322 * and waits for an event to occur (like a key press or
331 <!-- ----------------------------------------------------------------- -->
332 <sect1>Compiling Hello World <label id="sec_compiling">
337 gcc -Wall -g helloworld.c -o helloworld `gtk-config --cflags` \
341 This uses the program <tt/gtk-config/, which comes with GTK. This
342 program "knows" what compiler switches are needed to compile programs
343 that use GTK. <tt/gtk-config --cflags/ will output a list of include
344 directories for the compiler to look in, and <tt>gtk-config --libs</>
345 will output the list of libraries for the compiler to link with and
346 the directories to find them in. In the above example they could have
347 been combined into a single instance, such as
348 <tt/`gtk-config --cflags --libs`/.
350 Note that the type of single quote used in the compile command above
353 The libraries that are usually linked in are:
355 <item>The GTK library (-lgtk), the widget library, based on top of GDK.
356 <item>The GDK library (-lgdk), the Xlib wrapper.
357 <item>The gmodule library (-lgmodule), which is used to load run time
359 <item>The GLib library (-lglib), containing miscellaneous functions;
360 only g_print() is used in this particular example. GTK is built on top
361 of glib so you will always require this library. See the section on
362 <ref id="sec_glib" name="GLib"> for details.
363 <item>The Xlib library (-lX11) which is used by GDK.
364 <item>The Xext library (-lXext). This contains code for shared memory
365 pixmaps and other X extensions.
366 <item>The math library (-lm). This is used by GTK for various purposes.
369 <!-- ----------------------------------------------------------------- -->
370 <sect1>Theory of Signals and Callbacks
372 Before we look in detail at <em>helloworld</em>, we'll discuss signals
373 and callbacks. GTK is an event driven toolkit, which means it will
374 sleep in gtk_main until an event occurs and control is passed to the
375 appropriate function.
377 This passing of control is done using the idea of "signals". (Note
378 that these signals are not the same as the Unix system signals, and
379 are not implemented using them, although the terminology is almost
380 identical.) When an event occurs, such as the press of a mouse button,
381 the appropriate signal will be "emitted" by the widget that was
382 pressed. This is how GTK does most of its useful work. There are
383 signals that all widgets inherit, such as "destroy", and there are
384 signals that are widget specific, such as "toggled" on a toggle
387 To make a button perform an action, we set up a signal handler to
388 catch these signals and call the appropriate function. This is done by
389 using a function such as:
392 gint gtk_signal_connect( GtkObject *object,
395 gpointer func_data );
398 where the first argument is the widget which will be emitting the
399 signal, and the second the name of the signal you wish to catch. The
400 third is the function you wish to be called when it is caught, and the
401 fourth, the data you wish to have passed to this function.
403 The function specified in the third argument is called a "callback
404 function", and should generally be of the form
407 void callback_func( GtkWidget *widget,
408 gpointer callback_data );
411 where the first argument will be a pointer to the widget that emitted
412 the signal, and the second a pointer to the data given as the last
413 argument to the gtk_signal_connect() function as shown above.
415 Note that the above form for a signal callback function declaration is
416 only a general guide, as some widget specific signals generate
417 different calling parameters. For example, the CList "select_row"
418 signal provides both row and column parameters.
420 Another call used in the <em>helloworld</em> example, is:
423 gint gtk_signal_connect_object( GtkObject *object,
426 GtkObject *slot_object );
429 gtk_signal_connect_object() is the same as gtk_signal_connect() except
430 that the callback function only uses one argument, a pointer to a GTK
431 object. So when using this function to connect signals, the callback
432 should be of the form
435 void callback_func( GtkObject *object );
438 where the object is usually a widget. We usually don't setup callbacks
439 for gtk_signal_connect_object however. They are usually used to call a
440 GTK function that accepts a single widget or object as an argument, as
441 is the case in our <em>helloworld</em> example.
443 The purpose of having two functions to connect signals is simply to
444 allow the callbacks to have a different number of arguments. Many
445 functions in the GTK library accept only a single GtkWidget pointer as
446 an argument, so you want to use the gtk_signal_connect_object() for
447 these, whereas for your functions, you may need to have additional
448 data supplied to the callbacks.
450 <!-- ----------------------------------------------------------------- -->
453 In addition to the signal mechanism described above, there is a set
454 of <em>events</em> that reflect the X event mechanism. Callbacks may
455 also be attached to these events. These events are:
459 <item> button_press_event
460 <item> button_release_event
461 <item> motion_notify_event
465 <item> key_press_event
466 <item> key_release_event
467 <item> enter_notify_event
468 <item> leave_notify_event
469 <item> configure_event
470 <item> focus_in_event
471 <item> focus_out_event
474 <item> property_notify_event
475 <item> selection_clear_event
476 <item> selection_request_event
477 <item> selection_notify_event
478 <item> proximity_in_event
479 <item> proximity_out_event
480 <item> drag_begin_event
481 <item> drag_request_event
482 <item> drag_end_event
483 <item> drop_enter_event
484 <item> drop_leave_event
485 <item> drop_data_available_event
489 In order to connect a callback function to one of these events, you
490 use the function gtk_signal_connect, as described above, using one of
491 the above event names as the <tt/name/ parameter. The callback
492 function for events has a slightly different form than that for
496 void callback_func( GtkWidget *widget,
498 gpointer callback_data );
501 GdkEvent is a C <tt/union/ structure whose type will depend upon which
502 of the above events has occurred. In order for us to tell which event
503 has been issued each of the possible alternatives has a <tt/type/
504 parameter which reflects the event being issued. The other components
505 of the event structure will depend upon the type of the
506 event. Possible values for the type are:
528 GDK_SELECTION_REQUEST
538 GDK_VISIBILITY_NOTIFY
540 GDK_OTHER_EVENT /* Deprecated, use filters instead */
543 So, to connect a callback function to one of these events we would use
547 gtk_signal_connect( GTK_OBJECT(button), "button_press_event",
548 GTK_SIGNAL_FUNC(button_press_callback),
552 This assumes that <tt/button/ is a Button widget. Now, when the
553 mouse is over the button and a mouse button is pressed, the function
554 <tt/button_press_callback/ will be called. This function may be
558 static gint button_press_callback( GtkWidget *widget,
559 GdkEventButton *event,
563 Note that we can declare the second argument as type
564 <tt/GdkEventButton/ as we know what type of event will occur for this
565 function to be called.
567 The value returned from this function indicates whether the event
568 should be propagated further by the GTK event handling
569 mechanism. Returning TRUE indicates that the event has been handled,
570 and that it should not propagate further. Returning FALSE continues
571 the normal event handling. See the section on
572 <ref id="sec_Adv_Events_and_Signals"
573 name="Advanced Event and Signal Handling"> for more details on this
576 For details on the GdkEvent data types, see the appendix entitled
577 <ref id="sec_GDK_Event_Types" name="GDK Event Types">.
579 <!-- ----------------------------------------------------------------- -->
580 <sect1>Stepping Through Hello World
582 Now that we know the theory behind this, let's clarify by walking
583 through the example <em>helloworld</em> program.
585 Here is the callback function that will be called when the button is
586 "clicked". We ignore both the widget and the data in this example, but
587 it is not hard to do things with them. The next example will use the
588 data argument to tell us which button was pressed.
591 void hello( GtkWidget *widget,
594 g_print ("Hello World\n");
598 The next callback is a bit special. The "delete_event" occurs when the
599 window manager sends this event to the application. We have a choice
600 here as to what to do about these events. We can ignore them, make
601 some sort of response, or simply quit the application.
603 The value you return in this callback lets GTK know what action to
604 take. By returning TRUE, we let it know that we don't want to have
605 the "destroy" signal emitted, keeping our application running. By
606 returning FALSE, we ask that "destroy" be emitted, which in turn will
607 call our "destroy" signal handler.
610 gint delete_event( GtkWidget *widget,
614 g_print ("delete event occurred\n");
620 Here is another callback function which causes the program to quit by
621 calling gtk_main_quit(). This function tells GTK that it is to exit
622 from gtk_main when control is returned to it.
625 void destroy( GtkWidget *widget,
632 I assume you know about the main() function... yes, as with other
633 applications, all GTK applications will also have one of these.
641 This next part declares pointers to a structure of type
642 GtkWidget. These are used below to create a window and a button.
649 Here is our gtk_init again. As before, this initializes the toolkit,
650 and parses the arguments found on the command line. Any argument it
651 recognizes from the command line, it removes from the list, and
652 modifies argc and argv to make it look like they never existed,
653 allowing your application to parse the remaining arguments.
656 gtk_init (&argc, &argv);
659 Create a new window. This is fairly straightforward. Memory is
660 allocated for the GtkWidget *window structure so it now points to a
661 valid structure. It sets up a new window, but it is not displayed
662 until we call gtk_widget_show(window) near the end of our program.
665 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
668 Here are two examples of connecting a signal handler to an object, in
669 this case, the window. Here, the "delete_event" and "destroy" signals
670 are caught. The first is emitted when we use the window manager to
671 kill the window, or when we use the gtk_widget_destroy() call passing
672 in the window widget as the object to destroy. The second is emitted
673 when, in the "delete_event" handler, we return FALSE.
675 The <tt/GTK_OBJECT/ and <tt/GTK_SIGNAL_FUNC/ are macros that perform
676 type casting and checking for us, as well as aid the readability of
680 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
681 GTK_SIGNAL_FUNC (delete_event), NULL);
682 gtk_signal_connect (GTK_OBJECT (window), "destroy",
683 GTK_SIGNAL_FUNC (destroy), NULL);
686 This next function is used to set an attribute of a container object.
687 This just sets the window so it has a blank area along the inside of
688 it 10 pixels wide where no widgets will go. There are other similar
689 functions which we will look at in the section on
690 <ref id="sec_setting_widget_attributes" name="Setting Widget Attributes">
692 And again, <tt/GTK_CONTAINER/ is a macro to perform type casting.
695 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
698 This call creates a new button. It allocates space for a new GtkWidget
699 structure in memory, initializes it, and makes the button pointer
700 point to it. It will have the label "Hello World" on it when
704 button = gtk_button_new_with_label ("Hello World");
707 Here, we take this button, and make it do something useful. We attach
708 a signal handler to it so when it emits the "clicked" signal, our
709 hello() function is called. The data is ignored, so we simply pass in
710 NULL to the hello() callback function. Obviously, the "clicked" signal
711 is emitted when we click the button with our mouse pointer.
714 gtk_signal_connect (GTK_OBJECT (button), "clicked",
715 GTK_SIGNAL_FUNC (hello), NULL);
718 We are also going to use this button to exit our program. This will
719 illustrate how the "destroy" signal may come from either the window
720 manager, or our program. When the button is "clicked", same as above,
721 it calls the first hello() callback function, and then this one in the
722 order they are set up. You may have as many callback functions as you
723 need, and all will be executed in the order you connected
724 them. Because the gtk_widget_destroy() function accepts only a
725 GtkWidget *widget as an argument, we use the
726 gtk_signal_connect_object() function here instead of straight
727 gtk_signal_connect().
730 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
731 GTK_SIGNAL_FUNC (gtk_widget_destroy),
732 GTK_OBJECT (window));
735 This is a packing call, which will be explained in depth later on in
736 <ref id="sec_packing_widgets" name="Packing Widgets">. But it is
737 fairly easy to understand. It simply tells GTK that the button is to
738 be placed in the window where it will be displayed. Note that a GTK
739 container can only contain one widget. There are other widgets, that
740 are described later, which are designed to layout multiple widgets in
744 gtk_container_add (GTK_CONTAINER (window), button);
747 Now we have everything set up the way we want it to be. With all the
748 signal handlers in place, and the button placed in the window where it
749 should be, we ask GTK to "show" the widgets on the screen. The window
750 widget is shown last so the whole window will pop up at once rather
751 than seeing the window pop up, and then the button form inside of
752 it. Although with such a simple example, you'd never notice.
755 gtk_widget_show (button);
757 gtk_widget_show (window);
760 And of course, we call gtk_main() which waits for events to come from
761 the X server and will call on the widgets to emit signals when these
768 And the final return. Control returns here after gtk_quit() is called.
774 Now, when we click the mouse button on a GTK button, the widget emits
775 a "clicked" signal. In order for us to use this information, our
776 program sets up a signal handler to catch that signal, which
777 dispatches the function of our choice. In our example, when the button
778 we created is "clicked", the hello() function is called with a NULL
779 argument, and then the next handler for this signal is called. This
780 calls the gtk_widget_destroy() function, passing it the window widget
781 as its argument, destroying the window widget. This causes the window
782 to emit the "destroy" signal, which is caught, and calls our destroy()
783 callback function, which simply exits GTK.
785 Another course of events is to use the window manager to kill the
786 window, which will cause the "delete_event" to be emitted. This will
787 call our "delete_event" handler. If we return TRUE here, the window
788 will be left as is and nothing will happen. Returning FALSE will cause
789 GTK to emit the "destroy" signal which of course calls the "destroy"
790 callback, exiting GTK.
792 <!-- ***************************************************************** -->
794 <!-- ***************************************************************** -->
796 <!-- ----------------------------------------------------------------- -->
799 There are a few things you probably noticed in the previous examples
800 that need explaining. The gint, gchar, etc. that you see are typedefs
801 to int and char, respectively, that are part of the GLlib system. This
802 is done to get around that nasty dependency on the size of simple data
803 types when doing calculations.
805 A good example is "gint32" which will be typedef'd to a 32 bit integer
806 for any given platform, whether it be the 64 bit alpha, or the 32 bit
807 i386. The typedefs are very straightforward and intuitive. They are
808 all defined in glib/glib.h (which gets included from gtk.h).
810 You'll also notice GTK's ability to use GtkWidget when the function
811 calls for an Object. GTK is an object oriented design, and a widget
814 <!-- ----------------------------------------------------------------- -->
815 <sect1>More on Signal Handlers
817 Lets take another look at the gtk_signal_connect declaration.
820 gint gtk_signal_connect( GtkObject *object,
823 gpointer func_data );
826 Notice the gint return value? This is a tag that identifies your
827 callback function. As stated above, you may have as many callbacks per
828 signal and per object as you need, and each will be executed in turn,
829 in the order they were attached.
831 This tag allows you to remove this callback from the list by using:
834 void gtk_signal_disconnect( GtkObject *object,
838 So, by passing in the widget you wish to remove the handler from, and
839 the tag returned by one of the signal_connect functions, you can
840 disconnect a signal handler.
842 You can also temporarily disable signal handlers with the
843 gtk_signal_handler_block() and gtk_signal_handler_unblock() family of
847 void gtk_signal_handler_block( GtkObject *object,
850 void gtk_signal_handler_block_by_func( GtkObject *object,
854 void gtk_signal_handler_block_by_data( GtkObject *object,
857 void gtk_signal_handler_unblock( GtkObject *object,
860 void gtk_signal_handler_unblock_by_func( GtkObject *object,
864 void gtk_signal_handler_unblock_by_data( GtkObject *object,
868 <!-- ----------------------------------------------------------------- -->
869 <sect1>An Upgraded Hello World
871 Let's take a look at a slightly improved <em>helloworld</em> with
872 better examples of callbacks. This will also introduce us to our next
873 topic, packing widgets.
876 /* example-start helloworld2 helloworld2.c */
880 /* Our new improved callback. The data passed to this function
881 * is printed to stdout. */
882 void callback( GtkWidget *widget,
885 g_print ("Hello again - %s was pressed\n", (char *) data);
888 /* another callback */
889 gint delete_event( GtkWidget *widget,
900 /* GtkWidget is the storage type for widgets */
905 /* This is called in all GTK applications. Arguments are parsed
906 * from the command line and are returned to the application. */
907 gtk_init (&argc, &argv);
909 /* Create a new window */
910 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
912 /* This is a new call, which just sets the title of our
913 * new window to "Hello Buttons!" */
914 gtk_window_set_title (GTK_WINDOW (window), "Hello Buttons!");
916 /* Here we just set a handler for delete_event that immediately
918 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
919 GTK_SIGNAL_FUNC (delete_event), NULL);
921 /* Sets the border width of the window. */
922 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
924 /* We create a box to pack widgets into. This is described in detail
925 * in the "packing" section. The box is not really visible, it
926 * is just used as a tool to arrange widgets. */
927 box1 = gtk_hbox_new(FALSE, 0);
929 /* Put the box into the main window. */
930 gtk_container_add (GTK_CONTAINER (window), box1);
932 /* Creates a new button with the label "Button 1". */
933 button = gtk_button_new_with_label ("Button 1");
935 /* Now when the button is clicked, we call the "callback" function
936 * with a pointer to "button 1" as its argument */
937 gtk_signal_connect (GTK_OBJECT (button), "clicked",
938 GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");
940 /* Instead of gtk_container_add, we pack this button into the invisible
941 * box, which has been packed into the window. */
942 gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
944 /* Always remember this step, this tells GTK that our preparation for
945 * this button is complete, and it can now be displayed. */
946 gtk_widget_show(button);
948 /* Do these same steps again to create a second button */
949 button = gtk_button_new_with_label ("Button 2");
951 /* Call the same callback function with a different argument,
952 * passing a pointer to "button 2" instead. */
953 gtk_signal_connect (GTK_OBJECT (button), "clicked",
954 GTK_SIGNAL_FUNC (callback), (gpointer) "button 2");
956 gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
958 /* The order in which we show the buttons is not really important, but I
959 * recommend showing the window last, so it all pops up at once. */
960 gtk_widget_show(button);
962 gtk_widget_show(box1);
964 gtk_widget_show (window);
966 /* Rest in gtk_main and wait for the fun to begin! */
974 Compile this program using the same linking arguments as our first
975 example. You'll notice this time there is no easy way to exit the
976 program, you have to use your window manager or command line to kill
977 it. A good exercise for the reader would be to insert a third "Quit"
978 button that will exit the program. You may also wish to play with the
979 options to gtk_box_pack_start() while reading the next section. Try
980 resizing the window, and observe the behavior.
982 Just as a side note, there is another useful define for
983 gtk_window_new() - <tt/GTK_WINDOW_DIALOG/. This interacts with the
984 window manager a little differently and should be used for transient
987 <!-- ***************************************************************** -->
988 <sect>Packing Widgets <label id="sec_packing_widgets">
989 <!-- ***************************************************************** -->
991 When creating an application, you'll want to put more than one widget
992 inside a window. Our first <em>helloworld</em> example only used one
993 widget so we could simply use a gtk_container_add call to "pack" the
994 widget into the window. But when you want to put more than one widget
995 into a window, how do you control where that widget is positioned?
996 This is where packing comes in.
998 <!-- ----------------------------------------------------------------- -->
999 <sect1>Theory of Packing Boxes
1001 Most packing is done by creating boxes as in the example above. These
1002 are invisible widget containers that we can pack our widgets into
1003 which come in two forms, a horizontal box, and a vertical box. When
1004 packing widgets into a horizontal box, the objects are inserted
1005 horizontally from left to right or right to left depending on the call
1006 used. In a vertical box, widgets are packed from top to bottom or vice
1007 versa. You may use any combination of boxes inside or beside other
1008 boxes to create the desired effect.
1010 To create a new horizontal box, we use a call to gtk_hbox_new(), and
1011 for vertical boxes, gtk_vbox_new(). The gtk_box_pack_start() and
1012 gtk_box_pack_end() functions are used to place objects inside of these
1013 containers. The gtk_box_pack_start() function will start at the top
1014 and work its way down in a vbox, and pack left to right in an hbox.
1015 gtk_box_pack_end() will do the opposite, packing from bottom to top in
1016 a vbox, and right to left in an hbox. Using these functions allows us
1017 to right justify or left justify our widgets and may be mixed in any
1018 way to achieve the desired effect. We will use gtk_box_pack_start() in
1019 most of our examples. An object may be another container or a
1020 widget. In fact, many widgets are actually containers themselves,
1021 including the button, but we usually only use a label inside a button.
1023 By using these calls, GTK knows where you want to place your widgets
1024 so it can do automatic resizing and other nifty things. There are also
1025 a number of options as to how your widgets should be packed. As you
1026 can imagine, this method gives us a quite a bit of flexibility when
1027 placing and creating widgets.
1029 <!-- ----------------------------------------------------------------- -->
1030 <sect1>Details of Boxes
1032 Because of this flexibility, packing boxes in GTK can be confusing at
1033 first. There are a lot of options, and it's not immediately obvious how
1034 they all fit together. In the end, however, there are basically five
1039 <IMG SRC="gtk_tut_packbox1.gif" VSPACE="15" HSPACE="10" WIDTH="528"
1040 HEIGHT="235" ALT="Box Packing Example Image">
1044 Each line contains one horizontal box (hbox) with several buttons. The
1045 call to gtk_box_pack is shorthand for the call to pack each of the
1046 buttons into the hbox. Each of the buttons is packed into the hbox the
1047 same way (i.e., same arguments to the gtk_box_pack_start() function).
1049 This is the declaration of the gtk_box_pack_start function.
1052 void gtk_box_pack_start( GtkBox *box,
1059 The first argument is the box you are packing the object into, the
1060 second is the object. The objects will all be buttons for now, so
1061 we'll be packing buttons into boxes.
1063 The expand argument to gtk_box_pack_start() and gtk_box_pack_end()
1064 controls whether the widgets are laid out in the box to fill in all
1065 the extra space in the box so the box is expanded to fill the area
1066 allotted to it (TRUE); or the box is shrunk to just fit the widgets
1067 (FALSE). Setting expand to FALSE will allow you to do right and left
1068 justification of your widgets. Otherwise, they will all expand to fit
1069 into the box, and the same effect could be achieved by using only one
1070 of gtk_box_pack_start or gtk_box_pack_end.
1072 The fill argument to the gtk_box_pack functions control whether the
1073 extra space is allocated to the objects themselves (TRUE), or as extra
1074 padding in the box around these objects (FALSE). It only has an effect
1075 if the expand argument is also TRUE.
1077 When creating a new box, the function looks like this:
1080 GtkWidget *gtk_hbox_new (gint homogeneous,
1084 The homogeneous argument to gtk_hbox_new (and the same for
1085 gtk_vbox_new) controls whether each object in the box has the same
1086 size (i.e., the same width in an hbox, or the same height in a
1087 vbox). If it is set, the gtk_box_pack routines function essentially
1088 as if the <tt/expand/ argument was always turned on.
1090 What's the difference between spacing (set when the box is created)
1091 and padding (set when elements are packed)? Spacing is added between
1092 objects, and padding is added on either side of an object. The
1093 following figure should make it clearer:
1097 <IMG ALIGN="center" SRC="gtk_tut_packbox2.gif" WIDTH="509"
1098 HEIGHT="213" VSPACE="15" HSPACE="10"
1099 ALT="Box Packing Example Image">
1103 Here is the code used to create the above images. I've commented it
1104 fairly heavily so I hope you won't have any problems following
1105 it. Compile it yourself and play with it.
1107 <!-- ----------------------------------------------------------------- -->
1108 <sect1>Packing Demonstration Program
1111 /* example-start packbox packbox.c */
1115 #include "gtk/gtk.h"
1117 gint delete_event( GtkWidget *widget,
1125 /* Make a new hbox filled with button-labels. Arguments for the
1126 * variables we're interested are passed in to this function.
1127 * We do not show the box, but do show everything inside. */
1128 GtkWidget *make_box( gint homogeneous,
1138 /* Create a new hbox with the appropriate homogeneous
1139 * and spacing settings */
1140 box = gtk_hbox_new (homogeneous, spacing);
1142 /* Create a series of buttons with the appropriate settings */
1143 button = gtk_button_new_with_label ("gtk_box_pack");
1144 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1145 gtk_widget_show (button);
1147 button = gtk_button_new_with_label ("(box,");
1148 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1149 gtk_widget_show (button);
1151 button = gtk_button_new_with_label ("button,");
1152 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1153 gtk_widget_show (button);
1155 /* Create a button with the label depending on the value of
1158 button = gtk_button_new_with_label ("TRUE,");
1160 button = gtk_button_new_with_label ("FALSE,");
1162 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1163 gtk_widget_show (button);
1165 /* This is the same as the button creation for "expand"
1166 * above, but uses the shorthand form. */
1167 button = gtk_button_new_with_label (fill ? "TRUE," : "FALSE,");
1168 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1169 gtk_widget_show (button);
1171 sprintf (padstr, "%d);", padding);
1173 button = gtk_button_new_with_label (padstr);
1174 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1175 gtk_widget_show (button);
1187 GtkWidget *separator;
1192 /* Our init, don't forget this! :) */
1193 gtk_init (&argc, &argv);
1196 fprintf (stderr, "usage: packbox num, where num is 1, 2, or 3.\n");
1197 /* This just does cleanup in GTK and exits with an exit status of 1. */
1201 which = atoi (argv[1]);
1203 /* Create our window */
1204 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1206 /* You should always remember to connect the delete_event signal
1207 * to the main window. This is very important for proper intuitive
1209 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
1210 GTK_SIGNAL_FUNC (delete_event), NULL);
1211 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
1213 /* We create a vertical box (vbox) to pack the horizontal boxes into.
1214 * This allows us to stack the horizontal boxes filled with buttons one
1215 * on top of the other in this vbox. */
1216 box1 = gtk_vbox_new (FALSE, 0);
1218 /* which example to show. These correspond to the pictures above. */
1221 /* create a new label. */
1222 label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1224 /* Align the label to the left side. We'll discuss this function and
1225 * others in the section on Widget Attributes. */
1226 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1228 /* Pack the label into the vertical box (vbox box1). Remember that
1229 * widgets added to a vbox will be packed one on top of the other in
1231 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1233 /* Show the label */
1234 gtk_widget_show (label);
1236 /* Call our make box function - homogeneous = FALSE, spacing = 0,
1237 * expand = FALSE, fill = FALSE, padding = 0 */
1238 box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1239 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1240 gtk_widget_show (box2);
1242 /* Call our make box function - homogeneous = FALSE, spacing = 0,
1243 * expand = TRUE, fill = FALSE, padding = 0 */
1244 box2 = make_box (FALSE, 0, TRUE, FALSE, 0);
1245 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1246 gtk_widget_show (box2);
1248 /* Args are: homogeneous, spacing, expand, fill, padding */
1249 box2 = make_box (FALSE, 0, TRUE, TRUE, 0);
1250 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1251 gtk_widget_show (box2);
1253 /* Creates a separator, we'll learn more about these later,
1254 * but they are quite simple. */
1255 separator = gtk_hseparator_new ();
1257 /* Pack the separator into the vbox. Remember each of these
1258 * widgets is being packed into a vbox, so they'll be stacked
1260 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1261 gtk_widget_show (separator);
1263 /* Create another new label, and show it. */
1264 label = gtk_label_new ("gtk_hbox_new (TRUE, 0);");
1265 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1266 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1267 gtk_widget_show (label);
1269 /* Args are: homogeneous, spacing, expand, fill, padding */
1270 box2 = make_box (TRUE, 0, TRUE, FALSE, 0);
1271 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1272 gtk_widget_show (box2);
1274 /* Args are: homogeneous, spacing, expand, fill, padding */
1275 box2 = make_box (TRUE, 0, TRUE, TRUE, 0);
1276 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1277 gtk_widget_show (box2);
1279 /* Another new separator. */
1280 separator = gtk_hseparator_new ();
1281 /* The last 3 arguments to gtk_box_pack_start are:
1282 * expand, fill, padding. */
1283 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1284 gtk_widget_show (separator);
1290 /* Create a new label, remember box1 is a vbox as created
1291 * near the beginning of main() */
1292 label = gtk_label_new ("gtk_hbox_new (FALSE, 10);");
1293 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1294 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1295 gtk_widget_show (label);
1297 /* Args are: homogeneous, spacing, expand, fill, padding */
1298 box2 = make_box (FALSE, 10, TRUE, FALSE, 0);
1299 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1300 gtk_widget_show (box2);
1302 /* Args are: homogeneous, spacing, expand, fill, padding */
1303 box2 = make_box (FALSE, 10, TRUE, TRUE, 0);
1304 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1305 gtk_widget_show (box2);
1307 separator = gtk_hseparator_new ();
1308 /* The last 3 arguments to gtk_box_pack_start are:
1309 * expand, fill, padding. */
1310 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1311 gtk_widget_show (separator);
1313 label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1314 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1315 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1316 gtk_widget_show (label);
1318 /* Args are: homogeneous, spacing, expand, fill, padding */
1319 box2 = make_box (FALSE, 0, TRUE, FALSE, 10);
1320 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1321 gtk_widget_show (box2);
1323 /* Args are: homogeneous, spacing, expand, fill, padding */
1324 box2 = make_box (FALSE, 0, TRUE, TRUE, 10);
1325 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1326 gtk_widget_show (box2);
1328 separator = gtk_hseparator_new ();
1329 /* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */
1330 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1331 gtk_widget_show (separator);
1336 /* This demonstrates the ability to use gtk_box_pack_end() to
1337 * right justify widgets. First, we create a new box as before. */
1338 box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1340 /* Create the label that will be put at the end. */
1341 label = gtk_label_new ("end");
1342 /* Pack it using gtk_box_pack_end(), so it is put on the right
1343 * side of the hbox created in the make_box() call. */
1344 gtk_box_pack_end (GTK_BOX (box2), label, FALSE, FALSE, 0);
1345 /* Show the label. */
1346 gtk_widget_show (label);
1348 /* Pack box2 into box1 (the vbox remember ? :) */
1349 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1350 gtk_widget_show (box2);
1352 /* A separator for the bottom. */
1353 separator = gtk_hseparator_new ();
1354 /* This explicitly sets the separator to 400 pixels wide by 5 pixels
1355 * high. This is so the hbox we created will also be 400 pixels wide,
1356 * and the "end" label will be separated from the other labels in the
1357 * hbox. Otherwise, all the widgets in the hbox would be packed as
1358 * close together as possible. */
1359 gtk_widget_set_usize (separator, 400, 5);
1360 /* pack the separator into the vbox (box1) created near the start
1362 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1363 gtk_widget_show (separator);
1366 /* Create another new hbox.. remember we can use as many as we need! */
1367 quitbox = gtk_hbox_new (FALSE, 0);
1369 /* Our quit button. */
1370 button = gtk_button_new_with_label ("Quit");
1372 /* Setup the signal to terminate the program when the button is clicked */
1373 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
1374 GTK_SIGNAL_FUNC (gtk_main_quit),
1375 GTK_OBJECT (window));
1376 /* Pack the button into the quitbox.
1377 * The last 3 arguments to gtk_box_pack_start are:
1378 * expand, fill, padding. */
1379 gtk_box_pack_start (GTK_BOX (quitbox), button, TRUE, FALSE, 0);
1380 /* pack the quitbox into the vbox (box1) */
1381 gtk_box_pack_start (GTK_BOX (box1), quitbox, FALSE, FALSE, 0);
1383 /* Pack the vbox (box1) which now contains all our widgets, into the
1385 gtk_container_add (GTK_CONTAINER (window), box1);
1387 /* And show everything left */
1388 gtk_widget_show (button);
1389 gtk_widget_show (quitbox);
1391 gtk_widget_show (box1);
1392 /* Showing the window last so everything pops up at once. */
1393 gtk_widget_show (window);
1395 /* And of course, our main function. */
1398 /* Control returns here when gtk_main_quit() is called, but not when
1399 * gtk_exit is used. */
1406 <!-- ----------------------------------------------------------------- -->
1407 <sect1>Packing Using Tables
1409 Let's take a look at another way of packing - Tables. These can be
1410 extremely useful in certain situations.
1412 Using tables, we create a grid that we can place widgets in. The
1413 widgets may take up as many spaces as we specify.
1415 The first thing to look at, of course, is the gtk_table_new function:
1418 GtkWidget *gtk_table_new( gint rows,
1423 The first argument is the number of rows to make in the table, while
1424 the second, obviously, is the number of columns.
1426 The homogeneous argument has to do with how the table's boxes are
1427 sized. If homogeneous is TRUE, the table boxes are resized to the size
1428 of the largest widget in the table. If homogeneous is FALSE, the size
1429 of a table boxes is dictated by the tallest widget in its same row,
1430 and the widest widget in its column.
1432 The rows and columns are laid out from 0 to n, where n was the number
1433 specified in the call to gtk_table_new. So, if you specify rows = 2
1434 and columns = 2, the layout would look something like this:
1438 0+----------+----------+
1440 1+----------+----------+
1442 2+----------+----------+
1445 Note that the coordinate system starts in the upper left hand corner.
1446 To place a widget into a box, use the following function:
1449 void gtk_table_attach( GtkTable *table,
1461 The first argument ("table") is the table you've created and the
1462 second ("child") the widget you wish to place in the table.
1464 The left and right attach arguments specify where to place the widget,
1465 and how many boxes to use. If you want a button in the lower right
1466 table entry of our 2x2 table, and want it to fill that entry ONLY,
1467 left_attach would be = 1, right_attach = 2, top_attach = 1,
1470 Now, if you wanted a widget to take up the whole top row of our 2x2
1471 table, you'd use left_attach = 0, right_attach = 2, top_attach = 0,
1474 The xoptions and yoptions are used to specify packing options and may
1475 be bitwise OR'ed together to allow multiple options.
1479 <item><tt/GTK_FILL/ - If the table box is larger than the widget, and
1480 <tt/GTK_FILL/ is specified, the widget will expand to use all the room
1483 <item><tt/GTK_SHRINK/ - If the table widget was allocated less space
1484 then was requested (usually by the user resizing the window), then the
1485 widgets would normally just be pushed off the bottom of the window and
1486 disappear. If <tt/GTK_SHRINK/ is specified, the widgets will shrink
1489 <item><tt/GTK_EXPAND/ - This will cause the table to expand to use up
1490 any remaining space in the window.
1493 Padding is just like in boxes, creating a clear area around the widget
1494 specified in pixels.
1496 gtk_table_attach() has a LOT of options. So, there's a shortcut:
1499 void gtk_table_attach_defaults( GtkTable *table,
1504 gint bottom_attach );
1507 The X and Y options default to <tt/GTK_FILL | GTK_EXPAND/, and X and Y
1508 padding are set to 0. The rest of the arguments are identical to the
1511 We also have gtk_table_set_row_spacing() and
1512 gtk_table_set_col_spacing(). These places spacing between the rows at
1513 the specified row or column.
1516 void gtk_table_set_row_spacing( GtkTable *table,
1524 void gtk_table_set_col_spacing ( GtkTable *table,
1529 Note that for columns, the space goes to the right of the column, and
1530 for rows, the space goes below the row.
1532 You can also set a consistent spacing of all rows and/or columns with:
1535 void gtk_table_set_row_spacings( GtkTable *table,
1542 void gtk_table_set_col_spacings( GtkTable *table,
1546 Note that with these calls, the last row and last column do not get
1549 <!-- ----------------------------------------------------------------- -->
1550 <sect1>Table Packing Example
1552 Here we make a window with three buttons in a 2x2 table.
1553 The first two buttons will be placed in the upper row.
1554 A third, quit button, is placed in the lower row, spanning both columns.
1555 Which means it should look something like this:
1559 <IMG SRC="gtk_tut_table.gif" VSPACE="15" HSPACE="10"
1560 ALT="Table Packing Example Image" WIDTH="180" HEIGHT="120">
1564 Here's the source code:
1567 /* example-start table table.c */
1569 #include <gtk/gtk.h>
1572 * The data passed to this function is printed to stdout */
1573 void callback( GtkWidget *widget,
1576 g_print ("Hello again - %s was pressed\n", (char *) data);
1579 /* This callback quits the program */
1580 gint delete_event( GtkWidget *widget,
1595 gtk_init (&argc, &argv);
1597 /* Create a new window */
1598 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1600 /* Set the window title */
1601 gtk_window_set_title (GTK_WINDOW (window), "Table");
1603 /* Set a handler for delete_event that immediately
1605 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
1606 GTK_SIGNAL_FUNC (delete_event), NULL);
1608 /* Sets the border width of the window. */
1609 gtk_container_set_border_width (GTK_CONTAINER (window), 20);
1611 /* Create a 2x2 table */
1612 table = gtk_table_new (2, 2, TRUE);
1614 /* Put the table in the main window */
1615 gtk_container_add (GTK_CONTAINER (window), table);
1617 /* Create first button */
1618 button = gtk_button_new_with_label ("button 1");
1620 /* When the button is clicked, we call the "callback" function
1621 * with a pointer to "button 1" as its argument */
1622 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1623 GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");
1626 /* Insert button 1 into the upper left quadrant of the table */
1627 gtk_table_attach_defaults (GTK_TABLE(table), button, 0, 1, 0, 1);
1629 gtk_widget_show (button);
1631 /* Create second button */
1633 button = gtk_button_new_with_label ("button 2");
1635 /* When the button is clicked, we call the "callback" function
1636 * with a pointer to "button 2" as its argument */
1637 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1638 GTK_SIGNAL_FUNC (callback), (gpointer) "button 2");
1639 /* Insert button 2 into the upper right quadrant of the table */
1640 gtk_table_attach_defaults (GTK_TABLE(table), button, 1, 2, 0, 1);
1642 gtk_widget_show (button);
1644 /* Create "Quit" button */
1645 button = gtk_button_new_with_label ("Quit");
1647 /* When the button is clicked, we call the "delete_event" function
1648 * and the program exits */
1649 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1650 GTK_SIGNAL_FUNC (delete_event), NULL);
1652 /* Insert the quit button into the both
1653 * lower quadrants of the table */
1654 gtk_table_attach_defaults (GTK_TABLE(table), button, 0, 2, 1, 2);
1656 gtk_widget_show (button);
1658 gtk_widget_show (table);
1659 gtk_widget_show (window);
1668 <!-- ***************************************************************** -->
1669 <sect>Widget Overview
1670 <!-- ***************************************************************** -->
1672 The general steps to creating a widget in GTK are:
1674 <item> gtk_*_new - one of various functions to create a new widget.
1675 These are all detailed in this section.
1677 <item> Connect all signals and events we wish to use to the
1678 appropriate handlers.
1680 <item> Set the attributes of the widget.
1682 <item> Pack the widget into a container using the appropriate call
1683 such as gtk_container_add() or gtk_box_pack_start().
1685 <item> gtk_widget_show() the widget.
1688 gtk_widget_show() lets GTK know that we are done setting the
1689 attributes of the widget, and it is ready to be displayed. You may
1690 also use gtk_widget_hide to make it disappear again. The order in
1691 which you show the widgets is not important, but I suggest showing the
1692 window last so the whole window pops up at once rather than seeing the
1693 individual widgets come up on the screen as they're formed. The
1694 children of a widget (a window is a widget too) will not be displayed
1695 until the window itself is shown using the gtk_widget_show() function.
1697 <!-- ----------------------------------------------------------------- -->
1700 You'll notice as you go on that GTK uses a type casting system. This
1701 is always done using macros that both test the ability to cast the
1702 given item, and perform the cast. Some common ones you will see are:
1707 GTK_SIGNAL_FUNC(function)
1708 GTK_CONTAINER(container)
1713 These are all used to cast arguments in functions. You'll see them in the
1714 examples, and can usually tell when to use them simply by looking at the
1715 function's declaration.
1717 As you can see below in the class hierarchy, all GtkWidgets are
1718 derived from the Object base class. This means you can use a widget
1719 in any place the function asks for an object - simply use the
1720 <tt/GTK_OBJECT()/ macro.
1725 gtk_signal_connect( GTK_OBJECT(button), "clicked",
1726 GTK_SIGNAL_FUNC(callback_function), callback_data);
1729 This casts the button into an object, and provides a cast for the
1730 function pointer to the callback.
1732 Many widgets are also containers. If you look in the class hierarchy
1733 below, you'll notice that many widgets derive from the Container
1734 class. Any one of these widgets may be used with the
1735 <tt/GTK_CONTAINER/ macro to pass them to functions that ask for
1738 Unfortunately, these macros are not extensively covered in the
1739 tutorial, but I recommend taking a look through the GTK header
1740 files. It can be very educational. In fact, it's not difficult to
1741 learn how a widget works just by looking at the function declarations.
1743 <!-- ----------------------------------------------------------------- -->
1744 <sect1>Widget Hierarchy
1746 For your reference, here is the class hierarchy tree used to implement widgets.
1753 | | | +GtkAccelLabel
1762 | | | | `GtkAspectFrame
1764 | | | | +GtkToggleButton
1765 | | | | | `GtkCheckButton
1766 | | | | | `GtkRadioButton
1767 | | | | `GtkOptionMenu
1769 | | | | +GtkMenuItem
1770 | | | | | +GtkCheckMenuItem
1771 | | | | | | `GtkRadioMenuItem
1772 | | | | | `GtkTearoffMenuItem
1773 | | | | +GtkListItem
1774 | | | | `GtkTreeItem
1776 | | | | +GtkColorSelectionDialog
1778 | | | | | `GtkInputDialog
1779 | | | | +GtkDrawWindow
1780 | | | | +GtkFileSelection
1781 | | | | +GtkFontSelectionDialog
1785 | | | +GtkScrolledWindow
1789 | | | | +GtkHButtonBox
1790 | | | | `GtkVButtonBox
1792 | | | | +GtkColorSelection
1793 | | | | `GtkGammaCurve
1801 | | | `GtkFontSelection
1820 | | | `GtkSpinButton
1844 <!-- ----------------------------------------------------------------- -->
1845 <sect1>Widgets Without Windows
1847 The following widgets do not have an associated window. If you want to
1848 capture events, you'll have to use the EventBox. See the section on
1849 the <ref id="sec_EventBox" name="EventBox"> widget.
1871 We'll further our exploration of GTK by examining each widget in turn,
1872 creating a few simple functions to display them. Another good source
1873 is the testgtk.c program that comes with GTK. It can be found in
1876 <!-- ***************************************************************** -->
1877 <sect>The Button Widget
1878 <!-- ***************************************************************** -->
1880 <!-- ----------------------------------------------------------------- -->
1881 <sect1>Normal Buttons
1883 We've almost seen all there is to see of the button widget. It's
1884 pretty simple. There are however two ways to create a button. You can
1885 use the gtk_button_new_with_label() to create a button with a label,
1886 or use gtk_button_new() to create a blank button. It's then up to you
1887 to pack a label or pixmap into this new button. To do this, create a
1888 new box, and then pack your objects into this box using the usual
1889 gtk_box_pack_start, and then use gtk_container_add to pack the box
1892 Here's an example of using gtk_button_new to create a button with a
1893 picture and a label in it. I've broken up the code to create a box
1894 from the rest so you can use it in your programs. There are further
1895 examples of using pixmaps later in the tutorial.
1898 /* example-start buttons buttons.c */
1900 #include <gtk/gtk.h>
1902 /* Create a new hbox with an image and a label packed into it
1903 * and return the box. */
1905 GtkWidget *xpm_label_box( GtkWidget *parent,
1906 gchar *xpm_filename,
1911 GtkWidget *pixmapwid;
1916 /* Create box for xpm and label */
1917 box1 = gtk_hbox_new (FALSE, 0);
1918 gtk_container_set_border_width (GTK_CONTAINER (box1), 2);
1920 /* Get the style of the button to get the
1921 * background color. */
1922 style = gtk_widget_get_style(parent);
1924 /* Now on to the xpm stuff */
1925 pixmap = gdk_pixmap_create_from_xpm (parent->window, &mask,
1926 &style->bg[GTK_STATE_NORMAL],
1928 pixmapwid = gtk_pixmap_new (pixmap, mask);
1930 /* Create a label for the button */
1931 label = gtk_label_new (label_text);
1933 /* Pack the pixmap and label into the box */
1934 gtk_box_pack_start (GTK_BOX (box1),
1935 pixmapwid, FALSE, FALSE, 3);
1937 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 3);
1939 gtk_widget_show(pixmapwid);
1940 gtk_widget_show(label);
1945 /* Our usual callback function */
1946 void callback( GtkWidget *widget,
1949 g_print ("Hello again - %s was pressed\n", (char *) data);
1956 /* GtkWidget is the storage type for widgets */
1961 gtk_init (&argc, &argv);
1963 /* Create a new window */
1964 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1966 gtk_window_set_title (GTK_WINDOW (window), "Pixmap'd Buttons!");
1968 /* It's a good idea to do this for all windows. */
1969 gtk_signal_connect (GTK_OBJECT (window), "destroy",
1970 GTK_SIGNAL_FUNC (gtk_exit), NULL);
1972 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
1973 GTK_SIGNAL_FUNC (gtk_exit), NULL);
1975 /* Sets the border width of the window. */
1976 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
1977 gtk_widget_realize(window);
1979 /* Create a new button */
1980 button = gtk_button_new ();
1982 /* Connect the "clicked" signal of the button to our callback */
1983 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1984 GTK_SIGNAL_FUNC (callback), (gpointer) "cool button");
1986 /* This calls our box creating function */
1987 box1 = xpm_label_box(window, "info.xpm", "cool button");
1989 /* Pack and show all our widgets */
1990 gtk_widget_show(box1);
1992 gtk_container_add (GTK_CONTAINER (button), box1);
1994 gtk_widget_show(button);
1996 gtk_container_add (GTK_CONTAINER (window), button);
1998 gtk_widget_show (window);
2000 /* Rest in gtk_main and wait for the fun to begin! */
2008 The xpm_label_box function could be used to pack xpm's and labels into
2009 any widget that can be a container.
2011 Notice in <tt/xpm_label_box/ how there is a call to
2012 <tt/gtk_widget_get_style/. Every widget has a "style", consisting of
2013 foreground and background colors for a variety of situations, font
2014 selection, and other graphics data relevant to a widget. These style
2015 values are defaulted in each widget, and are required by many GDK
2016 function calls, such as <tt/gdk_pixmap_create_from_xpm/, which here is
2017 given the "normal" background color. The style data of widgets may
2018 be customized, using <ref id="sec_gtkrc_files" name="GTK's rc files">.
2020 Also notice the call to <tt/gtk_widget_realize/ after setting the
2021 window's border width. This function uses GDK to create the X
2022 windows related to the widget. The function is automatically called
2023 when you invoke <tt/gtk_widget_show/ for a widget, and so has not been
2024 shown in earlier examples. But the call to
2025 <tt/gdk_pixmap_create_from_xpm/ requires that its <tt/window/ argument
2026 refer to a real X window, so it is necessary to realize the widget
2027 before this GDK call.
2029 The Button widget has the following signals:
2032 <item><tt/pressed/ - emitted when pointer button is pressed within
2034 <item><tt/released/ - emitted when pointer button is released within
2036 <item><tt/clicked/ - emitted when pointer button is pressed and then
2037 released within Button widget
2038 <item><tt/enter/ - emitted when pointer enters Button widget
2039 <item><tt/leave/ - emitted when pointer leaves Button widget
2042 <!-- ----------------------------------------------------------------- -->
2043 <sect1> Toggle Buttons
2045 Toggle buttons are derived from normal buttons and are very similar,
2046 except they will always be in one of two states, alternated by a
2047 click. They may be depressed, and when you click again, they will pop
2048 back up. Click again, and they will pop back down.
2050 Toggle buttons are the basis for check buttons and radio buttons, as
2051 such, many of the calls used for toggle buttons are inherited by radio
2052 and check buttons. I will point these out when we come to them.
2054 Creating a new toggle button:
2057 GtkWidget *gtk_toggle_button_new( void );
2059 GtkWidget *gtk_toggle_button_new_with_label( gchar *label );
2062 As you can imagine, these work identically to the normal button widget
2063 calls. The first creates a blank toggle button, and the second, a
2064 button with a label widget already packed into it.
2066 To retrieve the state of the toggle widget, including radio and check
2067 buttons, we use a construct as shown in our example below. This tests
2068 the state of the toggle, by accessing the <tt/active/ field of the
2069 toggle widget's structure, after first using the
2070 <tt/GTK_TOGGLE_BUTTON/ macro to cast the widget pointer into a toggle
2071 widget pointer. The signal of interest to us emitted by toggle
2072 buttons (the toggle button, check button, and radio button widgets) is
2073 the "toggled" signal. To check the state of these buttons, set up a
2074 signal handler to catch the toggled signal, and access the structure
2075 to determine its state. The callback will look something like:
2078 void toggle_button_callback (GtkWidget *widget, gpointer data)
2080 if (GTK_TOGGLE_BUTTON (widget)->active)
2082 /* If control reaches here, the toggle button is down */
2086 /* If control reaches here, the toggle button is up */
2091 To force the state of a toggle button, and its children, the radio and
2092 check buttons, use this function:
2095 void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,
2099 The above call can be used to set the state of the toggle button, and
2100 its children the radio and check buttons. Passing in your created
2101 button as the first argument, and a TRUE or FALSE for the second state
2102 argument to specify whether it should be down (depressed) or up
2103 (released). Default is up, or FALSE.
2105 Note that when you use the gtk_toggle_button_set_active() function, and
2106 the state is actually changed, it causes the "clicked" signal to be
2107 emitted from the button.
2110 void gtk_toggle_button_toggled (GtkToggleButton *toggle_button);
2113 This simply toggles the button, and emits the "toggled" signal.
2115 <!-- ----------------------------------------------------------------- -->
2116 <sect1> Check Buttons
2118 Check buttons inherit many properties and functions from the the
2119 toggle buttons above, but look a little different. Rather than being
2120 buttons with text inside them, they are small squares with the text to
2121 the right of them. These are often used for toggling options on and
2122 off in applications.
2124 The two creation functions are similar to those of the normal button.
2127 GtkWidget *gtk_check_button_new( void );
2129 GtkWidget *gtk_check_button_new_with_label ( gchar *label );
2132 The new_with_label function creates a check button with a label beside
2135 Checking the state of the check button is identical to that of the
2138 <!-- ----------------------------------------------------------------- -->
2139 <sect1> Radio Buttons <label id="sec_Radio_Buttons">
2141 Radio buttons are similar to check buttons except they are grouped so
2142 that only one may be selected/depressed at a time. This is good for
2143 places in your application where you need to select from a short list
2146 Creating a new radio button is done with one of these calls:
2149 GtkWidget *gtk_radio_button_new( GSList *group );
2151 GtkWidget *gtk_radio_button_new_with_label( GSList *group,
2155 You'll notice the extra argument to these calls. They require a group
2156 to perform their duty properly. The first call to
2157 gtk_radio_button_new_with_label or gtk_radio_button_new_with_label
2158 should pass NULL as the first argument. Then create a group using:
2161 GSList *gtk_radio_button_group( GtkRadioButton *radio_button );
2164 The important thing to remember is that gtk_radio_button_group must be
2165 called for each new button added to the group, with the previous
2166 button passed in as an argument. The result is then passed into the
2167 next call to gtk_radio_button_new or
2168 gtk_radio_button_new_with_label. This allows a chain of buttons to be
2169 established. The example below should make this clear.
2171 You can shorten this slightly by using the following syntax, which
2172 removes the need for a variable to hold the list of buttons. This form
2173 is used in the example to create the third button:
2176 button2 = gtk_radio_button_new_with_label(
2177 gtk_radio_button_group (GTK_RADIO_BUTTON (button1)),
2181 It is also a good idea to explicitly set which button should be the
2182 default depressed button with:
2185 void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,
2189 This is described in the section on toggle buttons, and works in
2190 exactly the same way. Once the radio buttons are grouped together,
2191 only one of the group may be active at a time. If the user clicks on
2192 one radio button, and then on another, the first radio button will
2193 first emit a "toggled" signal (to report becoming inactive), and then
2194 the second will emit its "toggled" signal (to report becoming active).
2196 The following example creates a radio button group with three buttons.
2199 /* example-start radiobuttons radiobuttons.c */
2201 #include <gtk/gtk.h>
2204 gint close_application( GtkWidget *widget,
2215 GtkWidget *window = NULL;
2219 GtkWidget *separator;
2222 gtk_init(&argc,&argv);
2224 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2226 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
2227 GTK_SIGNAL_FUNC(close_application),
2230 gtk_window_set_title (GTK_WINDOW (window), "radio buttons");
2231 gtk_container_set_border_width (GTK_CONTAINER (window), 0);
2233 box1 = gtk_vbox_new (FALSE, 0);
2234 gtk_container_add (GTK_CONTAINER (window), box1);
2235 gtk_widget_show (box1);
2237 box2 = gtk_vbox_new (FALSE, 10);
2238 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2239 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2240 gtk_widget_show (box2);
2242 button = gtk_radio_button_new_with_label (NULL, "button1");
2243 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2244 gtk_widget_show (button);
2246 group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
2247 button = gtk_radio_button_new_with_label(group, "button2");
2248 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2249 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2250 gtk_widget_show (button);
2252 button = gtk_radio_button_new_with_label(
2253 gtk_radio_button_group (GTK_RADIO_BUTTON (button)),
2255 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2256 gtk_widget_show (button);
2258 separator = gtk_hseparator_new ();
2259 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
2260 gtk_widget_show (separator);
2262 box2 = gtk_vbox_new (FALSE, 10);
2263 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2264 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
2265 gtk_widget_show (box2);
2267 button = gtk_button_new_with_label ("close");
2268 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2269 GTK_SIGNAL_FUNC(close_application),
2270 GTK_OBJECT (window));
2271 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2272 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
2273 gtk_widget_grab_default (button);
2274 gtk_widget_show (button);
2275 gtk_widget_show (window);
2284 <!-- TODO: check out gtk_radio_button_new_from_widget function - TRG -->
2286 <!-- ***************************************************************** -->
2287 <sect> Adjustments <label id="sec_Adjustment">
2288 <!-- ***************************************************************** -->
2290 GTK has various widgets that can be visually adjusted by the user
2291 using the mouse or the keyboard, such as the range widgets, described
2292 in the <ref id="sec_Range_Widgets" name="Range Widgets">
2293 section. There are also a few widgets that display some adjustable
2294 portion of a larger area of data, such as the text widget and the
2297 Obviously, an application needs to be able to react to changes the
2298 user makes in range widgets. One way to do this would be to have each
2299 widget emit its own type of signal when its adjustment changes, and
2300 either pass the new value to the signal handler, or require it to look
2301 inside the widget's data structure in order to ascertain the value.
2302 But you may also want to connect the adjustments of several widgets
2303 together, so that adjusting one adjusts the others. The most obvious
2304 example of this is connecting a scrollbar to a panning viewport or a
2305 scrolling text area. If each widget has its own way of setting or
2306 getting the adjustment value, then the programmer may have to write
2307 their own signal handlers to translate between the output of one
2308 widget's signal and the "input" of another's adjustment setting
2311 GTK solves this problem using the Adjustment object, which is not a
2312 widget but a way for widgets to store and pass adjustment information
2313 in an abstract and flexible form. The most obvious use of Adjustment
2314 is to store the configuration parameters and values of range widgets,
2315 such as scrollbars and scale controls. However, since Adjustments are
2316 derived from Object, they have some special powers beyond those of
2317 normal data structures. Most importantly, they can emit signals, just
2318 like widgets, and these signals can be used not only to allow your
2319 program to react to user input on adjustable widgets, but also to
2320 propagate adjustment values transparently between adjustable widgets.
2322 You will see how adjustments fit in when you see the other widgets
2323 that incorporate them:
2324 <ref id="sec_ProgressBar" name="Progress Bars">,
2325 <ref id="sec_Viewports" name="Viewports">,
2326 <ref id="sec_ScrolledWindow" name="Scrolled Windows">, and others.
2328 <sect1> Creating an Adjustment
2330 Many of the widgets which use adjustment objects do so automatically,
2331 but some cases will be shown in later examples where you may need to
2332 create one yourself. You create an adjustment using:
2335 GtkObject *gtk_adjustment_new( gfloat value,
2338 gfloat step_increment,
2339 gfloat page_increment,
2343 The <tt/value/ argument is the initial value you want to give to the
2344 adjustment, usually corresponding to the topmost or leftmost position
2345 of an adjustable widget. The <tt/lower/ argument specifies the lowest
2346 value which the adjustment can hold. The <tt/step_increment/ argument
2347 specifies the "smaller" of the two increments by which the user can
2348 change the value, while the <tt/page_increment/ is the "larger" one.
2349 The <tt/page_size/ argument usually corresponds somehow to the visible
2350 area of a panning widget. The <tt/upper/ argument is used to represent
2351 the bottom most or right most coordinate in a panning widget's
2352 child. Therefore it is <em/not/ always the largest number that
2353 <tt/value/ can take, since the <tt/page_size/ of such widgets is
2356 <!-- ----------------------------------------------------------------- -->
2357 <sect1> Using Adjustments the Easy Way
2359 The adjustable widgets can be roughly divided into those which use and
2360 require specific units for these values and those which treat them as
2361 arbitrary numbers. The group which treats the values as arbitrary
2362 numbers includes the range widgets (scrollbars and scales, the
2363 progress bar widget, and the spin button widget). These widgets are
2364 all the widgets which are typically "adjusted" directly by the user
2365 with the mouse or keyboard. They will treat the <tt/lower/ and
2366 <tt/upper/ values of an adjustment as a range within which the user
2367 can manipulate the adjustment's <tt/value/. By default, they will only
2368 modify the <tt/value/ of an adjustment.
2370 The other group includes the text widget, the viewport widget, the
2371 compound list widget, and the scrolled window widget. All of these
2372 widgets use pixel values for their adjustments. These are also all
2373 widgets which are typically "adjusted" indirectly using scrollbars.
2374 While all widgets which use adjustments can either create their own
2375 adjustments or use ones you supply, you'll generally want to let this
2376 particular category of widgets create its own adjustments. Usually,
2377 they will eventually override all the values except the <tt/value/
2378 itself in whatever adjustments you give them, but the results are, in
2379 general, undefined (meaning, you'll have to read the source code to
2380 find out, and it may be different from widget to widget).
2382 Now, you're probably thinking, since text widgets and viewports insist
2383 on setting everything except the <tt/value/ of their adjustments,
2384 while scrollbars will <em/only/ touch the adjustment's <tt/value/, if
2385 you <em/share/ an adjustment object between a scrollbar and a text
2386 widget, manipulating the scrollbar will automagically adjust the text
2387 widget? Of course it will! Just like this:
2390 /* creates its own adjustments */
2391 text = gtk_text_new (NULL, NULL);
2392 /* uses the newly-created adjustment for the scrollbar as well */
2393 vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
2397 <!-- ----------------------------------------------------------------- -->
2398 <sect1> Adjustment Internals
2400 Ok, you say, that's nice, but what if I want to create my own handlers
2401 to respond when the user adjusts a range widget or a spin button, and
2402 how do I get at the value of the adjustment in these handlers? To
2403 answer these questions and more, let's start by taking a look at
2404 <tt>struct _GtkAdjustment</tt> itself:
2407 struct _GtkAdjustment
2414 gfloat step_increment;
2415 gfloat page_increment;
2420 The first thing you should know is that there aren't any handy-dandy
2421 macros or accessor functions for getting the <tt/value/ out of an
2422 Adjustment, so you'll have to (horror of horrors) do it like a
2423 <em/real/ C programmer. Don't worry - the <tt>GTK_ADJUSTMENT
2424 (Object)</tt> macro does run-time type checking (as do all the GTK
2425 type-casting macros, actually).
2427 Since, when you set the <tt/value/ of an adjustment, you generally
2428 want the change to be reflected by every widget that uses this
2429 adjustment, GTK provides this convenience function to do this:
2432 void gtk_adjustment_set_value( GtkAdjustment *adjustment,
2436 As mentioned earlier, Adjustment is a subclass of Object just
2437 like all the various widgets, and thus it is able to emit signals.
2438 This is, of course, why updates happen automagically when you share an
2439 adjustment object between a scrollbar and another adjustable widget;
2440 all adjustable widgets connect signal handlers to their adjustment's
2441 <tt/value_changed/ signal, as can your program. Here's the definition
2442 of this signal in <tt/struct _GtkAdjustmentClass/:
2445 void (* value_changed) (GtkAdjustment *adjustment);
2448 The various widgets that use the Adjustment object will emit this
2449 signal on an adjustment whenever they change its value. This happens
2450 both when user input causes the slider to move on a range widget, as
2451 well as when the program explicitly changes the value with
2452 <tt/gtk_adjustment_set_value()/. So, for example, if you have a scale
2453 widget, and you want to change the rotation of a picture whenever its
2454 value changes, you would create a callback like this:
2457 void cb_rotate_picture (GtkAdjustment *adj, GtkWidget *picture)
2459 set_picture_rotation (picture, adj->value);
2463 and connect it to the scale widget's adjustment like this:
2466 gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
2467 GTK_SIGNAL_FUNC (cb_rotate_picture), picture);
2470 What about when a widget reconfigures the <tt/upper/ or <tt/lower/
2471 fields of its adjustment, such as when a user adds more text to a text
2472 widget? In this case, it emits the <tt/changed/ signal, which looks
2476 void (* changed) (GtkAdjustment *adjustment);
2479 Range widgets typically connect a handler to this signal, which
2480 changes their appearance to reflect the change - for example, the size
2481 of the slider in a scrollbar will grow or shrink in inverse proportion
2482 to the difference between the <tt/lower/ and <tt/upper/ values of its
2485 You probably won't ever need to attach a handler to this signal,
2486 unless you're writing a new type of range widget. However, if you
2487 change any of the values in a Adjustment directly, you should emit
2488 this signal on it to reconfigure whatever widgets are using it, like
2492 gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");
2495 Now go forth and adjust!
2499 <!-- ***************************************************************** -->
2500 <sect> Range Widgets<label id="sec_Range_Widgets">
2501 <!-- ***************************************************************** -->
2504 The category of range widgets includes the ubiquitous scrollbar widget
2505 and the less common "scale" widget. Though these two types of widgets
2506 are generally used for different purposes, they are quite similar in
2507 function and implementation. All range widgets share a set of common
2508 graphic elements, each of which has its own X window and receives
2509 events. They all contain a "trough" and a "slider" (what is sometimes
2510 called a "thumbwheel" in other GUI environments). Dragging the slider
2511 with the pointer moves it back and forth within the trough, while
2512 clicking in the trough advances the slider towards the location of the
2513 click, either completely, or by a designated amount, depending on
2514 which mouse button is used.
2516 As mentioned in <ref id="sec_Adjustment" name="Adjustments"> above,
2517 all range widgets are associated with an adjustment object, from which
2518 they calculate the length of the slider and its position within the
2519 trough. When the user manipulates the slider, the range widget will
2520 change the value of the adjustment.
2522 <!-- ----------------------------------------------------------------- -->
2523 <sect1> Scrollbar Widgets
2525 These are your standard, run-of-the-mill scrollbars. These should be
2526 used only for scrolling some other widget, such as a list, a text box,
2527 or a viewport (and it's generally easier to use the scrolled window
2528 widget in most cases). For other purposes, you should use scale
2529 widgets, as they are friendlier and more featureful.
2531 There are separate types for horizontal and vertical scrollbars.
2532 There really isn't much to say about these. You create them with the
2533 following functions, defined in <tt><gtk/gtkhscrollbar.h></tt>
2534 and <tt><gtk/gtkvscrollbar.h></tt>:
2537 GtkWidget *gtk_hscrollbar_new( GtkAdjustment *adjustment );
2539 GtkWidget *gtk_vscrollbar_new( GtkAdjustment *adjustment );
2542 and that's about it (if you don't believe me, look in the header
2543 files!). The <tt/adjustment/ argument can either be a pointer to an
2544 existing Adjustment, or NULL, in which case one will be created for
2545 you. Specifying NULL might actually be useful in this case, if you
2546 wish to pass the newly-created adjustment to the constructor function
2547 of some other widget which will configure it for you, such as a text
2551 <!-- ----------------------------------------------------------------- -->
2552 <sect1> Scale Widgets
2554 Scale widgets are used to allow the user to visually select and
2555 manipulate a value within a specific range. You might want to use a
2556 scale widget, for example, to adjust the magnification level on a
2557 zoomed preview of a picture, or to control the brightness of a color,
2558 or to specify the number of minutes of inactivity before a screensaver
2559 takes over the screen.
2561 <!-- ----------------------------------------------------------------- -->
2562 <sect2>Creating a Scale Widget
2564 As with scrollbars, there are separate widget types for horizontal and
2565 vertical scale widgets. (Most programmers seem to favour horizontal
2566 scale widgets.) Since they work essentially the same way, there's no
2567 need to treat them separately here. The following functions, defined
2568 in <tt><gtk/gtkvscale.h></tt> and
2569 <tt><gtk/gtkhscale.h></tt>, create vertical and horizontal scale
2570 widgets, respectively:
2574 GtkWidget *gtk_vscale_new( GtkAdjustment *adjustment );
2576 GtkWidget *gtk_hscale_new( GtkAdjustment *adjustment );
2580 The <tt/adjustment/ argument can either be an adjustment which has
2581 already been created with <tt/gtk_adjustment_new()/, or <tt/NULL/, in
2582 which case, an anonymous Adjustment is created with all of its
2583 values set to <tt/0.0/ (which isn't very useful in this case). In
2584 order to avoid confusing yourself, you probably want to create your
2585 adjustment with a <tt/page_size/ of <tt/0.0/ so that its <tt/upper/
2586 value actually corresponds to the highest value the user can select.
2587 (If you're <em/already/ thoroughly confused, read the section on <ref
2588 id="sec_Adjustment" name="Adjustments"> again for an explanation of
2589 what exactly adjustments do and how to create and manipulate them.)
2591 <!-- ----------------------------------------------------------------- -->
2592 <sect2> Functions and Signals (well, functions, at least)
2594 Scale widgets can display their current value as a number beside the
2595 trough. The default behaviour is to show the value, but you can change
2596 this with this function:
2599 void gtk_scale_set_draw_value( GtkScale *scale,
2603 As you might have guessed, <tt/draw_value/ is either <tt/TRUE/ or
2604 <tt/FALSE/, with predictable consequences for either one.
2606 The value displayed by a scale widget is rounded to one decimal point
2607 by default, as is the <tt/value/ field in its GtkAdjustment. You can
2612 void gtk_scale_set_digits( GtkScale *scale,
2617 where <tt/digits/ is the number of decimal places you want. You can
2618 set <tt/digits/ to anything you like, but no more than 13 decimal
2619 places will actually be drawn on screen.
2621 Finally, the value can be drawn in different positions
2622 relative to the trough:
2626 void gtk_scale_set_value_pos( GtkScale *scale,
2627 GtkPositionType pos );
2631 The argument <tt/pos/ is of type <tt>GtkPositionType</tt>, which is
2632 defined in <tt><gtk/gtkenums.h></tt>, and can take one of the
2642 If you position the value on the "side" of the trough (e.g., on the
2643 top or bottom of a horizontal scale widget), then it will follow the
2644 slider up and down the trough.
2646 All the preceding functions are defined in
2647 <tt><gtk/gtkscale.h></tt>. The header files for all GTK widgets
2648 are automatically included when you include
2649 <tt><gtk/gtk.h></tt>. But you should look over the header files
2650 of all widgets that interest you,
2655 <!-- ----------------------------------------------------------------- -->
2656 <sect1> Common Range Functions <label id="sec_Range_Functions">
2658 The Range widget class is fairly complicated internally, but, like
2659 all the "base class" widgets, most of its complexity is only
2660 interesting if you want to hack on it. Also, almost all of the
2661 functions and signals it defines are only really used in writing
2662 derived widgets. There are, however, a few useful functions that are
2663 defined in <tt><gtk/gtkrange.h></tt> and will work on all range
2666 <!-- ----------------------------------------------------------------- -->
2667 <sect2> Setting the Update Policy
2669 The "update policy" of a range widget defines at what points during
2670 user interaction it will change the <tt/value/ field of its
2671 Adjustment and emit the "value_changed" signal on this
2672 Adjustment. The update policies, defined in
2673 <tt><gtk/gtkenums.h></tt> as type <tt>enum GtkUpdateType</tt>,
2677 <item>GTK_UPDATE_POLICY_CONTINUOUS - This is the default. The
2678 "value_changed" signal is emitted continuously, i.e., whenever the
2679 slider is moved by even the tiniest amount.
2681 <item>GTK_UPDATE_POLICY_DISCONTINUOUS - The "value_changed" signal is
2682 only emitted once the slider has stopped moving and the user has
2683 released the mouse button.
2685 <item>GTK_UPDATE_POLICY_DELAYED - The "value_changed" signal is emitted
2686 when the user releases the mouse button, or if the slider stops moving
2687 for a short period of time.
2691 The update policy of a range widget can be set by casting it using the
2692 <tt>GTK_RANGE (Widget)</tt> macro and passing it to this function:
2695 void gtk_range_set_update_policy( GtkRange *range,
2696 GtkUpdateType policy) ;
2699 <!-- ----------------------------------------------------------------- -->
2700 <sect2>Getting and Setting Adjustments
2702 Getting and setting the adjustment for a range widget "on the fly" is
2703 done, predictably, with:
2706 GtkAdjustment* gtk_range_get_adjustment( GtkRange *range );
2708 void gtk_range_set_adjustment( GtkRange *range,
2709 GtkAdjustment *adjustment );
2712 <tt/gtk_range_get_adjustment()/ returns a pointer to the adjustment to
2713 which <tt/range/ is connected.
2715 <tt/gtk_range_set_adjustment()/ does absolutely nothing if you pass it
2716 the adjustment that <tt/range/ is already using, regardless of whether
2717 you changed any of its fields or not. If you pass it a new
2718 Adjustment, it will unreference the old one if it exists (possibly
2719 destroying it), connect the appropriate signals to the new one, and
2720 call the private function <tt/gtk_range_adjustment_changed()/, which
2721 will (or at least, is supposed to...) recalculate the size and/or
2722 position of the slider and redraw if necessary. As mentioned in the
2723 section on adjustments, if you wish to reuse the same Adjustment,
2724 when you modify its values directly, you should emit the "changed"
2725 signal on it, like this:
2728 gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");
2733 <!-- ----------------------------------------------------------------- -->
2734 <sect1> Key and Mouse bindings
2736 All of the GTK range widgets react to mouse clicks in more or less
2737 the same way. Clicking button-1 in the trough will cause its
2738 adjustment's <tt/page_increment/ to be added or subtracted from its
2739 <tt/value/, and the slider to be moved accordingly. Clicking mouse
2740 button-2 in the trough will jump the slider to the point at which the
2741 button was clicked. Clicking any button on a scrollbar's arrows will
2742 cause its adjustment's value to change <tt/step_increment/ at a time.
2744 It may take a little while to get used to, but by default, scrollbars
2745 as well as scale widgets can take the keyboard focus in GTK. If you
2746 think your users will find this too confusing, you can always disable
2747 this by unsetting the <tt/GTK_CAN_FOCUS/ flag on the scrollbar, like
2751 GTK_WIDGET_UNSET_FLAGS (scrollbar, GTK_CAN_FOCUS);
2754 The key bindings (which are, of course, only active when the widget
2755 has focus) are slightly different between horizontal and vertical
2756 range widgets, for obvious reasons. They are also not quite the same
2757 for scale widgets as they are for scrollbars, for somewhat less
2758 obvious reasons (possibly to avoid confusion between the keys for
2759 horizontal and vertical scrollbars in scrolled windows, where both
2760 operate on the same area).
2762 <sect2> Vertical Range Widgets
2764 All vertical range widgets can be operated with the up and down arrow
2765 keys, as well as with the <tt/Page Up/ and <tt/Page Down/ keys. The
2766 arrows move the slider up and down by <tt/step_increment/, while
2767 <tt/Page Up/ and <tt/Page Down/ move it by <tt/page_increment/.
2769 The user can also move the slider all the way to one end or the other
2770 of the trough using the keyboard. With the VScale widget, this is
2771 done with the <tt/Home/ and <tt/End/ keys, whereas with the
2772 VScrollbar widget, this is done by typing <tt>Control-Page Up</tt>
2773 and <tt>Control-Page Down</tt>.
2775 <!-- ----------------------------------------------------------------- -->
2776 <sect2> Horizontal Range Widgets
2778 The left and right arrow keys work as you might expect in these
2779 widgets, moving the slider back and forth by <tt/step_increment/. The
2780 <tt/Home/ and <tt/End/ keys move the slider to the ends of the trough.
2781 For the HScale widget, moving the slider by <tt/page_increment/ is
2782 accomplished with <tt>Control-Left</tt> and <tt>Control-Right</tt>,
2783 while for HScrollbar, it's done with <tt>Control-Home</tt> and
2784 <tt>Control-End</tt>.
2788 <!-- ----------------------------------------------------------------- -->
2789 <sect1> Example<label id="sec_Range_Example">
2791 This example is a somewhat modified version of the "range controls"
2792 test from <tt/testgtk.c/. It basically puts up a window with three
2793 range widgets all connected to the same adjustment, and a couple of
2794 controls for adjusting some of the parameters mentioned above and in
2795 the section on adjustments, so you can see how they affect the way
2796 these widgets work for the user.
2799 /* example-start rangewidgets rangewidgets.c */
2801 #include <gtk/gtk.h>
2803 GtkWidget *hscale, *vscale;
2805 void cb_pos_menu_select( GtkWidget *item,
2806 GtkPositionType pos )
2808 /* Set the value position on both scale widgets */
2809 gtk_scale_set_value_pos (GTK_SCALE (hscale), pos);
2810 gtk_scale_set_value_pos (GTK_SCALE (vscale), pos);
2813 void cb_update_menu_select( GtkWidget *item,
2814 GtkUpdateType policy )
2816 /* Set the update policy for both scale widgets */
2817 gtk_range_set_update_policy (GTK_RANGE (hscale), policy);
2818 gtk_range_set_update_policy (GTK_RANGE (vscale), policy);
2821 void cb_digits_scale( GtkAdjustment *adj )
2823 /* Set the number of decimal places to which adj->value is rounded */
2824 gtk_scale_set_digits (GTK_SCALE (hscale), (gint) adj->value);
2825 gtk_scale_set_digits (GTK_SCALE (vscale), (gint) adj->value);
2828 void cb_page_size( GtkAdjustment *get,
2829 GtkAdjustment *set )
2831 /* Set the page size and page increment size of the sample
2832 * adjustment to the value specified by the "Page Size" scale */
2833 set->page_size = get->value;
2834 set->page_increment = get->value;
2835 /* Now emit the "changed" signal to reconfigure all the widgets that
2836 * are attached to this adjustment */
2837 gtk_signal_emit_by_name (GTK_OBJECT (set), "changed");
2840 void cb_draw_value( GtkToggleButton *button )
2842 /* Turn the value display on the scale widgets off or on depending
2843 * on the state of the checkbutton */
2844 gtk_scale_set_draw_value (GTK_SCALE (hscale), button->active);
2845 gtk_scale_set_draw_value (GTK_SCALE (vscale), button->active);
2848 /* Convenience functions */
2850 GtkWidget *make_menu_item( gchar *name,
2851 GtkSignalFunc callback,
2856 item = gtk_menu_item_new_with_label (name);
2857 gtk_signal_connect (GTK_OBJECT (item), "activate",
2859 gtk_widget_show (item);
2864 void scale_set_default_values( GtkScale *scale )
2866 gtk_range_set_update_policy (GTK_RANGE (scale),
2867 GTK_UPDATE_CONTINUOUS);
2868 gtk_scale_set_digits (scale, 1);
2869 gtk_scale_set_value_pos (scale, GTK_POS_TOP);
2870 gtk_scale_set_draw_value (scale, TRUE);
2873 /* makes the sample window */
2875 void create_range_controls( void )
2878 GtkWidget *box1, *box2, *box3;
2880 GtkWidget *scrollbar;
2881 GtkWidget *separator;
2882 GtkWidget *opt, *menu, *item;
2885 GtkObject *adj1, *adj2;
2887 /* Standard window-creating stuff */
2888 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2889 gtk_signal_connect (GTK_OBJECT (window), "destroy",
2890 GTK_SIGNAL_FUNC(gtk_main_quit),
2892 gtk_window_set_title (GTK_WINDOW (window), "range controls");
2894 box1 = gtk_vbox_new (FALSE, 0);
2895 gtk_container_add (GTK_CONTAINER (window), box1);
2896 gtk_widget_show (box1);
2898 box2 = gtk_hbox_new (FALSE, 10);
2899 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2900 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2901 gtk_widget_show (box2);
2903 /* value, lower, upper, step_increment, page_increment, page_size */
2904 /* Note that the page_size value only makes a difference for
2905 * scrollbar widgets, and the highest value you'll get is actually
2906 * (upper - page_size). */
2907 adj1 = gtk_adjustment_new (0.0, 0.0, 101.0, 0.1, 1.0, 1.0);
2909 vscale = gtk_vscale_new (GTK_ADJUSTMENT (adj1));
2910 scale_set_default_values (GTK_SCALE (vscale));
2911 gtk_box_pack_start (GTK_BOX (box2), vscale, TRUE, TRUE, 0);
2912 gtk_widget_show (vscale);
2914 box3 = gtk_vbox_new (FALSE, 10);
2915 gtk_box_pack_start (GTK_BOX (box2), box3, TRUE, TRUE, 0);
2916 gtk_widget_show (box3);
2918 /* Reuse the same adjustment */
2919 hscale = gtk_hscale_new (GTK_ADJUSTMENT (adj1));
2920 gtk_widget_set_usize (GTK_WIDGET (hscale), 200, 30);
2921 scale_set_default_values (GTK_SCALE (hscale));
2922 gtk_box_pack_start (GTK_BOX (box3), hscale, TRUE, TRUE, 0);
2923 gtk_widget_show (hscale);
2925 /* Reuse the same adjustment again */
2926 scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adj1));
2927 /* Notice how this causes the scales to always be updated
2928 * continuously when the scrollbar is moved */
2929 gtk_range_set_update_policy (GTK_RANGE (scrollbar),
2930 GTK_UPDATE_CONTINUOUS);
2931 gtk_box_pack_start (GTK_BOX (box3), scrollbar, TRUE, TRUE, 0);
2932 gtk_widget_show (scrollbar);
2934 box2 = gtk_hbox_new (FALSE, 10);
2935 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2936 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2937 gtk_widget_show (box2);
2939 /* A checkbutton to control whether the value is displayed or not */
2940 button = gtk_check_button_new_with_label("Display value on scale widgets");
2941 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2942 gtk_signal_connect (GTK_OBJECT (button), "toggled",
2943 GTK_SIGNAL_FUNC(cb_draw_value), NULL);
2944 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2945 gtk_widget_show (button);
2947 box2 = gtk_hbox_new (FALSE, 10);
2948 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2950 /* An option menu to change the position of the value */
2951 label = gtk_label_new ("Scale Value Position:");
2952 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
2953 gtk_widget_show (label);
2955 opt = gtk_option_menu_new();
2956 menu = gtk_menu_new();
2958 item = make_menu_item ("Top",
2959 GTK_SIGNAL_FUNC(cb_pos_menu_select),
2960 GINT_TO_POINTER (GTK_POS_TOP));
2961 gtk_menu_append (GTK_MENU (menu), item);
2963 item = make_menu_item ("Bottom", GTK_SIGNAL_FUNC (cb_pos_menu_select),
2964 GINT_TO_POINTER (GTK_POS_BOTTOM));
2965 gtk_menu_append (GTK_MENU (menu), item);
2967 item = make_menu_item ("Left", GTK_SIGNAL_FUNC (cb_pos_menu_select),
2968 GINT_TO_POINTER (GTK_POS_LEFT));
2969 gtk_menu_append (GTK_MENU (menu), item);
2971 item = make_menu_item ("Right", GTK_SIGNAL_FUNC (cb_pos_menu_select),
2972 GINT_TO_POINTER (GTK_POS_RIGHT));
2973 gtk_menu_append (GTK_MENU (menu), item);
2975 gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
2976 gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
2977 gtk_widget_show (opt);
2979 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2980 gtk_widget_show (box2);
2982 box2 = gtk_hbox_new (FALSE, 10);
2983 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2985 /* Yet another option menu, this time for the update policy of the
2987 label = gtk_label_new ("Scale Update Policy:");
2988 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
2989 gtk_widget_show (label);
2991 opt = gtk_option_menu_new();
2992 menu = gtk_menu_new();
2994 item = make_menu_item ("Continuous",
2995 GTK_SIGNAL_FUNC (cb_update_menu_select),
2996 GINT_TO_POINTER (GTK_UPDATE_CONTINUOUS));
2997 gtk_menu_append (GTK_MENU (menu), item);
2999 item = make_menu_item ("Discontinuous",
3000 GTK_SIGNAL_FUNC (cb_update_menu_select),
3001 GINT_TO_POINTER (GTK_UPDATE_DISCONTINUOUS));
3002 gtk_menu_append (GTK_MENU (menu), item);
3004 item = make_menu_item ("Delayed",
3005 GTK_SIGNAL_FUNC (cb_update_menu_select),
3006 GINT_TO_POINTER (GTK_UPDATE_DELAYED));
3007 gtk_menu_append (GTK_MENU (menu), item);
3009 gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
3010 gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
3011 gtk_widget_show (opt);
3013 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3014 gtk_widget_show (box2);
3016 box2 = gtk_hbox_new (FALSE, 10);
3017 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3019 /* An HScale widget for adjusting the number of digits on the
3021 label = gtk_label_new ("Scale Digits:");
3022 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
3023 gtk_widget_show (label);
3025 adj2 = gtk_adjustment_new (1.0, 0.0, 5.0, 1.0, 1.0, 0.0);
3026 gtk_signal_connect (GTK_OBJECT (adj2), "value_changed",
3027 GTK_SIGNAL_FUNC (cb_digits_scale), NULL);
3028 scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
3029 gtk_scale_set_digits (GTK_SCALE (scale), 0);
3030 gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
3031 gtk_widget_show (scale);
3033 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3034 gtk_widget_show (box2);
3036 box2 = gtk_hbox_new (FALSE, 10);
3037 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3039 /* And, one last HScale widget for adjusting the page size of the
3041 label = gtk_label_new ("Scrollbar Page Size:");
3042 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
3043 gtk_widget_show (label);
3045 adj2 = gtk_adjustment_new (1.0, 1.0, 101.0, 1.0, 1.0, 0.0);
3046 gtk_signal_connect (GTK_OBJECT (adj2), "value_changed",
3047 GTK_SIGNAL_FUNC (cb_page_size), adj1);
3048 scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
3049 gtk_scale_set_digits (GTK_SCALE (scale), 0);
3050 gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
3051 gtk_widget_show (scale);
3053 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3054 gtk_widget_show (box2);
3056 separator = gtk_hseparator_new ();
3057 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
3058 gtk_widget_show (separator);
3060 box2 = gtk_vbox_new (FALSE, 10);
3061 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3062 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
3063 gtk_widget_show (box2);
3065 button = gtk_button_new_with_label ("Quit");
3066 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
3067 GTK_SIGNAL_FUNC(gtk_main_quit),
3069 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
3070 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
3071 gtk_widget_grab_default (button);
3072 gtk_widget_show (button);
3074 gtk_widget_show (window);
3080 gtk_init(&argc, &argv);
3082 create_range_controls();
3092 You will notice that the program does not call <tt/gtk_signal_connect/
3093 for the "delete_event", but only for the "destroy" signal. This will
3094 still perform the desired function, because an unhandled
3095 "delete_event" will result in a "destroy" signal being given to the
3101 <!-- ***************************************************************** -->
3102 <sect> Miscellaneous Widgets
3103 <!-- ***************************************************************** -->
3105 <!-- ----------------------------------------------------------------- -->
3108 Labels are used a lot in GTK, and are relatively simple. Labels emit
3109 no signals as they do not have an associated X window. If you need to
3110 catch signals, or do clipping, place it inside a <ref id="sec_EventBox"
3111 name="EventBox"> widget or a Button widget.
3113 To create a new label, use:
3116 GtkWidget *gtk_label_new( char *str );
3119 The sole argument is the string you wish the label to display.
3121 To change the label's text after creation, use the function:
3124 void gtk_label_set_text( GtkLabel *label,
3128 The first argument is the label you created previously (cast
3129 using the <tt/GTK_LABEL()/ macro), and the second is the new string.
3131 The space needed for the new string will be automatically adjusted if
3132 needed. You can produce multi-line labels by putting line breaks in
3135 To retrieve the current string, use:
3138 void gtk_label_get( GtkLabel *label,
3142 The first argument is the label you've created, and the second,
3143 the return for the string. Do not free the return string, as it is
3144 used internally by GTK.
3146 The label text can be justified using:
3149 void gtk_label_set_justify( GtkLabel *label,
3150 GtkJustification jtype );
3153 Values for <tt/jtype/ are:
3157 GTK_JUSTIFY_CENTER (the default)
3161 The label widget is also capable of line wrapping the text
3162 automatically. This can be activated using:
3165 void gtk_label_set_line_wrap (GtkLabel *label,
3169 The <tt/wrap/ argument takes a TRUE or FALSE value.
3171 If you want your label underlined, then you can set a pattern on the
3175 void gtk_label_set_pattern (GtkLabel *label,
3176 const gchar *pattern);
3179 The pattern argument indicates how the underlining should look. It
3180 consists of a string of underscore and space characters. An underscore
3181 indicates that the corresponding character in the label should be
3182 underlined. For example, the string <verb/"__ __"/ would underline the
3183 first two characters and eight and ninth characters.
3185 Below is a short example to illustrate these functions. This example
3186 makes use of the Frame widget to better demonstrate the label
3187 styles. You can ignore this for now as the <ref id="sec_Frames"
3188 name="Frame"> widget is explained later on.
3191 /* example-start label label.c */
3193 #include <gtk/gtk.h>
3198 static GtkWidget *window = NULL;
3204 /* Initialise GTK */
3205 gtk_init(&argc, &argv);
3207 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3208 gtk_signal_connect (GTK_OBJECT (window), "destroy",
3209 GTK_SIGNAL_FUNC(gtk_main_quit),
3212 gtk_window_set_title (GTK_WINDOW (window), "Label");
3213 vbox = gtk_vbox_new (FALSE, 5);
3214 hbox = gtk_hbox_new (FALSE, 5);
3215 gtk_container_add (GTK_CONTAINER (window), hbox);
3216 gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
3217 gtk_container_set_border_width (GTK_CONTAINER (window), 5);
3219 frame = gtk_frame_new ("Normal Label");
3220 label = gtk_label_new ("This is a Normal label");
3221 gtk_container_add (GTK_CONTAINER (frame), label);
3222 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3224 frame = gtk_frame_new ("Multi-line Label");
3225 label = gtk_label_new ("This is a Multi-line label.\nSecond line\n" \
3227 gtk_container_add (GTK_CONTAINER (frame), label);
3228 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3230 frame = gtk_frame_new ("Left Justified Label");
3231 label = gtk_label_new ("This is a Left-Justified\n" \
3232 "Multi-line label.\nThird line");
3233 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
3234 gtk_container_add (GTK_CONTAINER (frame), label);
3235 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3237 frame = gtk_frame_new ("Right Justified Label");
3238 label = gtk_label_new ("This is a Right-Justified\nMulti-line label.\n" \
3239 "Fourth line, (j/k)");
3240 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT);
3241 gtk_container_add (GTK_CONTAINER (frame), label);
3242 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3244 vbox = gtk_vbox_new (FALSE, 5);
3245 gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
3246 frame = gtk_frame_new ("Line wrapped label");
3247 label = gtk_label_new ("This is an example of a line-wrapped label. It " \
3248 "should not be taking up the entire " /* big space to test spacing */\
3249 "width allocated to it, but automatically " \
3250 "wraps the words to fit. " \
3251 "The time has come, for all good men, to come to " \
3252 "the aid of their party. " \
3253 "The sixth sheik's six sheep's sick.\n" \
3254 " It supports multiple paragraphs correctly, " \
3255 "and correctly adds "\
3256 "many extra spaces. ");
3257 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
3258 gtk_container_add (GTK_CONTAINER (frame), label);
3259 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3261 frame = gtk_frame_new ("Filled, wrapped label");
3262 label = gtk_label_new ("This is an example of a line-wrapped, filled label. " \
3263 "It should be taking "\
3264 "up the entire width allocated to it. " \
3265 "Here is a sentence to prove "\
3266 "my point. Here is another sentence. "\
3267 "Here comes the sun, do de do de do.\n"\
3268 " This is a new paragraph.\n"\
3269 " This is another newer, longer, better " \
3270 "paragraph. It is coming to an end, "\
3272 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_FILL);
3273 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
3274 gtk_container_add (GTK_CONTAINER (frame), label);
3275 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3277 frame = gtk_frame_new ("Underlined label");
3278 label = gtk_label_new ("This label is underlined!\n"
3279 "This one is underlined in quite a funky fashion");
3280 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
3281 gtk_label_set_pattern (GTK_LABEL (label),
3282 "_________________________ _ _________ _ ______ __ _______ ___");
3283 gtk_container_add (GTK_CONTAINER (frame), label);
3284 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3286 gtk_widget_show_all (window);
3295 <!-- ----------------------------------------------------------------- -->
3298 The Arrow widget draws an arrowhead, facing in a number of possible
3299 directions and having a number of possible styles. It can be very
3300 useful when placed on a button in many applications. Like the Label
3301 widget, it emits no signals.
3303 There are only two functions for manipulating an Arrow widget:
3306 GtkWidget *gtk_arrow_new( GtkArrowType arrow_type,
3307 GtkShadowType shadow_type );
3309 void gtk_arrow_set( GtkArrow *arrow,
3310 GtkArrowType arrow_type,
3311 GtkShadowType shadow_type );
3314 The first creates a new arrow widget with the indicated type and
3315 appearance. The second allows these values to be altered
3316 retrospectively. The <tt/arrow_type/ argument may take one of the
3326 These values obviously indicate the direction in which the arrow will
3327 point. The <tt/shadow_type/ argument may take one of these values:
3331 GTK_SHADOW_OUT (the default)
3332 GTK_SHADOW_ETCHED_IN
3333 GTK_SHADOW_ETCHED_OUT
3336 Here's a brief example to illustrate their use.
3339 /* example-start arrow arrow.c */
3341 #include <gtk/gtk.h>
3343 /* Create an Arrow widget with the specified parameters
3344 * and pack it into a button */
3345 GtkWidget *create_arrow_button( GtkArrowType arrow_type,
3346 GtkShadowType shadow_type )
3351 button = gtk_button_new();
3352 arrow = gtk_arrow_new (arrow_type, shadow_type);
3354 gtk_container_add (GTK_CONTAINER (button), arrow);
3356 gtk_widget_show(button);
3357 gtk_widget_show(arrow);
3365 /* GtkWidget is the storage type for widgets */
3370 /* Initialize the toolkit */
3371 gtk_init (&argc, &argv);
3373 /* Create a new window */
3374 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3376 gtk_window_set_title (GTK_WINDOW (window), "Arrow Buttons");
3378 /* It's a good idea to do this for all windows. */
3379 gtk_signal_connect (GTK_OBJECT (window), "destroy",
3380 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
3382 /* Sets the border width of the window. */
3383 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
3385 /* Create a box to hold the arrows/buttons */
3386 box = gtk_hbox_new (FALSE, 0);
3387 gtk_container_set_border_width (GTK_CONTAINER (box), 2);
3388 gtk_container_add (GTK_CONTAINER (window), box);
3390 /* Pack and show all our widgets */
3391 gtk_widget_show(box);
3393 button = create_arrow_button(GTK_ARROW_UP, GTK_SHADOW_IN);
3394 gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3396 button = create_arrow_button(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
3397 gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3399 button = create_arrow_button(GTK_ARROW_LEFT, GTK_SHADOW_ETCHED_IN);
3400 gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3402 button = create_arrow_button(GTK_ARROW_RIGHT, GTK_SHADOW_ETCHED_OUT);
3403 gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3405 gtk_widget_show (window);
3407 /* Rest in gtk_main and wait for the fun to begin! */
3415 <!-- ----------------------------------------------------------------- -->
3416 <sect1>The Tooltips Object
3418 These are the little text strings that pop up when you leave your
3419 pointer over a button or other widget for a few seconds. They are easy
3420 to use, so I will just explain them without giving an example. If you
3421 want to see some code, take a look at the testgtk.c program
3422 distributed with GTK.
3424 Widgets that do not receive events (widgets that do not have their
3425 own window) will not work with tooltips.
3427 The first call you will use creates a new tooltip. You only need to do
3428 this once for a set of tooltips as the <tt/GtkTooltips/ object this
3429 function returns can be used to create multiple tooltips.
3432 GtkTooltips *gtk_tooltips_new( void );
3435 Once you have created a new tooltip, and the widget you wish to use it
3436 on, simply use this call to set it:
3439 void gtk_tooltips_set_tip( GtkTooltips *tooltips,
3441 const gchar *tip_text,
3442 const gchar *tip_private );
3445 The first argument is the tooltip you've already created, followed by
3446 the widget you wish to have this tooltip pop up for, and the text you
3447 wish it to say. The last argument is a text string that can be used as
3448 an identifier when using GtkTipsQuery to implement context sensitive
3449 help. For now, you can set it to NULL.
3451 <!-- TODO: sort out what how to do the context sensitive help -->
3453 Here's a short example:
3456 GtkTooltips *tooltips;
3461 tooltips = gtk_tooltips_new ();
3462 button = gtk_button_new_with_label ("button 1");
3466 gtk_tooltips_set_tip (tooltips, button, "This is button 1", NULL);
3469 There are other calls that can be used with tooltips. I will just list
3470 them with a brief description of what they do.
3473 void gtk_tooltips_enable( GtkTooltips *tooltips );
3476 Enable a disabled set of tooltips.
3479 void gtk_tooltips_disable( GtkTooltips *tooltips );
3482 Disable an enabled set of tooltips.
3485 void gtk_tooltips_set_delay( GtkTooltips *tooltips,
3490 Sets how many milliseconds you have to hold your pointer over the
3491 widget before the tooltip will pop up. The default is 500
3492 milliseconds (half a second).
3495 void gtk_tooltips_set_colors( GtkTooltips *tooltips,
3496 GdkColor *background,
3497 GdkColor *foreground );
3500 Set the foreground and background color of the tooltips.
3502 And that's all the functions associated with tooltips. More than
3503 you'll ever want to know :-)
3505 <!-- ----------------------------------------------------------------- -->
3506 <sect1> Progress Bars <label id="sec_ProgressBar">
3508 Progress bars are used to show the status of an operation. They are
3509 pretty easy to use, as you will see with the code below. But first
3510 lets start out with the calls to create a new progress bar.
3512 There are two ways to create a progress bar, one simple that takes
3513 no arguments, and one that takes an Adjustment object as an
3514 argument. If the former is used, the progress bar creates its own
3518 GtkWidget *gtk_progress_bar_new( void );
3520 GtkWidget *gtk_progress_bar_new_with_adjustment( GtkAdjustment *adjustment );
3523 The second method has the advantage that we can use the adjustment
3524 object to specify our own range parameters for the progress bar.
3526 The adjustment of a progress object can be changed dynamically using:
3529 void gtk_progress_set_adjustment( GtkProgress *progress,
3530 GtkAdjustment *adjustment );
3533 Now that the progress bar has been created we can use it.
3536 void gtk_progress_bar_update( GtkProgressBar *pbar,
3537 gfloat percentage );
3540 The first argument is the progress bar you wish to operate on, and the
3541 second argument is the amount "completed", meaning the amount the
3542 progress bar has been filled from 0-100%. This is passed to the
3543 function as a real number ranging from 0 to 1.
3545 GTK v1.2 has added new functionality to the progress bar that enables
3546 it to display its value in different ways, and to inform the user of
3547 its current value and its range.
3549 A progress bar may be set to one of a number of orientations using the
3553 void gtk_progress_bar_set_orientation( GtkProgressBar *pbar,
3554 GtkProgressBarOrientation orientation );
3557 The <tt/orientation/ argument may take one of the following
3558 values to indicate the direction in which the progress bar moves:
3561 GTK_PROGRESS_LEFT_TO_RIGHT
3562 GTK_PROGRESS_RIGHT_TO_LEFT
3563 GTK_PROGRESS_BOTTOM_TO_TOP
3564 GTK_PROGRESS_TOP_TO_BOTTOM
3567 When used as a measure of how far a process has progressed, the
3568 ProgressBar can be set to display its value in either a continuous
3569 or discrete mode. In continuous mode, the progress bar is updated for
3570 each value. In discrete mode, the progress bar is updated in a number
3571 of discrete blocks. The number of blocks is also configurable.
3573 The style of a progress bar can be set using the following function.
3576 void gtk_progress_bar_set_bar_style( GtkProgressBar *pbar,
3577 GtkProgressBarStyle style );
3580 The <tt/style/ parameter can take one of two values:
3583 GTK_PROGRESS_CONTINUOUS
3584 GTK_PROGRESS_DISCRETE
3587 The number of discrete blocks can be set by calling
3590 void gtk_progress_bar_set_discrete_blocks( GtkProgressBar *pbar,
3594 As well as indicating the amount of progress that has occured, the
3595 progress bar may be set to just indicate that there is some
3596 activity. This can be useful in situations where progress cannot be
3597 measured against a value range. Activity mode is not affected by the
3598 bar style that is described above, and overrides it. This mode is
3599 either TRUE or FALSE, and is selected by the following function.
3602 void gtk_progress_set_activity_mode( GtkProgress *progress,
3603 guint activity_mode );
3606 The step size of the activity indicator, and the number of blocks are
3607 set using the following functions.
3610 void gtk_progress_bar_set_activity_step( GtkProgressBar *pbar,
3613 void gtk_progress_bar_set_activity_blocks( GtkProgressBar *pbar,
3617 When in continuous mode, the progress bar can also display a
3618 configurable text string within its trough, using the following
3622 void gtk_progress_set_format_string( GtkProgress *progress,
3626 The <tt/format/ argument is similiar to one that would be used in a C
3627 <tt/printf/ statement. The following directives may be used within the
3631 <item> %p - percentage
3633 <item> %l - lower range value
3634 <item> %u - upper range value
3637 The displaying of this text string can be toggled using:
3640 void gtk_progress_set_show_text( GtkProgress *progress,
3644 The <tt/show_text/ argument is a boolean TRUE/FALSE value. The
3645 appearance of the text can be modified further using:
3648 void gtk_progress_set_text_alignment( GtkProgress *progress,
3653 The <tt/x_align/ and <tt/y_align/ arguments take values between 0.0
3654 and 1.0. Their values indicate the position of the text string within
3655 the trough. Values of 0.0 for both would place the string in the top
3656 left hand corner; values of 0.5 (the default) centres the text, and
3657 values of 1.0 places the text in the lower right hand corner.
3659 The current text setting of a progress object can be retrieved using
3660 the current or a specified adjustment value using the following two
3661 functions. The character string returned by these functions should be
3662 freed by the application (using the g_free() function). These
3663 functions return the formatted string that would be displayed within
3667 gchar *gtk_progress_get_current_text( GtkProgress *progress );
3669 gchar *gtk_progress_get_text_from_value( GtkProgress *progress,
3673 There is yet another way to change the range and value of a progress
3674 object using the following function:
3677 void gtk_progress_configure( GtkProgress *progress,
3683 This function provides quite a simple interface to the range and value
3684 of a progress object.
3686 The remaining functions can be used to get and set the current value
3687 of a progess object in various types and formats:
3690 void gtk_progress_set_percentage( GtkProgress *progress,
3691 gfloat percentage );
3693 void gtk_progress_set_value( GtkProgress *progress,
3696 gfloat gtk_progress_get_value( GtkProgress *progress );
3698 gfloat gtk_progress_get_current_percentage( GtkProgress *progress );
3700 gfloat gtk_progress_get_percentage_from_value( GtkProgress *progress,
3704 These functions are pretty self explanatory. The last function uses
3705 the the adjustment of the specified progess object to compute the
3706 percentage value of the given range value.
3708 Progress Bars are usually used with timeouts or other such functions
3709 (see section on <ref id="sec_timeouts" name="Timeouts, I/O and Idle
3710 Functions">) to give the illusion of multitasking. All will employ the
3711 gtk_progress_bar_update function in the same manner.
3713 Here is an example of the progress bar, updated using timeouts. This
3714 code also shows you how to reset the Progress Bar.
3717 /* example-start progressbar progressbar.c */
3719 #include <gtk/gtk.h>
3721 typedef struct _ProgressData {
3727 /* Update the value of the progress bar so that we get
3729 gint progress_timeout( gpointer data )
3734 /* Calculate the value of the progress bar using the
3735 * value range set in the adjustment object */
3737 new_val = gtk_progress_get_value( GTK_PROGRESS(data) ) + 1;
3739 adj = GTK_PROGRESS (data)->adjustment;
3740 if (new_val > adj->upper)
3741 new_val = adj->lower;
3743 /* Set the new value */
3744 gtk_progress_set_value (GTK_PROGRESS (data), new_val);
3746 /* As this is a timeout function, return TRUE so that it
3747 * continues to get called */
3751 /* Callback that toggles the text display within the progress
3753 void toggle_show_text( GtkWidget *widget,
3754 ProgressData *pdata )
3756 gtk_progress_set_show_text (GTK_PROGRESS (pdata->pbar),
3757 GTK_TOGGLE_BUTTON (widget)->active);
3760 /* Callback that toggles the activity mode of the progress
3762 void toggle_activity_mode( GtkWidget *widget,
3763 ProgressData *pdata )
3765 gtk_progress_set_activity_mode (GTK_PROGRESS (pdata->pbar),
3766 GTK_TOGGLE_BUTTON (widget)->active);
3769 /* Callback that toggles the continuous mode of the progress
3771 void set_continuous_mode( GtkWidget *widget,
3772 ProgressData *pdata )
3774 gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
3775 GTK_PROGRESS_CONTINUOUS);
3778 /* Callback that toggles the discrete mode of the progress
3780 void set_discrete_mode( GtkWidget *widget,
3781 ProgressData *pdata )
3783 gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
3784 GTK_PROGRESS_DISCRETE);
3787 /* Clean up allocated memory and remove the timer */
3788 void destroy_progress( GtkWidget *widget,
3789 ProgressData *pdata)
3791 gtk_timeout_remove (pdata->timer);
3793 pdata->window = NULL;
3801 ProgressData *pdata;
3803 GtkWidget *separator;
3810 gtk_init (&argc, &argv);
3812 /* Allocate memory for the data that is passwd to the callbacks */
3813 pdata = g_malloc( sizeof(ProgressData) );
3815 pdata->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3816 gtk_window_set_policy (GTK_WINDOW (pdata->window), FALSE, FALSE, TRUE);
3818 gtk_signal_connect (GTK_OBJECT (pdata->window), "destroy",
3819 GTK_SIGNAL_FUNC (destroy_progress),
3821 gtk_window_set_title (GTK_WINDOW (pdata->window), "GtkProgressBar");
3822 gtk_container_set_border_width (GTK_CONTAINER (pdata->window), 0);
3824 vbox = gtk_vbox_new (FALSE, 5);
3825 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
3826 gtk_container_add (GTK_CONTAINER (pdata->window), vbox);
3827 gtk_widget_show(vbox);
3829 /* Create a centering alignment object */
3830 align = gtk_alignment_new (0.5, 0.5, 0, 0);
3831 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 5);
3832 gtk_widget_show(align);
3834 /* Create a Adjusment object to hold the range of the
3836 adj = (GtkAdjustment *) gtk_adjustment_new (0, 1, 150, 0, 0, 0);
3838 /* Create the GtkProgressBar using the adjustment */
3839 pdata->pbar = gtk_progress_bar_new_with_adjustment (adj);
3841 /* Set the format of the string that can be displayed in the
3842 * trough of the progress bar:
3845 * %l - lower range value
3846 * %u - upper range value */
3847 gtk_progress_set_format_string (GTK_PROGRESS (pdata->pbar),
3848 "%v from [%l-%u] (=%p%%)");
3849 gtk_container_add (GTK_CONTAINER (align), pdata->pbar);
3850 gtk_widget_show(pdata->pbar);
3852 /* Add a timer callback to update the value of the progress bar */
3853 pdata->timer = gtk_timeout_add (100, progress_timeout, pdata->pbar);
3855 separator = gtk_hseparator_new ();
3856 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
3857 gtk_widget_show(separator);
3859 /* rows, columns, homogeneous */
3860 table = gtk_table_new (2, 3, FALSE);
3861 gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0);
3862 gtk_widget_show(table);
3864 /* Add a check button to select displaying of the trough text */
3865 check = gtk_check_button_new_with_label ("Show text");
3866 gtk_table_attach (GTK_TABLE (table), check, 0, 1, 0, 1,
3867 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3869 gtk_signal_connect (GTK_OBJECT (check), "clicked",
3870 GTK_SIGNAL_FUNC (toggle_show_text),
3872 gtk_widget_show(check);
3874 /* Add a check button to toggle activity mode */
3875 check = gtk_check_button_new_with_label ("Activity mode");
3876 gtk_table_attach (GTK_TABLE (table), check, 0, 1, 1, 2,
3877 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3879 gtk_signal_connect (GTK_OBJECT (check), "clicked",
3880 GTK_SIGNAL_FUNC (toggle_activity_mode),
3882 gtk_widget_show(check);
3884 separator = gtk_vseparator_new ();
3885 gtk_table_attach (GTK_TABLE (table), separator, 1, 2, 0, 2,
3886 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3888 gtk_widget_show(separator);
3890 /* Add a radio button to select continuous display mode */
3891 button = gtk_radio_button_new_with_label (NULL, "Continuous");
3892 gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1,
3893 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3895 gtk_signal_connect (GTK_OBJECT (button), "clicked",
3896 GTK_SIGNAL_FUNC (set_continuous_mode),
3898 gtk_widget_show (button);
3900 /* Add a radio button to select discrete display mode */
3901 button = gtk_radio_button_new_with_label(
3902 gtk_radio_button_group (GTK_RADIO_BUTTON (button)),
3904 gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2,
3905 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3907 gtk_signal_connect (GTK_OBJECT (button), "clicked",
3908 GTK_SIGNAL_FUNC (set_discrete_mode),
3910 gtk_widget_show (button);
3912 separator = gtk_hseparator_new ();
3913 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
3914 gtk_widget_show(separator);
3916 /* Add a button to exit the program */
3917 button = gtk_button_new_with_label ("close");
3918 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
3919 (GtkSignalFunc) gtk_widget_destroy,
3920 GTK_OBJECT (pdata->window));
3921 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
3923 /* This makes it so the button is the default. */
3924 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
3926 /* This grabs this button to be the default button. Simply hitting
3927 * the "Enter" key will cause this button to activate. */
3928 gtk_widget_grab_default (button);
3929 gtk_widget_show(button);
3931 gtk_widget_show (pdata->window);
3940 <!-- ----------------------------------------------------------------- -->
3943 The Dialog widget is very simple, and is actually just a window with a
3944 few things pre-packed into it for you. The structure for a Dialog is:
3952 GtkWidget *action_area;
3956 So you see, it simply creates a window, and then packs a vbox into the
3957 top, which contains a separator and then an hbox called the
3960 The Dialog widget can be used for pop-up messages to the user, and
3961 other similar tasks. It is really basic, and there is only one
3962 function for the dialog box, which is:
3965 GtkWidget *gtk_dialog_new( void );
3968 So to create a new dialog box, use,
3972 window = gtk_dialog_new ();
3975 This will create the dialog box, and it is now up to you to use it.
3976 You could pack a button in the action_area by doing something like this:
3980 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area),
3981 button, TRUE, TRUE, 0);
3982 gtk_widget_show (button);
3985 And you could add to the vbox area by packing, for instance, a label
3986 in it, try something like this:
3989 label = gtk_label_new ("Dialogs are groovy");
3990 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox),
3991 label, TRUE, TRUE, 0);
3992 gtk_widget_show (label);
3995 As an example in using the dialog box, you could put two buttons in
3996 the action_area, a Cancel button and an Ok button, and a label in the
3997 vbox area, asking the user a question or giving an error etc. Then
3998 you could attach a different signal to each of the buttons and perform
3999 the operation the user selects.
4001 If the simple functionality provided by the default vertical and
4002 horizontal boxes in the two areas doesn't give you enough control for
4003 your application, then you can simply pack another layout widget into
4004 the boxes provided. For example, you could pack a table into the
4007 <!-- ----------------------------------------------------------------- -->
4008 <sect1> Pixmaps <label id="sec_Pixmaps">
4010 Pixmaps are data structures that contain pictures. These pictures can
4011 be used in various places, but most commonly as icons on the X
4012 desktop, or as cursors.
4014 A pixmap which only has 2 colors is called a bitmap, and there are a
4015 few additional routines for handling this common special case.
4017 To understand pixmaps, it would help to understand how X window
4018 system works. Under X, applications do not need to be running on the
4019 same computer that is interacting with the user. Instead, the various
4020 applications, called "clients", all communicate with a program which
4021 displays the graphics and handles the keyboard and mouse. This
4022 program which interacts directly with the user is called a "display
4023 server" or "X server." Since the communication might take place over
4024 a network, it's important to keep some information with the X server.
4025 Pixmaps, for example, are stored in the memory of the X server. This
4026 means that once pixmap values are set, they don't need to keep getting
4027 transmitted over the network; instead a command is sent to "display
4028 pixmap number XYZ here." Even if you aren't using X with GTK
4029 currently, using constructs such as Pixmaps will make your programs
4030 work acceptably under X.
4032 To use pixmaps in GTK, we must first build a GdkPixmap structure using
4033 routines from the GDK layer. Pixmaps can either be created from
4034 in-memory data, or from data read from a file. We'll go through each
4035 of the calls to create a pixmap.
4038 GdkPixmap *gdk_bitmap_create_from_data( GdkWindow *window,
4044 This routine is used to create a single-plane pixmap (2 colors) from
4045 data in memory. Each bit of the data represents whether that pixel is
4046 off or on. Width and height are in pixels. The GdkWindow pointer is to
4047 the current window, since a pixmap's resources are meaningful only in
4048 the context of the screen where it is to be displayed.
4051 GdkPixmap *gdk_pixmap_create_from_data( GdkWindow *window,
4060 This is used to create a pixmap of the given depth (number of colors) from
4061 the bitmap data specified. <tt/fg/ and <tt/bg/ are the foreground and
4062 background color to use.
4065 GdkPixmap *gdk_pixmap_create_from_xpm( GdkWindow *window,
4067 GdkColor *transparent_color,
4068 const gchar *filename );
4071 XPM format is a readable pixmap representation for the X Window
4072 System. It is widely used and many different utilities are available
4073 for creating image files in this format. The file specified by
4074 filename must contain an image in that format and it is loaded into
4075 the pixmap structure. The mask specifies which bits of the pixmap are
4076 opaque. All other bits are colored using the color specified by
4077 transparent_color. An example using this follows below.
4080 GdkPixmap *gdk_pixmap_create_from_xpm_d( GdkWindow *window,
4082 GdkColor *transparent_color,
4086 Small images can be incorporated into a program as data in the XPM
4087 format. A pixmap is created using this data, instead of reading it
4088 from a file. An example of such data is
4092 static const char * xpm_data[] = {
4095 ". c #000000000000",
4096 "X c #FFFFFFFFFFFF",
4115 When we're done using a pixmap and not likely to reuse it again soon,
4116 it is a good idea to release the resource using
4117 gdk_pixmap_unref(). Pixmaps should be considered a precious resource,
4118 because they take up memory in the end-user's X server process. Even
4119 though the X client you write may run on a powerful "server" computer,
4120 the user may be running the X server on a small personal computer.
4122 Once we've created a pixmap, we can display it as a GTK widget. We
4123 must create a GTK pixmap widget to contain the GDK pixmap. This is
4127 GtkWidget *gtk_pixmap_new( GdkPixmap *pixmap,
4131 The other pixmap widget calls are
4134 guint gtk_pixmap_get_type( void );
4136 void gtk_pixmap_set( GtkPixmap *pixmap,
4140 void gtk_pixmap_get( GtkPixmap *pixmap,
4145 gtk_pixmap_set is used to change the pixmap that the widget is currently
4146 managing. Val is the pixmap created using GDK.
4148 The following is an example of using a pixmap in a button.
4151 /* example-start pixmap pixmap.c */
4153 #include <gtk/gtk.h>
4156 /* XPM data of Open-File icon */
4157 static const char * xpm_data[] = {
4160 ". c #000000000000",
4161 "X c #FFFFFFFFFFFF",
4180 /* when invoked (via signal delete_event), terminates the application.
4182 gint close_application( GtkWidget *widget,
4191 /* is invoked when the button is clicked. It just prints a message.
4193 void button_clicked( GtkWidget *widget,
4195 g_print( "button clicked\n" );
4201 /* GtkWidget is the storage type for widgets */
4202 GtkWidget *window, *pixmapwid, *button;
4207 /* create the main window, and attach delete_event signal to terminating
4209 gtk_init( &argc, &argv );
4210 window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
4211 gtk_signal_connect( GTK_OBJECT (window), "delete_event",
4212 GTK_SIGNAL_FUNC (close_application), NULL );
4213 gtk_container_set_border_width( GTK_CONTAINER (window), 10 );
4214 gtk_widget_show( window );
4216 /* now for the pixmap from gdk */
4217 style = gtk_widget_get_style( window );
4218 pixmap = gdk_pixmap_create_from_xpm_d( window->window, &mask,
4219 &style->bg[GTK_STATE_NORMAL],
4220 (gchar **)xpm_data );
4222 /* a pixmap widget to contain the pixmap */
4223 pixmapwid = gtk_pixmap_new( pixmap, mask );
4224 gtk_widget_show( pixmapwid );
4226 /* a button to contain the pixmap widget */
4227 button = gtk_button_new();
4228 gtk_container_add( GTK_CONTAINER(button), pixmapwid );
4229 gtk_container_add( GTK_CONTAINER(window), button );
4230 gtk_widget_show( button );
4232 gtk_signal_connect( GTK_OBJECT(button), "clicked",
4233 GTK_SIGNAL_FUNC(button_clicked), NULL );
4235 /* show the window */
4243 To load a file from an XPM data file called icon0.xpm in the current
4244 directory, we would have created the pixmap thus
4247 /* load a pixmap from a file */
4248 pixmap = gdk_pixmap_create_from_xpm( window->window, &mask,
4249 &style->bg[GTK_STATE_NORMAL],
4251 pixmapwid = gtk_pixmap_new( pixmap, mask );
4252 gtk_widget_show( pixmapwid );
4253 gtk_container_add( GTK_CONTAINER(window), pixmapwid );
4256 A disadvantage of using pixmaps is that the displayed object is always
4257 rectangular, regardless of the image. We would like to create desktops
4258 and applications with icons that have more natural shapes. For
4259 example, for a game interface, we would like to have round buttons to
4260 push. The way to do this is using shaped windows.
4262 A shaped window is simply a pixmap where the background pixels are
4263 transparent. This way, when the background image is multi-colored, we
4264 don't overwrite it with a rectangular, non-matching border around our
4265 icon. The following example displays a full wheelbarrow image on the
4269 /* example-start wheelbarrow wheelbarrow.c */
4271 #include <gtk/gtk.h>
4274 static char * WheelbarrowFull_xpm[] = {
4277 ". c #DF7DCF3CC71B",
4278 "X c #965875D669A6",
4279 "o c #71C671C671C6",
4280 "O c #A699A289A699",
4281 "+ c #965892489658",
4282 "@ c #8E38410330C2",
4283 "# c #D75C7DF769A6",
4284 "$ c #F7DECF3CC71B",
4285 "% c #96588A288E38",
4286 "& c #A69992489E79",
4287 "* c #8E3886178E38",
4288 "= c #104008200820",
4289 "- c #596510401040",
4290 "; c #C71B30C230C2",
4291 ": c #C71B9A699658",
4292 "> c #618561856185",
4293 ", c #20811C712081",
4294 "< c #104000000000",
4295 "1 c #861720812081",
4296 "2 c #DF7D4D344103",
4297 "3 c #79E769A671C6",
4298 "4 c #861782078617",
4299 "5 c #41033CF34103",
4300 "6 c #000000000000",
4301 "7 c #49241C711040",
4302 "8 c #492445144924",
4303 "9 c #082008200820",
4304 "0 c #69A618611861",
4305 "q c #B6DA71C65144",
4306 "w c #410330C238E3",
4307 "e c #CF3CBAEAB6DA",
4308 "r c #71C6451430C2",
4309 "t c #EFBEDB6CD75C",
4310 "y c #28A208200820",
4311 "u c #186110401040",
4312 "i c #596528A21861",
4313 "p c #71C661855965",
4314 "a c #A69996589658",
4315 "s c #30C228A230C2",
4316 "d c #BEFBA289AEBA",
4317 "f c #596545145144",
4318 "g c #30C230C230C2",
4319 "h c #8E3882078617",
4320 "j c #208118612081",
4321 "k c #38E30C300820",
4322 "l c #30C2208128A2",
4323 "z c #38E328A238E3",
4324 "x c #514438E34924",
4325 "c c #618555555965",
4326 "v c #30C2208130C2",
4327 "b c #38E328A230C2",
4328 "n c #28A228A228A2",
4329 "m c #41032CB228A2",
4330 "M c #104010401040",
4331 "N c #492438E34103",
4332 "B c #28A2208128A2",
4333 "V c #A699596538E3",
4334 "C c #30C21C711040",
4335 "Z c #30C218611040",
4336 "A c #965865955965",
4337 "S c #618534D32081",
4338 "D c #38E31C711040",
4339 "F c #082000000820",
4348 "ty> 459@>+&& ",
4350 "%$;=* *3:.Xa.dfg> ",
4351 "Oh$;ya *3d.a8j,Xe.d3g8+ ",
4352 " Oh$;ka *3d$a8lz,,xxc:.e3g54 ",
4353 " Oh$;kO *pd$%svbzz,sxxxxfX..&wn> ",
4354 " Oh$@mO *3dthwlsslszjzxxxxxxx3:td8M4 ",
4355 " Oh$@g& *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B* ",
4356 " Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5& ",
4357 " Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM* ",
4358 " OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
4359 " 2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
4360 " :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
4361 " +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
4362 " *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&en",
4363 " p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>",
4364 " OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ",
4365 " 3206Bwxxszx%et.eaAp77m77mmmf3&eeeg* ",
4366 " @26MvzxNzvlbwfpdettttttttttt.c,n& ",
4367 " *;16=lsNwwNwgsvslbwwvccc3pcfu<o ",
4368 " p;<69BvwwsszslllbBlllllllu<5+ ",
4369 " OS0y6FBlvvvzvzss,u=Blllj=54 ",
4370 " c1-699Blvlllllu7k96MMMg4 ",
4371 " *10y8n6FjvllllB<166668 ",
4372 " S-kg+>666<M<996-y6n<8* ",
4373 " p71=4 m69996kD8Z-66698&& ",
4374 " &i0ycm6n4 ogk17,0<6666g ",
4375 " N-k-<> >=01-kuu666> ",
4376 " ,6ky& &46-10ul,66, ",
4377 " Ou0<> o66y<ulw<66& ",
4378 " *kk5 >66By7=xu664 ",
4379 " <<M4 466lj<Mxu66o ",
4380 " *>> +66uv,zN666* ",
4390 /* When invoked (via signal delete_event), terminates the application */
4391 gint close_application( GtkWidget *widget,
4402 /* GtkWidget is the storage type for widgets */
4403 GtkWidget *window, *pixmap, *fixed;
4404 GdkPixmap *gdk_pixmap;
4409 /* Create the main window, and attach delete_event signal to terminate
4410 * the application. Note that the main window will not have a titlebar
4411 * since we're making it a popup. */
4412 gtk_init (&argc, &argv);
4413 window = gtk_window_new( GTK_WINDOW_POPUP );
4414 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
4415 GTK_SIGNAL_FUNC (close_application), NULL);
4416 gtk_widget_show (window);
4418 /* Now for the pixmap and the pixmap widget */
4419 style = gtk_widget_get_default_style();
4420 gc = style->black_gc;
4421 gdk_pixmap = gdk_pixmap_create_from_xpm_d( window->window, &mask,
4422 &style->bg[GTK_STATE_NORMAL],
4423 WheelbarrowFull_xpm );
4424 pixmap = gtk_pixmap_new( gdk_pixmap, mask );
4425 gtk_widget_show( pixmap );
4427 /* To display the pixmap, we use a fixed widget to place the pixmap */
4428 fixed = gtk_fixed_new();
4429 gtk_widget_set_usize( fixed, 200, 200 );
4430 gtk_fixed_put( GTK_FIXED(fixed), pixmap, 0, 0 );
4431 gtk_container_add( GTK_CONTAINER(window), fixed );
4432 gtk_widget_show( fixed );
4434 /* This masks out everything except for the image itself */
4435 gtk_widget_shape_combine_mask( window, mask, 0, 0 );
4437 /* show the window */
4438 gtk_widget_set_uposition( window, 20, 400 );
4439 gtk_widget_show( window );
4447 To make the wheelbarrow image sensitive, we could attach the button
4448 press event signal to make it do something. The following few lines
4449 would make the picture sensitive to a mouse button being pressed which
4450 makes the application terminate.
4453 gtk_widget_set_events( window,
4454 gtk_widget_get_events( window ) |
4455 GDK_BUTTON_PRESS_MASK );
4457 gtk_signal_connect( GTK_OBJECT(window), "button_press_event",
4458 GTK_SIGNAL_FUNC(close_application), NULL );
4461 <!-- ----------------------------------------------------------------- -->
4464 Ruler widgets are used to indicate the location of the mouse pointer
4465 in a given window. A window can have a vertical ruler spanning across
4466 the width and a horizontal ruler spanning down the height. A small
4467 triangular indicator on the ruler shows the exact location of the
4468 pointer relative to the ruler.
4470 A ruler must first be created. Horizontal and vertical rulers are
4474 GtkWidget *gtk_hruler_new( void ); /* horizontal ruler */
4476 GtkWidget *gtk_vruler_new( void ); /* vertical ruler */
4479 Once a ruler is created, we can define the unit of measurement. Units
4480 of measure for rulers can be<tt/GTK_PIXELS/, <tt/GTK_INCHES/ or
4481 <tt/GTK_CENTIMETERS/. This is set using
4484 void gtk_ruler_set_metric( GtkRuler *ruler,
4485 GtkMetricType metric );
4488 The default measure is <tt/GTK_PIXELS/.
4491 gtk_ruler_set_metric( GTK_RULER(ruler), GTK_PIXELS );
4494 Other important characteristics of a ruler are how to mark the units
4495 of scale and where the position indicator is initially placed. These
4496 are set for a ruler using
4499 void gtk_ruler_set_range( GtkRuler *ruler,
4506 The lower and upper arguments define the extent of the ruler, and
4507 max_size is the largest possible number that will be displayed.
4508 Position defines the initial position of the pointer indicator within
4511 A vertical ruler can span an 800 pixel wide window thus
4514 gtk_ruler_set_range( GTK_RULER(vruler), 0, 800, 0, 800);
4517 The markings displayed on the ruler will be from 0 to 800, with a
4518 number for every 100 pixels. If instead we wanted the ruler to range
4519 from 7 to 16, we would code
4522 gtk_ruler_set_range( GTK_RULER(vruler), 7, 16, 0, 20);
4525 The indicator on the ruler is a small triangular mark that indicates
4526 the position of the pointer relative to the ruler. If the ruler is
4527 used to follow the mouse pointer, the motion_notify_event signal
4528 should be connected to the motion_notify_event method of the ruler.
4529 To follow all mouse movements within a window area, we would use
4532 #define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
4534 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4535 (GtkSignalFunc)EVENT_METHOD(ruler, motion_notify_event),
4536 GTK_OBJECT(ruler) );
4539 The following example creates a drawing area with a horizontal ruler
4540 above it and a vertical ruler to the left of it. The size of the
4541 drawing area is 600 pixels wide by 400 pixels high. The horizontal
4542 ruler spans from 7 to 13 with a mark every 100 pixels, while the
4543 vertical ruler spans from 0 to 400 with a mark every 100 pixels.
4544 Placement of the drawing area and the rulers is done using a table.
4547 /* example-start rulers rulers.c */
4549 #include <gtk/gtk.h>
4551 #define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
4556 /* This routine gets control when the close button is clicked */
4557 gint close_application( GtkWidget *widget,
4565 /* The main routine */
4568 GtkWidget *window, *table, *area, *hrule, *vrule;
4570 /* Initialize GTK and create the main window */
4571 gtk_init( &argc, &argv );
4573 window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
4574 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
4575 GTK_SIGNAL_FUNC( close_application ), NULL);
4576 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
4578 /* Create a table for placing the ruler and the drawing area */
4579 table = gtk_table_new( 3, 2, FALSE );
4580 gtk_container_add( GTK_CONTAINER(window), table );
4582 area = gtk_drawing_area_new();
4583 gtk_drawing_area_size( (GtkDrawingArea *)area, XSIZE, YSIZE );
4584 gtk_table_attach( GTK_TABLE(table), area, 1, 2, 1, 2,
4585 GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0 );
4586 gtk_widget_set_events( area, GDK_POINTER_MOTION_MASK |
4587 GDK_POINTER_MOTION_HINT_MASK );
4589 /* The horizontal ruler goes on top. As the mouse moves across the
4590 * drawing area, a motion_notify_event is passed to the
4591 * appropriate event handler for the ruler. */
4592 hrule = gtk_hruler_new();
4593 gtk_ruler_set_metric( GTK_RULER(hrule), GTK_PIXELS );
4594 gtk_ruler_set_range( GTK_RULER(hrule), 7, 13, 0, 20 );
4595 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4596 (GtkSignalFunc)EVENT_METHOD(hrule,
4597 motion_notify_event),
4598 GTK_OBJECT(hrule) );
4599 /* GTK_WIDGET_CLASS(GTK_OBJECT(hrule)->klass)->motion_notify_event, */
4600 gtk_table_attach( GTK_TABLE(table), hrule, 1, 2, 0, 1,
4601 GTK_EXPAND|GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0 );
4603 /* The vertical ruler goes on the left. As the mouse moves across
4604 * the drawing area, a motion_notify_event is passed to the
4605 * appropriate event handler for the ruler. */
4606 vrule = gtk_vruler_new();
4607 gtk_ruler_set_metric( GTK_RULER(vrule), GTK_PIXELS );
4608 gtk_ruler_set_range( GTK_RULER(vrule), 0, YSIZE, 10, YSIZE );
4609 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4611 GTK_WIDGET_CLASS(GTK_OBJECT(vrule)->klass)->
4612 motion_notify_event,
4613 GTK_OBJECT(vrule) );
4614 gtk_table_attach( GTK_TABLE(table), vrule, 0, 1, 1, 2,
4615 GTK_FILL, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0 );
4617 /* Now show everything */
4618 gtk_widget_show( area );
4619 gtk_widget_show( hrule );
4620 gtk_widget_show( vrule );
4621 gtk_widget_show( table );
4622 gtk_widget_show( window );
4630 <!-- ----------------------------------------------------------------- -->
4633 Statusbars are simple widgets used to display a text message. They
4634 keep a stack of the messages pushed onto them, so that popping the
4635 current message will re-display the previous text message.
4637 In order to allow different parts of an application to use the same
4638 statusbar to display messages, the statusbar widget issues Context
4639 Identifiers which are used to identify different "users". The message
4640 on top of the stack is the one displayed, no matter what context it is
4641 in. Messages are stacked in last-in-first-out order, not context
4644 A statusbar is created with a call to:
4647 GtkWidget *gtk_statusbar_new( void );
4650 A new Context Identifier is requested using a call to the following
4651 function with a short textual description of the context:
4654 guint gtk_statusbar_get_context_id( GtkStatusbar *statusbar,
4655 const gchar *context_description );
4658 There are three functions that can operate on statusbars:
4661 guint gtk_statusbar_push( GtkStatusbar *statusbar,
4665 void gtk_statusbar_pop( GtkStatusbar *statusbar)
4668 void gtk_statusbar_remove( GtkStatusbar *statusbar,
4673 The first, gtk_statusbar_push, is used to add a new message to the
4674 statusbar. It returns a Message Identifier, which can be passed later
4675 to the function gtk_statusbar_remove to remove the message with the
4676 given Message and Context Identifiers from the statusbar's stack.
4678 The function gtk_statusbar_pop removes the message highest in the
4679 stack with the given Context Identifier.
4681 The following example creates a statusbar and two buttons, one for
4682 pushing items onto the statusbar, and one for popping the last item
4686 /* example-start statusbar statusbar.c */
4688 #include <gtk/gtk.h>
4691 GtkWidget *status_bar;
4693 void push_item( GtkWidget *widget,
4696 static int count = 1;
4699 g_snprintf(buff, 20, "Item %d", count++);
4700 gtk_statusbar_push( GTK_STATUSBAR(status_bar), GPOINTER_TO_INT(data), buff);
4705 void pop_item( GtkWidget *widget,
4708 gtk_statusbar_pop( GTK_STATUSBAR(status_bar), GPOINTER_TO_INT(data) );
4722 gtk_init (&argc, &argv);
4724 /* create a new window */
4725 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4726 gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
4727 gtk_window_set_title(GTK_WINDOW (window), "GTK Statusbar Example");
4728 gtk_signal_connect(GTK_OBJECT (window), "delete_event",
4729 (GtkSignalFunc) gtk_exit, NULL);
4731 vbox = gtk_vbox_new(FALSE, 1);
4732 gtk_container_add(GTK_CONTAINER(window), vbox);
4733 gtk_widget_show(vbox);
4735 status_bar = gtk_statusbar_new();
4736 gtk_box_pack_start (GTK_BOX (vbox), status_bar, TRUE, TRUE, 0);
4737 gtk_widget_show (status_bar);
4739 context_id = gtk_statusbar_get_context_id(
4740 GTK_STATUSBAR(status_bar), "Statusbar example");
4742 button = gtk_button_new_with_label("push item");
4743 gtk_signal_connect(GTK_OBJECT(button), "clicked",
4744 GTK_SIGNAL_FUNC (push_item), GINT_TO_POINTER(context_id) );
4745 gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 2);
4746 gtk_widget_show(button);
4748 button = gtk_button_new_with_label("pop last item");
4749 gtk_signal_connect(GTK_OBJECT(button), "clicked",
4750 GTK_SIGNAL_FUNC (pop_item), GINT_TO_POINTER(context_id) );
4751 gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 2);
4752 gtk_widget_show(button);
4754 /* always display the window as the last step so it all splashes on
4755 * the screen at once. */
4756 gtk_widget_show(window);
4765 <!-- ----------------------------------------------------------------- -->
4768 The Entry widget allows text to be typed and displayed in a single line
4769 text box. The text may be set with function calls that allow new text
4770 to replace, prepend or append the current contents of the Entry widget.
4772 There are two functions for creating Entry widgets:
4775 GtkWidget *gtk_entry_new( void );
4777 GtkWidget *gtk_entry_new_with_max_length( guint16 max );
4780 The first just creates a new Entry widget, whilst the second creates a
4781 new Entry and sets a limit on the length of the text within the Entry.
4783 There are several functions for altering the text which is currently
4784 within the Entry widget.
4787 void gtk_entry_set_text( GtkEntry *entry,
4788 const gchar *text );
4790 void gtk_entry_append_text( GtkEntry *entry,
4791 const gchar *text );
4793 void gtk_entry_prepend_text( GtkEntry *entry,
4794 const gchar *text );
4797 The function gtk_entry_set_text sets the contents of the Entry widget,
4798 replacing the current contents. The functions gtk_entry_append_text
4799 and gtk_entry_prepend_text allow the current contents to be appended
4802 The next function allows the current insertion point to be set.
4805 void gtk_entry_set_position( GtkEntry *entry,
4809 The contents of the Entry can be retrieved by using a call to the
4810 following function. This is useful in the callback functions described below.
4813 gchar *gtk_entry_get_text( GtkEntry *entry );
4816 The value returned by this function is used internally, and must not
4817 be freed using either free() or g_free()
4819 If we don't want the contents of the Entry to be changed by someone typing
4820 into it, we can change its editable state.
4823 void gtk_entry_set_editable( GtkEntry *entry,
4824 gboolean editable );
4827 The function above allows us to toggle the editable state of the
4828 Entry widget by passing in a TRUE or FALSE value for the <tt/editable/
4831 If we are using the Entry where we don't want the text entered to be
4832 visible, for example when a password is being entered, we can use the
4833 following function, which also takes a boolean flag.
4836 void gtk_entry_set_visibility( GtkEntry *entry,
4840 A region of the text may be set as selected by using the following
4841 function. This would most often be used after setting some default
4842 text in an Entry, making it easy for the user to remove it.
4845 void gtk_entry_select_region( GtkEntry *entry,
4850 If we want to catch when the user has entered text, we can connect to
4851 the <tt/activate/ or <tt/changed/ signal. Activate is raised when the
4852 user hits the enter key within the Entry widget. Changed is raised
4853 when the text changes at all, e.g., for every character entered or
4856 The following code is an example of using an Entry widget.
4859 /* example-start entry entry.c */
4862 #include <gtk/gtk.h>
4864 void enter_callback( GtkWidget *widget,
4868 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
4869 printf("Entry contents: %s\n", entry_text);
4872 void entry_toggle_editable( GtkWidget *checkbutton,
4875 gtk_entry_set_editable(GTK_ENTRY(entry),
4876 GTK_TOGGLE_BUTTON(checkbutton)->active);
4879 void entry_toggle_visibility( GtkWidget *checkbutton,
4882 gtk_entry_set_visibility(GTK_ENTRY(entry),
4883 GTK_TOGGLE_BUTTON(checkbutton)->active);
4891 GtkWidget *vbox, *hbox;
4896 gtk_init (&argc, &argv);
4898 /* create a new window */
4899 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4900 gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
4901 gtk_window_set_title(GTK_WINDOW (window), "GTK Entry");
4902 gtk_signal_connect(GTK_OBJECT (window), "delete_event",
4903 (GtkSignalFunc) gtk_exit, NULL);
4905 vbox = gtk_vbox_new (FALSE, 0);
4906 gtk_container_add (GTK_CONTAINER (window), vbox);
4907 gtk_widget_show (vbox);
4909 entry = gtk_entry_new_with_max_length (50);
4910 gtk_signal_connect(GTK_OBJECT(entry), "activate",
4911 GTK_SIGNAL_FUNC(enter_callback),
4913 gtk_entry_set_text (GTK_ENTRY (entry), "hello");
4914 gtk_entry_append_text (GTK_ENTRY (entry), " world");
4915 gtk_entry_select_region (GTK_ENTRY (entry),
4916 0, GTK_ENTRY(entry)->text_length);
4917 gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0);
4918 gtk_widget_show (entry);
4920 hbox = gtk_hbox_new (FALSE, 0);
4921 gtk_container_add (GTK_CONTAINER (vbox), hbox);
4922 gtk_widget_show (hbox);
4924 check = gtk_check_button_new_with_label("Editable");
4925 gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
4926 gtk_signal_connect (GTK_OBJECT(check), "toggled",
4927 GTK_SIGNAL_FUNC(entry_toggle_editable), entry);
4928 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);
4929 gtk_widget_show (check);
4931 check = gtk_check_button_new_with_label("Visible");
4932 gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
4933 gtk_signal_connect (GTK_OBJECT(check), "toggled",
4934 GTK_SIGNAL_FUNC(entry_toggle_visibility), entry);
4935 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);
4936 gtk_widget_show (check);
4938 button = gtk_button_new_with_label ("Close");
4939 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
4940 GTK_SIGNAL_FUNC(gtk_exit),
4941 GTK_OBJECT (window));
4942 gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
4943 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
4944 gtk_widget_grab_default (button);
4945 gtk_widget_show (button);
4947 gtk_widget_show(window);
4955 <!-- ----------------------------------------------------------------- -->
4958 The Spin Button widget is generally used to allow the user to select a
4959 value from a range of numeric values. It consists of a text
4960 entry box with up and down arrow buttons attached to the
4961 side. Selecting one of the buttons causes the value to "spin" up and
4962 down the range of possible values. The entry box may also be edited
4963 directly to enter a specific value.
4965 The Spin Button allows the value to have zero or a number of decimal
4966 places and to be incremented/decremented in configurable steps. The
4967 action of holding down one of the buttons optionally results in an
4968 acceleration of change in the value according to how long it is
4971 The Spin Button uses an <ref id="sec_Adjustment" name="Adjustment">
4972 object to hold information about the range of values that the spin
4973 button can take. This makes for a powerful Spin Button widget.
4975 Recall that an adjustment widget is created with the following
4976 function, which illustrates the information that it holds:
4979 GtkObject *gtk_adjustment_new( gfloat value,
4982 gfloat step_increment,
4983 gfloat page_increment,
4987 These attributes of an Adjustment are used by the Spin Button in the
4991 <item> <tt/value/: initial value for the Spin Button
4992 <item> <tt/lower/: lower range value
4993 <item> <tt/upper/: upper range value
4994 <item> <tt/step_increment/: value to increment/decrement when pressing
4995 mouse button 1 on a button
4996 <item> <tt/page_increment/: value to increment/decrement when pressing
4997 mouse button 2 on a button
4998 <item> <tt/page_size/: unused
5001 Additionally, mouse button 3 can be used to jump directly to the
5002 <tt/upper/ or <tt/lower/ values when used to select one of the
5003 buttons. Lets look at how to create a Spin Button:
5006 GtkWidget *gtk_spin_button_new( GtkAdjustment *adjustment,
5011 The <tt/climb_rate/ argument take a value between 0.0 and 1.0 and
5012 indicates the amount of acceleration that the Spin Button has. The
5013 <tt/digits/ argument specifies the number of decimal places to which
5014 the value will be displayed.
5016 A Spin Button can be reconfigured after creation using the following
5020 void gtk_spin_button_configure( GtkSpinButton *spin_button,
5021 GtkAdjustment *adjustment,
5026 The <tt/spin_button/ argument specifies the Spin Button widget that is
5027 to be reconfigured. The other arguments are as specified above.
5029 The adjustment can be set and retrieved independantly using the
5030 following two functions:
5033 void gtk_spin_button_set_adjustment( GtkSpinButton *spin_button,
5034 GtkAdjustment *adjustment );
5036 GtkAdjustment *gtk_spin_button_get_adjustment( GtkSpinButton *spin_button );
5039 The number of decimal places can also be altered using:
5042 void gtk_spin_button_set_digits( GtkSpinButton *spin_button,
5046 The value that a Spin Button is currently displaying can be changed
5047 using the following function:
5050 void gtk_spin_button_set_value( GtkSpinButton *spin_button,
5054 The current value of a Spin Button can be retrieved as either a
5055 floating point or integer value with the following functions:
5058 gfloat gtk_spin_button_get_value_as_float( GtkSpinButton *spin_button );
5060 gint gtk_spin_button_get_value_as_int( GtkSpinButton *spin_button );
5063 If you want to alter the value of a Spin Value relative to its current
5064 value, then the following function can be used:
5067 void gtk_spin_button_spin( GtkSpinButton *spin_button,
5068 GtkSpinType direction,
5072 The <tt/direction/ parameter can take one of the following values:
5075 GTK_SPIN_STEP_FORWARD
5076 GTK_SPIN_STEP_BACKWARD
5077 GTK_SPIN_PAGE_FORWARD
5078 GTK_SPIN_PAGE_BACKWARD
5081 GTK_SPIN_USER_DEFINED
5084 This function packs in quite a bit of functionality, which I will
5085 attempt to clearly explain. Many of these settings use values from the
5086 Adjustment object that is associated with a Spin Button.
5088 <tt/GTK_SPIN_STEP_FORWARD/ and <tt/GTK_SPIN_STEP_BACKWARD/ change the
5089 value of the Spin Button by the amount specified by <tt/increment/,
5090 unless <tt/increment/ is equal to 0, in which case the value is
5091 changed by the value of <tt/step_increment/ in theAdjustment.
5093 <tt/GTK_SPIN_PAGE_FORWARD/ and <tt/GTK_SPIN_PAGE_BACKWARD/ simply
5094 alter the value of the Spin Button by <tt/increment/.
5096 <tt/GTK_SPIN_HOME/ sets the value of the Spin Button to the bottom of
5097 the Adjustments range.
5099 <tt/GTK_SPIN_END/ sets the value of the Spin Button to the top of the
5102 <tt/GTK_SPIN_USER_DEFINED/ simply alters the value of the Spin Button
5103 by the specified amount.
5105 We move away from functions for setting and retreving the range attributes
5106 of the Spin Button now, and move onto functions that affect the
5107 appearance and behaviour of the Spin Button widget itself.
5109 The first of these functions is used to constrain the text box of the
5110 Spin Button such that it may only contain a numeric value. This
5111 prevents a user from typing anything other than numeric values into
5112 the text box of a Spin Button:
5115 void gtk_spin_button_set_numeric( GtkSpinButton *spin_button,
5119 You can set whether a Spin Button will wrap around between the upper
5120 and lower range values with the following function:
5123 void gtk_spin_button_set_wrap( GtkSpinButton *spin_button,
5127 You can set a Spin Button to round the value to the nearest
5128 <tt/step_increment/, which is set within the Adjustment object used
5129 with the Spin Button. This is accomplished with the following
5133 void gtk_spin_button_set_snap_to_ticks( GtkSpinButton *spin_button,
5134 gboolean snap_to_ticks );
5137 The update policy of a Spin Button can be changed with the following
5141 void gtk_spin_button_set_update_policy( GtkSpinButton *spin_button,
5142 GtkSpinButtonUpdatePolicy policy );
5145 <!-- TODO: find out what this does - TRG -->
5147 The possible values of <tt/policy/ are either <tt/GTK_UPDATE_ALWAYS/ or
5148 <tt/GTK_UPDATE_IF_VALID/.
5150 These policies affect the behavior of a Spin Button when parsing
5151 inserted text and syncing its value with the values of the
5154 In the case of <tt/GTK_UPDATE_IF_VALID/ the Spin Button only value
5155 gets changed if the text input is a numeric value that is within the
5156 range specified by the Adjustment. Otherwise the text is reset to the
5159 In case of <tt/GTK_UPDATE_ALWAYS/ we ignore errors while converting
5160 text into a numeric value.
5162 The appearance of the buttons used in a Spin Button can be changed
5163 using the following function:
5166 void gtk_spin_button_set_shadow_type( GtkSpinButton *spin_button,
5167 GtkShadowType shadow_type );
5170 As usual, the <tt/shadow_type/ can be one of:
5175 GTK_SHADOW_ETCHED_IN
5176 GTK_SHADOW_ETCHED_OUT
5179 Finally, you can explicitly request that a Spin Button update itself:
5182 void gtk_spin_button_update( GtkSpinButton *spin_button );
5185 It's example time again.
5188 /* example-start spinbutton spinbutton.c */
5191 #include <gtk/gtk.h>
5193 static GtkWidget *spinner1;
5195 void toggle_snap( GtkWidget *widget,
5196 GtkSpinButton *spin )
5198 gtk_spin_button_set_snap_to_ticks (spin, GTK_TOGGLE_BUTTON (widget)->active);
5201 void toggle_numeric( GtkWidget *widget,
5202 GtkSpinButton *spin )
5204 gtk_spin_button_set_numeric (spin, GTK_TOGGLE_BUTTON (widget)->active);
5207 void change_digits( GtkWidget *widget,
5208 GtkSpinButton *spin )
5210 gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinner1),
5211 gtk_spin_button_get_value_as_int (spin));
5214 void get_value( GtkWidget *widget,
5219 GtkSpinButton *spin;
5221 spin = GTK_SPIN_BUTTON (spinner1);
5222 label = GTK_LABEL (gtk_object_get_user_data (GTK_OBJECT (widget)));
5223 if (GPOINTER_TO_INT (data) == 1)
5224 sprintf (buf, "%d", gtk_spin_button_get_value_as_int (spin));
5226 sprintf (buf, "%0.*f", spin->digits,
5227 gtk_spin_button_get_value_as_float (spin));
5228 gtk_label_set_text (label, buf);
5238 GtkWidget *main_vbox;
5241 GtkWidget *spinner2;
5245 GtkWidget *val_label;
5248 /* Initialise GTK */
5249 gtk_init(&argc, &argv);
5251 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5253 gtk_signal_connect (GTK_OBJECT (window), "destroy",
5254 GTK_SIGNAL_FUNC (gtk_main_quit),
5257 gtk_window_set_title (GTK_WINDOW (window), "Spin Button");
5259 main_vbox = gtk_vbox_new (FALSE, 5);
5260 gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 10);
5261 gtk_container_add (GTK_CONTAINER (window), main_vbox);
5263 frame = gtk_frame_new ("Not accelerated");
5264 gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
5266 vbox = gtk_vbox_new (FALSE, 0);
5267 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
5268 gtk_container_add (GTK_CONTAINER (frame), vbox);
5270 /* Day, month, year spinners */
5272 hbox = gtk_hbox_new (FALSE, 0);
5273 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
5275 vbox2 = gtk_vbox_new (FALSE, 0);
5276 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5278 label = gtk_label_new ("Day :");
5279 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5280 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5282 adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 31.0, 1.0,
5284 spinner = gtk_spin_button_new (adj, 0, 0);
5285 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
5286 gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
5288 gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5290 vbox2 = gtk_vbox_new (FALSE, 0);
5291 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5293 label = gtk_label_new ("Month :");
5294 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5295 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5297 adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 12.0, 1.0,
5299 spinner = gtk_spin_button_new (adj, 0, 0);
5300 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
5301 gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
5302 GTK_SHADOW_ETCHED_IN);
5303 gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5305 vbox2 = gtk_vbox_new (FALSE, 0);
5306 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5308 label = gtk_label_new ("Year :");
5309 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5310 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5312 adj = (GtkAdjustment *) gtk_adjustment_new (1998.0, 0.0, 2100.0,
5314 spinner = gtk_spin_button_new (adj, 0, 0);
5315 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), FALSE);
5316 gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
5318 gtk_widget_set_usize (spinner, 55, 0);
5319 gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5321 frame = gtk_frame_new ("Accelerated");
5322 gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
5324 vbox = gtk_vbox_new (FALSE, 0);
5325 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
5326 gtk_container_add (GTK_CONTAINER (frame), vbox);
5328 hbox = gtk_hbox_new (FALSE, 0);
5329 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5331 vbox2 = gtk_vbox_new (FALSE, 0);
5332 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5334 label = gtk_label_new ("Value :");
5335 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5336 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5338 adj = (GtkAdjustment *) gtk_adjustment_new (0.0, -10000.0, 10000.0,
5340 spinner1 = gtk_spin_button_new (adj, 1.0, 2);
5341 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner1), TRUE);
5342 gtk_widget_set_usize (spinner1, 100, 0);
5343 gtk_box_pack_start (GTK_BOX (vbox2), spinner1, FALSE, TRUE, 0);
5345 vbox2 = gtk_vbox_new (FALSE, 0);
5346 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5348 label = gtk_label_new ("Digits :");
5349 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5350 gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5352 adj = (GtkAdjustment *) gtk_adjustment_new (2, 1, 5, 1, 1, 0);
5353 spinner2 = gtk_spin_button_new (adj, 0.0, 0);
5354 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner2), TRUE);
5355 gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
5356 GTK_SIGNAL_FUNC (change_digits),
5357 (gpointer) spinner2);
5358 gtk_box_pack_start (GTK_BOX (vbox2), spinner2, FALSE, TRUE, 0);
5360 hbox = gtk_hbox_new (FALSE, 0);
5361 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5363 button = gtk_check_button_new_with_label ("Snap to 0.5-ticks");
5364 gtk_signal_connect (GTK_OBJECT (button), "clicked",
5365 GTK_SIGNAL_FUNC (toggle_snap),
5367 gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
5368 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
5370 button = gtk_check_button_new_with_label ("Numeric only input mode");
5371 gtk_signal_connect (GTK_OBJECT (button), "clicked",
5372 GTK_SIGNAL_FUNC (toggle_numeric),
5374 gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
5375 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
5377 val_label = gtk_label_new ("");
5379 hbox = gtk_hbox_new (FALSE, 0);
5380 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5381 button = gtk_button_new_with_label ("Value as Int");
5382 gtk_object_set_user_data (GTK_OBJECT (button), val_label);
5383 gtk_signal_connect (GTK_OBJECT (button), "clicked",
5384 GTK_SIGNAL_FUNC (get_value),
5385 GINT_TO_POINTER (1));
5386 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
5388 button = gtk_button_new_with_label ("Value as Float");
5389 gtk_object_set_user_data (GTK_OBJECT (button), val_label);
5390 gtk_signal_connect (GTK_OBJECT (button), "clicked",
5391 GTK_SIGNAL_FUNC (get_value),
5392 GINT_TO_POINTER (2));
5393 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
5395 gtk_box_pack_start (GTK_BOX (vbox), val_label, TRUE, TRUE, 0);
5396 gtk_label_set_text (GTK_LABEL (val_label), "0");
5398 hbox = gtk_hbox_new (FALSE, 0);
5399 gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, TRUE, 0);
5401 button = gtk_button_new_with_label ("Close");
5402 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
5403 GTK_SIGNAL_FUNC (gtk_widget_destroy),
5404 GTK_OBJECT (window));
5405 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
5407 gtk_widget_show_all (window);
5409 /* Enter the event loop */
5417 <!-- ----------------------------------------------------------------- -->
5420 The combo box is another fairly simple widget that is really just a
5421 collection of other widgets. From the user's point of view, the widget
5422 consists of a text entry box and a pull down menu from which the user
5423 can select one of a set of predefined entries. Alternatively, the user
5424 can type a different option directly into the text box.
5426 The following extract from the structure that defines a Combo Box
5427 identifies several of the components:
5440 As you can see, the Combo Box has two principal parts that you really
5441 care about: an entry and a list.
5443 First off, to create a combo box, use:
5446 GtkWidget *gtk_combo_new( void );
5449 Now, if you want to set the string in the entry section of the combo
5450 box, this is done by manipulating the <tt/entry/ widget directly:
5453 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), "My String.");
5456 To set the values in the popdown list, one uses the function:
5459 void gtk_combo_set_popdown_strings( GtkCombo *combo,
5463 Before you can do this, you have to assemble a GList of the strings
5464 that you want. GList is a linked list implementation that is part of
5465 <ref id="sec_glib" name="GLib">, a library supporing GTK. For the
5466 moment, the quick and dirty explanation is that you need to set up a
5467 GList pointer, set it equal to NULL, then append strings to it with
5470 GList *g_list_append( GList *glist,
5474 It is important that you set the initial GList pointer to NULL. The
5475 value returned from the g_list_append function must be used as the new
5476 pointer to the GList.
5478 Here's a typical code segment for creating a set of options:
5483 glist = g_list_append(glist, "String 1");
5484 glist = g_list_append(glist, "String 2");
5485 glist = g_list_append(glist, "String 3");
5486 glist = g_list_append(glist, "String 4");
5488 gtk_combo_set_popdown_strings( GTK_COMBO(combo), glist) ;
5491 The combo widget makes a copy of the strings passed to it in the glist
5492 structure. As a result, you need to make sure you free the memory used
5493 by the list if that is appropriate for your application.
5495 At this point you have a working combo box that has been set up.
5496 There are a few aspects of its behavior that you can change. These
5497 are accomplished with the functions:
5500 void gtk_combo_set_use_arrows( GtkCombo *combo,
5503 void gtk_combo_set_use_arrows_always( GtkCombo *combo,
5506 void gtk_combo_set_case_sensitive( GtkCombo *combo,
5510 <tt/gtk_combo_set_use_arrows()/ lets the user change the value in the
5511 entry using the up/down arrow keys. This doesn't bring up the list, but
5512 rather replaces the current text in the entry with the next list entry
5513 (up or down, as your key choice indicates). It does this by searching
5514 in the list for the item corresponding to the current value in the
5515 entry and selecting the previous/next item accordingly. Usually in an
5516 entry the arrow keys are used to change focus (you can do that anyway
5517 using TAB). Note that when the current item is the last of the list
5518 and you press arrow-down it changes the focus (the same applies with
5519 the first item and arrow-up).
5521 If the current value in the entry is not in the list, then the
5522 function of <tt/gtk_combo_set_use_arrows()/ is disabled.
5524 <tt/gtk_combo_set_use_arrows_always()/ similarly allows the use the
5525 the up/down arrow keys to cycle through the choices in the dropdown
5526 list, except that it wraps around the values in the list, completely
5527 disabling the use of the up and down arrow keys for changing focus.
5529 <tt/gtk_combo_set_case_sensitive()/ toggles whether or not GTK
5530 searches for entries in a case sensitive manner. This is used when the
5531 Combo widget is asked to find a value from the list using the current
5532 entry in the text box. This completion can be performed in either a
5533 case sensitive or insensitive manner, depending upon the use of this
5534 function. The Combo widget can also simply complete the current entry
5535 if the user presses the key combination MOD-1 and "Tab". MOD-1 is
5536 often mapped to the "Alt" key, by the <tt/xmodmap/ utility. Note,
5537 however that some window managers also use this key combination, which
5538 will override its use within GTK.
5540 Now that we have a combo box, tailored to look and act how we want it,
5541 all that remains is being able to get data from the combo box. This is
5542 relatively straightforward. The majority of the time, all you are
5543 going to care about getting data from is the entry. The entry is
5544 accessed simply by <tt>GTK_ENTRY(GTK_COMBO(combo)->entry)</tt>. The
5545 two principal things that you are going to want to do with it are
5546 attach to the activate signal, which indicates that the user has
5547 pressed the Return or Enter key, and read the text. The first is
5548 accomplished using something like:
5551 gtk_signal_connect(GTK_OBJECT(GTK_COMB(combo)->entry), "activate",
5552 GTK_SIGNAL_FUNC (my_callback_function), my_data);
5555 Getting the text at any arbitrary time is accomplished by simply using
5559 gchar *gtk_entry_get_text(GtkEntry *entry);
5567 string = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry));
5570 That's about all there is to it. There is a function
5573 void gtk_combo_disable_activate(GtkCombo *combo);
5576 that will disable the activate signal on the entry widget in the combo
5577 box. Personally, I can't think of why you'd want to use it, but it
5580 <!-- There is also a function to set the string on a particular item, void
5581 gtk_combo_set_item_string(GtkCombo *combo, GtkItem *item, const gchar
5582 *item_value), but this requires that you have a pointer to the
5583 appropriate Item. Frankly, I have no idea how to do that.
5586 <!-- ----------------------------------------------------------------- -->
5589 The Calendar widget is an effective way to display and retrieve
5590 monthly date related information. It is a very simple widget to create
5593 Creating a GtkCalendar widget is a simple as:
5596 GtkWidget *gtk_calendar_new();
5599 There might be times where you need to change a lot of information
5600 within this widget and the following functions allow you to make
5601 multiple change to a Calendar widget without the user seeing multiple
5605 void gtk_calendar_freeze( GtkCalendar *Calendar );
5607 void gtk_calendar_thaw ( GtkCalendar *Calendar );
5610 They work just like the freeze/thaw functions of every other
5613 The Calendar widget has a few options that allow you to change the way
5614 the widget both looks and operates by using the function
5617 void gtk_calendar_display_options( GtkCalendar *calendar,
5618 GtkCalendarDisplayOptions flags );
5621 The <tt/flags/ argument can be formed by combining either of the
5622 following five options using the logical bitwise OR (|) operation:
5624 <item> GTK_CALENDAR_SHOW_HEADING - this option specifies that
5625 the month and year should be shown when drawing the calendar.
5626 <item> GTK_CALENDAR_SHOW_DAY_NAMES - this option specifies that the
5627 three letter descriptions should be displayed for each day (eg
5630 <item> GTK_CALENDAR_NO_MONTH_CHANGE - this option states that the user
5631 should not and can not change the currently displayed month. This can
5632 be good if you only need to display a particular month such as if you
5633 are displaying 12 calendar widgets for every month in a particular
5636 <item> GTK_CALENDAR_SHOW_WEEK_NUMBERS - this option specifies that the
5637 number for each week should be displayed down the left side of the
5638 calendar. (eg. Jan 1 = Week 1,Dec 31 = Week 52).
5640 <item> GTK_CALENDAR_WEEK_START_MONDAY - this option states that the
5641 calander week will start on Monday instead of Sunday which is the
5642 default. This only affects the order in which days are displayed from
5646 The following functions are used to set the the currently displayed
5649 gint gtk_calendar_select_month( GtkCalendar *calendar,
5653 void gtk_calendar_select_day( GtkCalendar *calendar,
5657 The return value from <tt/gtk_calendar_select_month()/ is a boolean
5658 value indicating whether the selection was successful.
5660 With <tt/gtk_calendar_select_day()/ the specified day number is
5661 selected within the current month, if that is possible. A
5662 <tt/day/ value of 0 will deselect any current selection.
5664 In addition to having a day selected, any number of days in the month
5665 may be "marked". A marked day is highlighted within the calendar
5666 display. The following functions are provided to manipulate marked
5670 gint gtk_calendar_mark_day( GtkCalendar *calendar,
5673 gint gtk_calendar_unmark_day( GtkCalendar *calendar,
5676 void gtk_calendar_clear_marks( GtkCalendar *calendar);
5679 The currently marked days are stored within an array within the
5680 GtkCalendar structure. This array is 31 elements long so to test
5681 whether a particular day is currently marked, you need to access the
5682 corresponding element of the array (don't forget in C that array
5683 elements are numbered 0 to n-1). For example:
5686 GtkCalendar *calendar;
5687 calendar = gtk_calendar_new();
5691 /* Is day 7 marked? */
5692 if (calendar->marked_date[7-1])
5696 Note that marks are persistent across month and year changes.
5698 The final Calendar widget function is used to retrieve the currently
5699 selected date, month and/or year.
5702 void gtk_calendar_get_date( GtkCalendar *calendar,
5708 This function requires you to pass the addresses of <tt/guint/
5709 variables, into which the result will be placed. Passing <tt/NULL/ as
5710 a value will result in the corresponding value not being returned.
5712 The Calendar widget can generate a number of signals indicating date
5713 selection and change. The names of these signals are self explanatory,
5717 <item> <tt/month_changed/
5718 <item> <tt/day_selected/
5719 <item> <tt/day_selected_double_click/
5720 <item> <tt/prev_month/
5721 <item> <tt/next_month/
5722 <item> <tt/prev_year/
5723 <item> <tt/next_year/
5726 That just leaves us with the need to put all of this together into
5730 /* example-start calendar calendar.c */
5732 * Copyright (C) 1998 Cesar Miquel, Shawn T. Amundson, Mattias Grönlund
5733 * Copyright (C) 2000 Tony Gale
5735 * This program is free software; you can redistribute it and/or modify
5736 * it under the terms of the GNU General Public License as published by
5737 * the Free Software Foundation; either version 2 of the License, or
5738 * (at your option) any later version.
5740 * This program is distributed in the hope that it will be useful,
5741 * but WITHOUT ANY WARRANTY; without even the implied warranty of
5742 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5743 * GNU General Public License for more details.
5745 * You should have received a copy of the GNU General Public License
5746 * along with this program; if not, write to the Free Software
5747 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
5750 #include <gtk/gtk.h>
5756 #define DEF_PAD_SMALL 5
5758 #define TM_YEAR_BASE 1900
5760 typedef struct _CalendarData {
5761 GtkWidget *flag_checkboxes[5];
5762 gboolean settings[5];
5764 GtkWidget *font_dialog;
5766 GtkWidget *prev2_sig;
5767 GtkWidget *prev_sig;
5768 GtkWidget *last_sig;
5773 calendar_show_header,
5775 calendar_month_change,
5777 calendar_monday_first
5784 void calendar_date_to_string( CalendarData *data,
5791 memset (&tm, 0, sizeof (tm));
5792 gtk_calendar_get_date (GTK_CALENDAR(data->window),
5793 &tm.tm_year, &tm.tm_mon, &tm.tm_mday);
5794 tm.tm_year -= TM_YEAR_BASE;
5795 time = mktime(&tm);
5796 strftime (buffer, buff_len-1, "%x", gmtime(&time));
5799 void calendar_set_signal_strings( char *sig_str,
5804 gtk_label_get (GTK_LABEL (data->prev_sig), &prev_sig);
5805 gtk_label_set (GTK_LABEL (data->prev2_sig), prev_sig);
5807 gtk_label_get (GTK_LABEL (data->last_sig), &prev_sig);
5808 gtk_label_set (GTK_LABEL (data->prev_sig), prev_sig);
5809 gtk_label_set (GTK_LABEL (data->last_sig), sig_str);
5812 void calendar_month_changed( GtkWidget *widget,
5813 CalendarData *data )
5815 char buffer[256] = "month_changed: ";
5817 calendar_date_to_string (data, buffer+15, 256-15);
5818 calendar_set_signal_strings (buffer, data);
5821 void calendar_day_selected( GtkWidget *widget,
5822 CalendarData *data )
5824 char buffer[256] = "day_selected: ";
5826 calendar_date_to_string (data, buffer+14, 256-14);
5827 calendar_set_signal_strings (buffer, data);
5830 void calendar_day_selected_double_click( GtkWidget *widget,
5831 CalendarData *data )
5834 char buffer[256] = "day_selected_double_click: ";
5836 calendar_date_to_string (data, buffer+27, 256-27);
5837 calendar_set_signal_strings (buffer, data);
5839 memset (&tm, 0, sizeof (tm));
5840 gtk_calendar_get_date (GTK_CALENDAR(data->window),
5841 &tm.tm_year, &tm.tm_mon, &tm.tm_mday);
5842 tm.tm_year -= TM_YEAR_BASE;
5844 if(GTK_CALENDAR(data->window)->marked_date[tm.tm_mday-1] == 0) {
5845 gtk_calendar_mark_day(GTK_CALENDAR(data->window),tm.tm_mday);
5847 gtk_calendar_unmark_day(GTK_CALENDAR(data->window),tm.tm_mday);
5851 void calendar_prev_month( GtkWidget *widget,
5852 CalendarData *data )
5854 char buffer[256] = "prev_month: ";
5856 calendar_date_to_string (data, buffer+12, 256-12);
5857 calendar_set_signal_strings (buffer, data);
5860 void calendar_next_month( GtkWidget *widget,
5861 CalendarData *data )
5863 char buffer[256] = "next_month: ";
5865 calendar_date_to_string (data, buffer+12, 256-12);
5866 calendar_set_signal_strings (buffer, data);
5869 void calendar_prev_year( GtkWidget *widget,
5870 CalendarData *data )
5872 char buffer[256] = "prev_year: ";
5874 calendar_date_to_string (data, buffer+11, 256-11);
5875 calendar_set_signal_strings (buffer, data);
5878 void calendar_next_year( GtkWidget *widget,
5879 CalendarData *data )
5881 char buffer[256] = "next_year: ";
5883 calendar_date_to_string (data, buffer+11, 256-11);
5884 calendar_set_signal_strings (buffer, data);
5888 void calendar_set_flags( CalendarData *calendar )
5893 if (calendar->settings[i])
5895 options=options + (1<<i);
5897 if (calendar->window)
5898 gtk_calendar_display_options (GTK_CALENDAR (calendar->window), options);
5901 void calendar_toggle_flag( GtkWidget *toggle,
5902 CalendarData *calendar )
5908 if (calendar->flag_checkboxes[i] == toggle)
5911 calendar->settings[j]=!calendar->settings[j];
5912 calendar_set_flags(calendar);
5916 void calendar_font_selection_ok( GtkWidget *button,
5917 CalendarData *calendar )
5922 calendar->font = gtk_font_selection_dialog_get_font_name(
5923 GTK_FONT_SELECTION_DIALOG (calendar->font_dialog));
5924 if (calendar->window)
5926 font = gtk_font_selection_dialog_get_font(GTK_FONT_SELECTION_DIALOG(calendar->font_dialog));
5929 style = gtk_style_copy (gtk_widget_get_style (calendar->window));
5930 gdk_font_unref (style->font);
5932 gdk_font_ref (style->font);
5933 gtk_widget_set_style (calendar->window, style);
5938 void calendar_select_font( GtkWidget *button,
5939 CalendarData *calendar )
5943 if (!calendar->font_dialog) {
5944 window = gtk_font_selection_dialog_new ("Font Selection Dialog");
5945 g_return_if_fail(GTK_IS_FONT_SELECTION_DIALOG(window));
5946 calendar->font_dialog = window;
5948 gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE);
5950 gtk_signal_connect (GTK_OBJECT (window), "destroy",
5951 GTK_SIGNAL_FUNC (gtk_widget_destroyed),
5952 &calendar->font_dialog);
5954 gtk_signal_connect (GTK_OBJECT (GTK_FONT_SELECTION_DIALOG (window)->ok_button),
5955 "clicked", GTK_SIGNAL_FUNC(calendar_font_selection_ok),
5957 gtk_signal_connect_object (GTK_OBJECT (GTK_FONT_SELECTION_DIALOG (window)->cancel_button),
5959 GTK_SIGNAL_FUNC (gtk_widget_destroy),
5960 GTK_OBJECT (calendar->font_dialog));
5962 window=calendar->font_dialog;
5963 if (!GTK_WIDGET_VISIBLE (window))
5964 gtk_widget_show (window);
5966 gtk_widget_destroy (window);
5970 void create_calendar()
5973 GtkWidget *vbox, *vbox2, *vbox3;
5976 GtkWidget *calendar;
5980 GtkWidget *separator;
5983 static CalendarData calendar_data;
5991 { "Show Day Names" },
5992 { "No Month Change" },
5993 { "Show Week Numbers" },
5994 { "Week Start Monday" }
5998 calendar_data.window = NULL;
5999 calendar_data.font = NULL;
6000 calendar_data.font_dialog = NULL;
6002 for (i=0; i<5; i++) {
6003 calendar_data.settings[i]=0;
6006 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6007 gtk_window_set_title(GTK_WINDOW(window), "GtkCalendar Example");
6008 gtk_container_border_width (GTK_CONTAINER (window), 5);
6009 gtk_signal_connect(GTK_OBJECT(window), "destroy",
6010 GTK_SIGNAL_FUNC(gtk_main_quit),
6012 gtk_signal_connect(GTK_OBJECT(window), "delete-event",
6013 GTK_SIGNAL_FUNC(gtk_false),
6016 gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, TRUE);
6018 vbox = gtk_vbox_new(FALSE, DEF_PAD);
6019 gtk_container_add (GTK_CONTAINER (window), vbox);
6022 * The top part of the window, Calendar, flags and fontsel.
6025 hbox = gtk_hbox_new(FALSE, DEF_PAD);
6026 gtk_box_pack_start (GTK_BOX(vbox), hbox, TRUE, TRUE, DEF_PAD);
6027 hbbox = gtk_hbutton_box_new();
6028 gtk_box_pack_start(GTK_BOX(hbox), hbbox, FALSE, FALSE, DEF_PAD);
6029 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_SPREAD);
6030 gtk_button_box_set_spacing(GTK_BUTTON_BOX(hbbox), 5);
6032 /* Calendar widget */
6033 frame = gtk_frame_new("Calendar");
6034 gtk_box_pack_start(GTK_BOX(hbbox), frame, FALSE, TRUE, DEF_PAD);
6035 calendar=gtk_calendar_new();
6036 calendar_data.window = calendar;
6037 calendar_set_flags(&calendar_data);
6038 gtk_calendar_mark_day ( GTK_CALENDAR(calendar), 19);
6039 gtk_container_add( GTK_CONTAINER( frame), calendar);
6040 gtk_signal_connect (GTK_OBJECT (calendar), "month_changed",
6041 GTK_SIGNAL_FUNC (calendar_month_changed),
6042 &calendar_data);
6043 gtk_signal_connect (GTK_OBJECT (calendar), "day_selected",
6044 GTK_SIGNAL_FUNC (calendar_day_selected),
6045 &calendar_data);
6046 gtk_signal_connect (GTK_OBJECT (calendar), "day_selected_double_click",
6047 GTK_SIGNAL_FUNC (calendar_day_selected_double_click),
6048 &calendar_data);
6049 gtk_signal_connect (GTK_OBJECT (calendar), "prev_month",
6050 GTK_SIGNAL_FUNC (calendar_prev_month),
6051 &calendar_data);
6052 gtk_signal_connect (GTK_OBJECT (calendar), "next_month",
6053 GTK_SIGNAL_FUNC (calendar_next_month),
6054 &calendar_data);
6055 gtk_signal_connect (GTK_OBJECT (calendar), "prev_year",
6056 GTK_SIGNAL_FUNC (calendar_prev_year),
6057 &calendar_data);
6058 gtk_signal_connect (GTK_OBJECT (calendar), "next_year",
6059 GTK_SIGNAL_FUNC (calendar_next_year),
6060 &calendar_data);
6063 separator = gtk_vseparator_new ();
6064 gtk_box_pack_start (GTK_BOX (hbox), separator, FALSE, TRUE, 0);
6066 vbox2 = gtk_vbox_new(FALSE, DEF_PAD);
6067 gtk_box_pack_start(GTK_BOX(hbox), vbox2, FALSE, FALSE, DEF_PAD);
6069 /* Build the Right frame with the flags in */
6071 frame = gtk_frame_new("Flags");
6072 gtk_box_pack_start(GTK_BOX(vbox2), frame, TRUE, TRUE, DEF_PAD);
6073 vbox3 = gtk_vbox_new(TRUE, DEF_PAD_SMALL);
6074 gtk_container_add(GTK_CONTAINER(frame), vbox3);
6076 for (i = 0; i < 5; i++)
6078 toggle = gtk_check_button_new_with_label(flags[i].label);
6079 gtk_signal_connect (GTK_OBJECT (toggle),
6081 GTK_SIGNAL_FUNC(calendar_toggle_flag),
6082 &calendar_data);
6083 gtk_box_pack_start (GTK_BOX (vbox3), toggle, TRUE, TRUE, 0);
6084 calendar_data.flag_checkboxes[i]=toggle;
6086 /* Build the right font-button */
6087 button = gtk_button_new_with_label("Font...");
6088 gtk_signal_connect (GTK_OBJECT (button),
6090 GTK_SIGNAL_FUNC(calendar_select_font),
6091 &calendar_data);
6092 gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0);
6095 * Build the Signal-event part.
6098 frame = gtk_frame_new("Signal events");
6099 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, DEF_PAD);
6101 vbox2 = gtk_vbox_new(TRUE, DEF_PAD_SMALL);
6102 gtk_container_add(GTK_CONTAINER(frame), vbox2);
6104 hbox = gtk_hbox_new (FALSE, 3);
6105 gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0);
6106 label = gtk_label_new ("Signal:");
6107 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
6108 calendar_data.last_sig = gtk_label_new ("");
6109 gtk_box_pack_start (GTK_BOX (hbox), calendar_data.last_sig, FALSE, TRUE, 0);
6111 hbox = gtk_hbox_new (FALSE, 3);
6112 gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0);
6113 label = gtk_label_new ("Previous signal:");
6114 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
6115 calendar_data.prev_sig = gtk_label_new ("");
6116 gtk_box_pack_start (GTK_BOX (hbox), calendar_data.prev_sig, FALSE, TRUE, 0);
6118 hbox = gtk_hbox_new (FALSE, 3);
6119 gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0);
6120 label = gtk_label_new ("Second previous signal:");
6121 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
6122 calendar_data.prev2_sig = gtk_label_new ("");
6123 gtk_box_pack_start (GTK_BOX (hbox), calendar_data.prev2_sig, FALSE, TRUE, 0);
6125 bbox = gtk_hbutton_box_new ();
6126 gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
6127 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
6129 button = gtk_button_new_with_label ("Close");
6130 gtk_signal_connect (GTK_OBJECT (button), "clicked",
6131 GTK_SIGNAL_FUNC (gtk_main_quit),
6133 gtk_container_add (GTK_CONTAINER (bbox), button);
6134 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
6135 gtk_widget_grab_default (button);
6137 gtk_widget_show_all(window);
6145 gtk_init (&argc, &argv);
6158 <!-- ----------------------------------------------------------------- -->
6159 <sect1> Color Selection
6161 The color selection widget is, not surprisingly, a widget for
6162 interactive selection of colors. This composite widget lets the user
6163 select a color by manipulating RGB (Red, Green, Blue) and HSV (Hue,
6164 Saturation, Value) triples. This is done either by adjusting single
6165 values with sliders or entries, or by picking the desired color from a
6166 hue-saturation wheel/value bar. Optionally, the opacity of the color
6169 The color selection widget currently emits only one signal,
6170 "color_changed", which is emitted whenever the current color in the
6171 widget changes, either when the user changes it or if it's set
6172 explicitly through gtk_color_selection_set_color().
6174 Lets have a look at what the color selection widget has to offer
6175 us. The widget comes in two flavours: gtk_color_selection and
6176 gtk_color_selection_dialog.
6179 GtkWidget *gtk_color_selection_new( void );
6182 You'll probably not be using this constructor directly. It creates an
6183 orphan ColorSelection widget which you'll have to parent
6184 yourself. The ColorSelection widget inherits from the VBox
6188 GtkWidget *gtk_color_selection_dialog_new( const gchar *title );
6191 This is the most common color selection constructor. It creates a
6192 ColorSelectionDialog. It consists of a Frame containing a
6193 ColorSelection widget, an HSeparator and an HBox with three buttons,
6194 "Ok", "Cancel" and "Help". You can reach these buttons by accessing
6195 the "ok_button", "cancel_button" and "help_button" widgets in the
6196 ColorSelectionDialog structure,
6197 (i.e., <tt>GTK_COLOR_SELECTION_DIALOG(colorseldialog)->ok_button</tt>)).
6200 void gtk_color_selection_set_update_policy( GtkColorSelection *colorsel,
6201 GtkUpdateType policy );
6204 This function sets the update policy. The default policy is
6205 <tt/GTK_UPDATE_CONTINUOUS/ which means that the current color is
6206 updated continuously when the user drags the sliders or presses the
6207 mouse and drags in the hue-saturation wheel or value bar. If you
6208 experience performance problems, you may want to set the policy to
6209 <tt/GTK_UPDATE_DISCONTINUOUS/ or <tt/GTK_UPDATE_DELAYED/.
6212 void gtk_color_selection_set_opacity( GtkColorSelection *colorsel,
6216 The color selection widget supports adjusting the opacity of a color
6217 (also known as the alpha channel). This is disabled by
6218 default. Calling this function with use_opacity set to TRUE enables
6219 opacity. Likewise, use_opacity set to FALSE will disable opacity.
6222 void gtk_color_selection_set_color( GtkColorSelection *colorsel,
6226 You can set the current color explicitly by calling this function with
6227 a pointer to an array of colors (gdouble). The length of the array
6228 depends on whether opacity is enabled or not. Position 0 contains the
6229 red component, 1 is green, 2 is blue and opacity is at position 3
6230 (only if opacity is enabled, see
6231 gtk_color_selection_set_opacity()). All values are between 0.0 and
6235 void gtk_color_selection_get_color( GtkColorSelection *colorsel,
6239 When you need to query the current color, typically when you've
6240 received a "color_changed" signal, you use this function. Color is a
6241 pointer to the array of colors to fill in. See the
6242 gtk_color_selection_set_color() function for the description of this
6245 <!-- Need to do a whole section on DnD - TRG
6249 The color sample areas (right under the hue-saturation wheel) supports
6250 drag and drop. The type of drag and drop is "application/x-color". The
6251 message data consists of an array of 4 (or 5 if opacity is enabled)
6252 gdouble values, where the value at position 0 is 0.0 (opacity on) or
6253 1.0 (opacity off) followed by the red, green and blue values at
6254 positions 1,2 and 3 respectively. If opacity is enabled, the opacity
6255 is passed in the value at position 4.
6258 Here's a simple example demonstrating the use of the
6259 ColorSelectionDialog. The program displays a window containing a
6260 drawing area. Clicking on it opens a color selection dialog, and
6261 changing the color in the color selection dialog changes the
6265 /* example-start colorsel colorsel.c */
6268 #include <gdk/gdk.h>
6269 #include <gtk/gtk.h>
6271 GtkWidget *colorseldlg = NULL;
6272 GtkWidget *drawingarea = NULL;
6274 /* Color changed handler */
6276 void color_changed_cb( GtkWidget *widget,
6277 GtkColorSelection *colorsel )
6281 GdkColormap *colormap;
6283 /* Get drawingarea colormap */
6285 colormap = gdk_window_get_colormap (drawingarea->window);
6287 /* Get current color */
6289 gtk_color_selection_get_color (colorsel,color);
6291 /* Fit to a unsigned 16 bit integer (0..65535) and
6292 * insert into the GdkColor structure */
6294 gdk_color.red = (guint16)(color[0]*65535.0);
6295 gdk_color.green = (guint16)(color[1]*65535.0);
6296 gdk_color.blue = (guint16)(color[2]*65535.0);
6298 /* Allocate color */
6300 gdk_color_alloc (colormap, &gdk_color);
6302 /* Set window background color */
6304 gdk_window_set_background (drawingarea->window, &gdk_color);
6308 gdk_window_clear (drawingarea->window);
6311 /* Drawingarea event handler */
6313 gint area_event( GtkWidget *widget,
6315 gpointer client_data )
6317 gint handled = FALSE;
6318 GtkWidget *colorsel;
6320 /* Check if we've received a button pressed event */
6322 if (event->type == GDK_BUTTON_PRESS && colorseldlg == NULL)
6324 /* Yes, we have an event and there's no colorseldlg yet! */
6328 /* Create color selection dialog */
6330 colorseldlg = gtk_color_selection_dialog_new("Select background color");
6332 /* Get the ColorSelection widget */
6334 colorsel = GTK_COLOR_SELECTION_DIALOG(colorseldlg)->colorsel;
6336 /* Connect to the "color_changed" signal, set the client-data
6337 * to the colorsel widget */
6339 gtk_signal_connect(GTK_OBJECT(colorsel), "color_changed",
6340 (GtkSignalFunc)color_changed_cb, (gpointer)colorsel);
6342 /* Show the dialog */
6344 gtk_widget_show(colorseldlg);
6350 /* Close down and exit handler */
6352 gint destroy_window( GtkWidget *widget,
6354 gpointer client_data )
6362 gint main( gint argc,
6367 /* Initialize the toolkit, remove gtk-related commandline stuff */
6369 gtk_init (&argc,&argv);
6371 /* Create toplevel window, set title and policies */
6373 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6374 gtk_window_set_title (GTK_WINDOW(window), "Color selection test");
6375 gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, TRUE);
6377 /* Attach to the "delete" and "destroy" events so we can exit */
6379 gtk_signal_connect (GTK_OBJECT(window), "delete_event",
6380 (GtkSignalFunc)destroy_window, (gpointer)window);
6382 /* Create drawingarea, set size and catch button events */
6384 drawingarea = gtk_drawing_area_new ();
6386 gtk_drawing_area_size (GTK_DRAWING_AREA(drawingarea), 200, 200);
6388 gtk_widget_set_events (drawingarea, GDK_BUTTON_PRESS_MASK);
6390 gtk_signal_connect (GTK_OBJECT(drawingarea), "event",
6391 (GtkSignalFunc)area_event, (gpointer)drawingarea);
6393 /* Add drawingarea to window, then show them both */
6395 gtk_container_add (GTK_CONTAINER(window), drawingarea);
6397 gtk_widget_show (drawingarea);
6398 gtk_widget_show (window);
6400 /* Enter the gtk main loop (this never returns) */
6404 /* Satisfy grumpy compilers */
6411 <!-- ----------------------------------------------------------------- -->
6412 <sect1> File Selections
6414 The file selection widget is a quick and simple way to display a File
6415 dialog box. It comes complete with Ok, Cancel, and Help buttons, a
6416 great way to cut down on programming time.
6418 To create a new file selection box use:
6421 GtkWidget *gtk_file_selection_new( gchar *title );
6424 To set the filename, for example to bring up a specific directory, or
6425 give a default filename, use this function:
6428 void gtk_file_selection_set_filename( GtkFileSelection *filesel,
6432 To grab the text that the user has entered or clicked on, use this
6436 gchar *gtk_file_selection_get_filename( GtkFileSelection *filesel );
6439 There are also pointers to the widgets contained within the file
6440 selection widget. These are:
6453 Most likely you will want to use the ok_button, cancel_button, and
6454 help_button pointers in signaling their use.
6456 Included here is an example stolen from testgtk.c, modified to run on
6457 its own. As you will see, there is nothing much to creating a file
6458 selection widget. While in this example the Help button appears on the
6459 screen, it does nothing as there is not a signal attached to it.
6462 /* example-start filesel filesel.c */
6464 #include <gtk/gtk.h>
6466 /* Get the selected filename and print it to the console */
6467 void file_ok_sel( GtkWidget *w,
6468 GtkFileSelection *fs )
6470 g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
6473 void destroy( GtkWidget *widget,
6484 gtk_init (&argc, &argv);
6486 /* Create a new file selection widget */
6487 filew = gtk_file_selection_new ("File selection");
6489 gtk_signal_connect (GTK_OBJECT (filew), "destroy",
6490 (GtkSignalFunc) destroy, &filew);
6491 /* Connect the ok_button to file_ok_sel function */
6492 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
6493 "clicked", (GtkSignalFunc) file_ok_sel, filew );
6495 /* Connect the cancel_button to destroy the widget */
6496 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION
6497 (filew)->cancel_button),
6498 "clicked", (GtkSignalFunc) gtk_widget_destroy,
6499 GTK_OBJECT (filew));
6501 /* Lets set the filename, as if this were a save dialog, and we are giving
6502 a default filename */
6503 gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew),
6506 gtk_widget_show(filew);
6513 <!-- ***************************************************************** -->
6514 <sect> Container Widgets
6515 <!-- ***************************************************************** -->
6517 <!-- ----------------------------------------------------------------- -->
6518 <sect1>The EventBox <label id="sec_EventBox">
6520 Some GTK widgets don't have associated X windows, so they just draw on
6521 their parents. Because of this, they cannot receive events and if they
6522 are incorrectly sized, they don't clip so you can get messy
6523 overwriting, etc. If you require more from these widgets, the EventBox
6526 At first glance, the EventBox widget might appear to be totally
6527 useless. It draws nothing on the screen and responds to no
6528 events. However, it does serve a function - it provides an X window
6529 for its child widget. This is important as many GTK widgets do not
6530 have an associated X window. Not having an X window saves memory and
6531 improves performance, but also has some drawbacks. A widget without an
6532 X window cannot receive events, and does not perform any clipping on
6533 its contents. Although the name <em/EventBox/ emphasizes the
6534 event-handling function, the widget can also be used for clipping.
6535 (and more, see the example below).
6537 To create a new EventBox widget, use:
6540 GtkWidget *gtk_event_box_new( void );
6543 A child widget can then be added to this EventBox:
6546 gtk_container_add( GTK_CONTAINER(event_box), child_widget );
6549 The following example demonstrates both uses of an EventBox - a label
6550 is created that is clipped to a small box, and set up so that a
6551 mouse-click on the label causes the program to exit. Resizing the
6552 window reveals varying amounts of the label.
6555 /* example-start eventbox eventbox.c */
6557 #include <gtk/gtk.h>
6563 GtkWidget *event_box;
6566 gtk_init (&argc, &argv);
6568 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6570 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
6572 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6573 GTK_SIGNAL_FUNC (gtk_exit), NULL);
6575 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6577 /* Create an EventBox and add it to our toplevel window */
6579 event_box = gtk_event_box_new ();
6580 gtk_container_add (GTK_CONTAINER(window), event_box);
6581 gtk_widget_show (event_box);
6583 /* Create a long label */
6585 label = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
6586 gtk_container_add (GTK_CONTAINER (event_box), label);
6587 gtk_widget_show (label);
6589 /* Clip it short. */
6590 gtk_widget_set_usize (label, 110, 20);
6592 /* And bind an action to it */
6593 gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
6594 gtk_signal_connect (GTK_OBJECT(event_box), "button_press_event",
6595 GTK_SIGNAL_FUNC (gtk_exit), NULL);
6597 /* Yet one more thing you need an X window for ... */
6599 gtk_widget_realize (event_box);
6600 gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1));
6602 gtk_widget_show (window);
6611 <!-- ----------------------------------------------------------------- -->
6612 <sect1>The Alignment widget <label id="sec_Alignment">
6614 The alignment widget allows you to place a widget within its window at
6615 a position and size relative to the size of the Alignment widget
6616 itself. For example, it can be very useful for centering a widget
6619 There are only two functions associated with the Alignment widget:
6622 GtkWidget* gtk_alignment_new( gfloat xalign,
6627 void gtk_alignment_set( GtkAlignment *alignment,
6634 The first function creates a new Alignment widget with the specified
6635 parameters. The second function allows the alignment paramters of an
6636 exisiting Alignment widget to be altered.
6638 All four alignment parameters are floating point numbers which can
6639 range from 0.0 to 1.0. The <tt/xalign/ and <tt/yalign/ arguments
6640 affect the position of the widget placed within the Alignment
6641 widget. The <tt/xscale/ and <tt/yscale/ arguments affect the amount of
6642 space allocated to the widget.
6644 A child widget can be added to this Alignment widget using:
6647 gtk_container_add( GTK_CONTAINER(alignment), child_widget );
6650 For an example of using an Alignment widget, refer to the example for
6651 the <ref id="sec_ProgressBar" name="Progress Bar"> widget.
6653 <!-- ----------------------------------------------------------------- -->
6654 <sect1> Fixed Container
6656 The Fixed container allows you to place widgets at a fixed position
6657 within its window, relative to its upper left hand corner. The
6658 position of the widgets can be changed dynamically.
6660 There are only three functions associated with the fixed widget:
6663 GtkWidget* gtk_fixed_new( void );
6665 void gtk_fixed_put( GtkFixed *fixed,
6670 void gtk_fixed_move( GtkFixed *fixed,
6676 The function <tt/gtk_fixed_new/ allows you to create a new Fixed
6679 <tt/gtk_fixed_put/ places <tt/widget/ in the container <tt/fixed/ at
6680 the position specified by <tt/x/ and <tt/y/.
6682 <tt/gtk_fixed_move/ allows the specified widget to be moved to a new
6685 The following example illustrates how to use the Fixed Container.
6688 /* example-start fixed fixed.c */
6690 #include <gtk/gtk.h>
6692 /* I'm going to be lazy and use some global variables to
6693 * store the position of the widget within the fixed
6698 /* This callback function moves the button to a new position
6699 * in the Fixed container. */
6700 void move_button( GtkWidget *widget,
6705 gtk_fixed_move( GTK_FIXED(fixed), widget, x, y);
6711 /* GtkWidget is the storage type for widgets */
6717 /* Initialise GTK */
6718 gtk_init(&argc, &argv);
6720 /* Create a new window */
6721 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6722 gtk_window_set_title(GTK_WINDOW(window), "Fixed Container");
6724 /* Here we connect the "destroy" event to a signal handler */
6725 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6726 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
6728 /* Sets the border width of the window. */
6729 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6731 /* Create a Fixed Container */
6732 fixed = gtk_fixed_new();
6733 gtk_container_add(GTK_CONTAINER(window), fixed);
6734 gtk_widget_show(fixed);
6736 for (i = 1 ; i <= 3 ; i++) {
6737 /* Creates a new button with the label "Press me" */
6738 button = gtk_button_new_with_label ("Press me");
6740 /* When the button receives the "clicked" signal, it will call the
6741 * function move_button() passing it the Fixed Container as its
6743 gtk_signal_connect (GTK_OBJECT (button), "clicked",
6744 GTK_SIGNAL_FUNC (move_button), fixed);
6746 /* This packs the button into the fixed containers window. */
6747 gtk_fixed_put (GTK_FIXED (fixed), button, i*50, i*50);
6749 /* The final step is to display this newly created widget. */
6750 gtk_widget_show (button);
6753 /* Display the window */
6754 gtk_widget_show (window);
6756 /* Enter the event loop */
6764 <!-- ----------------------------------------------------------------- -->
6765 <sect1> Layout Container
6767 The Layout container is similar to the Fixed container except that it
6768 implements an infinite (where infinity is less than 2^32) scrolling
6769 area. The X window system has a limitation where windows can be at
6770 most 32767 pixels wide or tall. The Layout container gets around this
6771 limitation by doing some exotic stuff using window and bit gravities,
6772 so that you can have smooth scrolling even when you have many child
6773 widgets in your scrolling area.
6775 A Layout container is created using:
6778 GtkWidget *gtk_layout_new( GtkAdjustment *hadjustment,
6779 GtkAdjustment *vadjustment );
6782 As you can see, you can optionally specify the Adjustment objects that
6783 the Layout widget will use for its scrolling.
6785 You can add and move widgets in the Layout container using the
6786 following two functions:
6789 void gtk_layout_put( GtkLayout *layout,
6794 void gtk_layout_move( GtkLayout *layout,
6800 The size of the Layout container can be set using the next function:
6803 void gtk_layout_set_size( GtkLayout *layout,
6808 Layout containers are one of the very few widgets in the GTK widget
6809 set that actively repaint themselves on screen as they are changed
6810 using the above functions (the vast majority of widgets queue
6811 requests which are then processed when control returns to the
6812 <tt/gtk_main()/ function).
6814 When you want to make a large number of changes to a Layout container,
6815 you can use the following two functions to disable and re-enable this
6816 repainting functionality:
6819 void gtk_layout_freeze( GtkLayout *layout );
6821 void gtk_layout_thaw( GtkLayout *layout );
6824 The final four functions for use with Layout widgets are for
6825 manipulating the horizontal and vertical adjustment widgets:
6828 GtkAdjustment* gtk_layout_get_hadjustment( GtkLayout *layout );
6830 GtkAdjustment* gtk_layout_get_vadjustment( GtkLayout *layout );
6832 void gtk_layout_set_hadjustment( GtkLayout *layout,
6833 GtkAdjustment *adjustment );
6835 void gtk_layout_set_vadjustment( GtkLayout *layout,
6836 GtkAdjustment *adjustment);
6839 <!-- ----------------------------------------------------------------- -->
6840 <sect1> Frames <label id="sec_Frames">
6842 Frames can be used to enclose one or a group of widgets with a box
6843 which can optionally be labelled. The position of the label and the
6844 style of the box can be altered to suit.
6846 A Frame can be created with the following function:
6849 GtkWidget *gtk_frame_new( const gchar *label );
6852 The label is by default placed in the upper left hand corner of the
6853 frame. A value of NULL for the <tt/label/ argument will result in no
6854 label being displayed. The text of the label can be changed using the
6858 void gtk_frame_set_label( GtkFrame *frame,
6859 const gchar *label );
6862 The position of the label can be changed using this function:
6865 void gtk_frame_set_label_align( GtkFrame *frame,
6870 <tt/xalign/ and <tt/yalign/ take values between 0.0 and 1.0. <tt/xalign/
6871 indicates the position of the label along the top horizontal of the
6872 frame. <tt/yalign/ is not currently used. The default value of xalign
6873 is 0.0 which places the label at the left hand end of the frame.
6875 The next function alters the style of the box that is used to outline
6879 void gtk_frame_set_shadow_type( GtkFrame *frame,
6880 GtkShadowType type);
6883 The <tt/type/ argument can take one of the following values:
6888 GTK_SHADOW_ETCHED_IN (the default)
6889 GTK_SHADOW_ETCHED_OUT
6892 The following code example illustrates the use of the Frame widget.
6895 /* example-start frame frame.c */
6897 #include <gtk/gtk.h>
6902 /* GtkWidget is the storage type for widgets */
6908 /* Initialise GTK */
6909 gtk_init(&argc, &argv);
6911 /* Create a new window */
6912 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6913 gtk_window_set_title(GTK_WINDOW(window), "Frame Example");
6915 /* Here we connect the "destroy" event to a signal handler */
6916 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6917 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
6919 gtk_widget_set_usize(window, 300, 300);
6920 /* Sets the border width of the window. */
6921 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6923 /* Create a Frame */
6924 frame = gtk_frame_new(NULL);
6925 gtk_container_add(GTK_CONTAINER(window), frame);
6927 /* Set the frame's label */
6928 gtk_frame_set_label( GTK_FRAME(frame), "GTK Frame Widget" );
6930 /* Align the label at the right of the frame */
6931 gtk_frame_set_label_align( GTK_FRAME(frame), 1.0, 0.0);
6933 /* Set the style of the frame */
6934 gtk_frame_set_shadow_type( GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
6936 gtk_widget_show(frame);
6938 /* Display the window */
6939 gtk_widget_show (window);
6941 /* Enter the event loop */
6950 <!-- ----------------------------------------------------------------- -->
6951 <sect1> Aspect Frames
6953 The aspect frame widget is like a frame widget, except that it also
6954 enforces the aspect ratio (that is, the ratio of the width to the
6955 height) of the child widget to have a certain value, adding extra
6956 space if necessary. This is useful, for instance, if you want to
6957 preview a larger image. The size of the preview should vary when the
6958 user resizes the window, but the aspect ratio needs to always match
6961 To create a new aspect frame use:
6964 GtkWidget *gtk_aspect_frame_new( const gchar *label,
6971 <tt/xalign/ and <tt/yalign/ specify alignment as with Alignment
6972 widgets. If <tt/obey_child/ is true, the aspect ratio of a child
6973 widget will match the aspect ratio of the ideal size it requests.
6974 Otherwise, it is given by <tt/ratio/.
6976 To change the options of an existing aspect frame, you can use:
6979 void gtk_aspect_frame_set( GtkAspectFrame *aspect_frame,
6986 As an example, the following program uses an AspectFrame to present a
6987 drawing area whose aspect ratio will always be 2:1, no matter how the
6988 user resizes the top-level window.
6991 /* example-start aspectframe aspectframe.c */
6993 #include <gtk/gtk.h>
6999 GtkWidget *aspect_frame;
7000 GtkWidget *drawing_area;
7001 gtk_init (&argc, &argv);
7003 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
7004 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
7005 gtk_signal_connect (GTK_OBJECT (window), "destroy",
7006 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
7007 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
7009 /* Create an aspect_frame and add it to our toplevel window */
7011 aspect_frame = gtk_aspect_frame_new ("2x1", /* label */
7014 2, /* xsize/ysize = 2 */
7015 FALSE /* ignore child's aspect */);
7017 gtk_container_add (GTK_CONTAINER(window), aspect_frame);
7018 gtk_widget_show (aspect_frame);
7020 /* Now add a child widget to the aspect frame */
7022 drawing_area = gtk_drawing_area_new ();
7024 /* Ask for a 200x200 window, but the AspectFrame will give us a 200x100
7025 * window since we are forcing a 2x1 aspect ratio */
7026 gtk_widget_set_usize (drawing_area, 200, 200);
7027 gtk_container_add (GTK_CONTAINER(aspect_frame), drawing_area);
7028 gtk_widget_show (drawing_area);
7030 gtk_widget_show (window);
7037 <!-- ----------------------------------------------------------------- -->
7038 <sect1> Paned Window Widgets
7040 The paned window widgets are useful when you want to divide an area
7041 into two parts, with the relative size of the two parts controlled by
7042 the user. A groove is drawn between the two portions with a handle
7043 that the user can drag to change the ratio. The division can either be
7044 horizontal (HPaned) or vertical (VPaned).
7046 To create a new paned window, call one of:
7049 GtkWidget *gtk_hpaned_new (void);
7051 GtkWidget *gtk_vpaned_new (void);
7054 After creating the paned window widget, you need to add child widgets
7055 to its two halves. To do this, use the functions:
7058 void gtk_paned_add1 (GtkPaned *paned, GtkWidget *child);
7060 void gtk_paned_add2 (GtkPaned *paned, GtkWidget *child);
7063 <tt/gtk_paned_add1()/ adds the child widget to the left or top half of
7064 the paned window. <tt/gtk_paned_add2()/ adds the child widget to the
7065 right or bottom half of the paned window.
7067 A paned widget can be changed visually using the following two
7071 void gtk_paned_set_handle_size( GtkPaned *paned,
7074 void gtk_paned_set_gutter_size( GtkPaned *paned,
7078 The first of these sets the size of the handle and the second sets the
7079 size of the gutter that is between the two parts of the paned window.
7081 As an example, we will create part of the user interface of an
7082 imaginary email program. A window is divided into two portions
7083 vertically, with the top portion being a list of email messages and
7084 the bottom portion the text of the email message. Most of the program
7085 is pretty straightforward. A couple of points to note: text can't be
7086 added to a Text widget until it is realized. This could be done by
7087 calling <tt/gtk_widget_realize()/, but as a demonstration of an
7088 alternate technique, we connect a handler to the "realize" signal to
7089 add the text. Also, we need to add the <tt/GTK_SHRINK/ option to some
7090 of the items in the table containing the text window and its
7091 scrollbars, so that when the bottom portion is made smaller, the
7092 correct portions shrink instead of being pushed off the bottom of the
7096 /* example-start paned paned.c */
7099 #include <gtk/gtk.h>
7101 /* Create the list of "messages" */
7102 GtkWidget *create_list( void )
7105 GtkWidget *scrolled_window;
7107 GtkWidget *list_item;
7112 /* Create a new scrolled window, with scrollbars only if needed */
7113 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
7114 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
7115 GTK_POLICY_AUTOMATIC,
7116 GTK_POLICY_AUTOMATIC);
7118 /* Create a new list and put it in the scrolled window */
7119 list = gtk_list_new ();
7120 gtk_scrolled_window_add_with_viewport (
7121 GTK_SCROLLED_WINDOW (scrolled_window), list);
7122 gtk_widget_show (list);
7124 /* Add some messages to the window */
7125 for (i=0; i<10; i++) {
7127 sprintf(buffer,"Message #%d",i);
7128 list_item = gtk_list_item_new_with_label (buffer);
7129 gtk_container_add (GTK_CONTAINER(list), list_item);
7130 gtk_widget_show (list_item);
7134 return scrolled_window;
7137 /* Add some text to our text widget - this is a callback that is invoked
7138 when our window is realized. We could also force our window to be
7139 realized with gtk_widget_realize, but it would have to be part of
7140 a hierarchy first */
7142 void realize_text( GtkWidget *text,
7145 gtk_text_freeze (GTK_TEXT (text));
7146 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
7147 "From: pathfinder@nasa.gov\n"
7148 "To: mom@nasa.gov\n"
7149 "Subject: Made it!\n"
7151 "We just got in this morning. The weather has been\n"
7152 "great - clear but cold, and there are lots of fun sights.\n"
7153 "Sojourner says hi. See you soon.\n"
7156 gtk_text_thaw (GTK_TEXT (text));
7159 /* Create a scrolled text area that displays a "message" */
7160 GtkWidget *create_text( void )
7164 GtkWidget *hscrollbar;
7165 GtkWidget *vscrollbar;
7167 /* Create a table to hold the text widget and scrollbars */
7168 table = gtk_table_new (2, 2, FALSE);
7170 /* Put a text widget in the upper left hand corner. Note the use of
7171 * GTK_SHRINK in the y direction */
7172 text = gtk_text_new (NULL, NULL);
7173 gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
7174 GTK_FILL | GTK_EXPAND,
7175 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
7176 gtk_widget_show (text);
7178 /* Put a HScrollbar in the lower left hand corner */
7179 hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
7180 gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
7181 GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
7182 gtk_widget_show (hscrollbar);
7184 /* And a VScrollbar in the upper right */
7185 vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
7186 gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
7187 GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
7188 gtk_widget_show (vscrollbar);
7190 /* Add a handler to put a message in the text widget when it is realized */
7191 gtk_signal_connect (GTK_OBJECT (text), "realize",
7192 GTK_SIGNAL_FUNC (realize_text), NULL);
7205 gtk_init (&argc, &argv);
7207 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
7208 gtk_window_set_title (GTK_WINDOW (window), "Paned Windows");
7209 gtk_signal_connect (GTK_OBJECT (window), "destroy",
7210 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
7211 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
7212 gtk_widget_set_usize (GTK_WIDGET(window), 450, 400);
7214 /* create a vpaned widget and add it to our toplevel window */
7216 vpaned = gtk_vpaned_new ();
7217 gtk_container_add (GTK_CONTAINER(window), vpaned);
7218 gtk_paned_set_handle_size (GTK_PANED(vpaned),
7220 gtk_paned_set_gutter_size (GTK_PANED(vpaned),
7222 gtk_widget_show (vpaned);
7224 /* Now create the contents of the two halves of the window */
7226 list = create_list ();
7227 gtk_paned_add1 (GTK_PANED(vpaned), list);
7228 gtk_widget_show (list);
7230 text = create_text ();
7231 gtk_paned_add2 (GTK_PANED(vpaned), text);
7232 gtk_widget_show (text);
7233 gtk_widget_show (window);
7240 <!-- ----------------------------------------------------------------- -->
7241 <sect1>Viewports <label id="sec_Viewports">
7243 It is unlikely that you will ever need to use the Viewport widget
7244 directly. You are much more likely to use the
7245 <ref id="sec_ScrolledWindow" name="Scrolled Window"> widget which
7246 itself uses the Viewport.
7248 A viewport widget allows you to place a larger widget within it such
7249 that you can view a part of it at a time. It uses
7250 <ref id="sec_Adjustment" name="Adjustments"> to define the area that
7251 is currently in view.
7253 A Viewport is created with the function
7256 GtkWidget *gtk_viewport_new( GtkAdjustment *hadjustment,
7257 GtkAdjustment *vadjustment );
7260 As you can see you can specify the horizontal and vertical Adjustments
7261 that the widget is to use when you create the widget. It will create
7262 its own if you pass NULL as the value of the arguments.
7264 You can get and set the adjustments after the widget has been created
7265 using the following four functions:
7268 GtkAdjustment *gtk_viewport_get_hadjustment (GtkViewport *viewport );
7270 GtkAdjustment *gtk_viewport_get_vadjustment (GtkViewport *viewport );
7272 void gtk_viewport_set_hadjustment( GtkViewport *viewport,
7273 GtkAdjustment *adjustment );
7275 void gtk_viewport_set_vadjustment( GtkViewport *viewport,
7276 GtkAdjustment *adjustment );
7279 The only other viewport function is used to alter its appearance:
7282 void gtk_viewport_set_shadow_type( GtkViewport *viewport,
7283 GtkShadowType type );
7286 Possible values for the <tt/type/ parameter are:
7291 GTK_SHADOW_ETCHED_IN,
7292 GTK_SHADOW_ETCHED_OUT
7295 <!-- ----------------------------------------------------------------- -->
7296 <sect1>Scrolled Windows <label id="sec_ScrolledWindow">
7298 Scrolled windows are used to create a scrollable area with another
7299 widget inside it. You may insert any type of widget into a scrolled
7300 window, and it will be accessible regardless of the size by using the
7303 The following function is used to create a new scrolled window.
7306 GtkWidget *gtk_scrolled_window_new( GtkAdjustment *hadjustment,
7307 GtkAdjustment *vadjustment );
7310 Where the first argument is the adjustment for the horizontal
7311 direction, and the second, the adjustment for the vertical direction.
7312 These are almost always set to NULL.
7315 void gtk_scrolled_window_set_policy( GtkScrolledWindow *scrolled_window,
7316 GtkPolicyType hscrollbar_policy,
7317 GtkPolicyType vscrollbar_policy );
7320 This sets the policy to be used with respect to the scrollbars.
7321 The first argument is the scrolled window you wish to change. The second
7322 sets the policy for the horizontal scrollbar, and the third the policy for
7323 the vertical scrollbar.
7325 The policy may be one of <tt/GTK_POLICY_AUTOMATIC/ or
7326 <tt/GTK_POLICY_ALWAYS/. <tt/GTK_POLICY_AUTOMATIC/ will automatically
7327 decide whether you need scrollbars, whereas <tt/GTK_POLICY_ALWAYS/
7328 will always leave the scrollbars there.
7330 You can then place your object into the scrolled window using the
7334 void gtk_scrolled_window_add_with_viewport( GtkScrolledWindow *scrolled_window,
7338 Here is a simple example that packs a table eith 100 toggle buttons
7339 into a scrolled window. I've only commented on the parts that may be
7343 /* example-start scrolledwin scrolledwin.c */
7346 #include <gtk/gtk.h>
7348 void destroy( GtkWidget *widget,
7357 static GtkWidget *window;
7358 GtkWidget *scrolled_window;
7364 gtk_init (&argc, &argv);
7366 /* Create a new dialog window for the scrolled window to be
7368 window = gtk_dialog_new ();
7369 gtk_signal_connect (GTK_OBJECT (window), "destroy",
7370 (GtkSignalFunc) destroy, NULL);
7371 gtk_window_set_title (GTK_WINDOW (window), "GtkScrolledWindow example");
7372 gtk_container_set_border_width (GTK_CONTAINER (window), 0);
7373 gtk_widget_set_usize(window, 300, 300);
7375 /* create a new scrolled window. */
7376 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
7378 gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 10);
7380 /* the policy is one of GTK_POLICY AUTOMATIC, or GTK_POLICY_ALWAYS.
7381 * GTK_POLICY_AUTOMATIC will automatically decide whether you need
7382 * scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars
7383 * there. The first one is the horizontal scrollbar, the second,
7385 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
7386 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
7387 /* The dialog window is created with a vbox packed into it. */
7388 gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)->vbox), scrolled_window,
7390 gtk_widget_show (scrolled_window);
7392 /* create a table of 10 by 10 squares. */
7393 table = gtk_table_new (10, 10, FALSE);
7395 /* set the spacing to 10 on x and 10 on y */
7396 gtk_table_set_row_spacings (GTK_TABLE (table), 10);
7397 gtk_table_set_col_spacings (GTK_TABLE (table), 10);
7399 /* pack the table into the scrolled window */
7400 gtk_scrolled_window_add_with_viewport (
7401 GTK_SCROLLED_WINDOW (scrolled_window), table);
7402 gtk_widget_show (table);
7404 /* this simply creates a grid of toggle buttons on the table
7405 * to demonstrate the scrolled window. */
7406 for (i = 0; i < 10; i++)
7407 for (j = 0; j < 10; j++) {
7408 sprintf (buffer, "button (%d,%d)\n", i, j);
7409 button = gtk_toggle_button_new_with_label (buffer);
7410 gtk_table_attach_defaults (GTK_TABLE (table), button,
7412 gtk_widget_show (button);
7415 /* Add a "close" button to the bottom of the dialog */
7416 button = gtk_button_new_with_label ("close");
7417 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
7418 (GtkSignalFunc) gtk_widget_destroy,
7419 GTK_OBJECT (window));
7421 /* this makes it so the button is the default. */
7423 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
7424 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0);
7426 /* This grabs this button to be the default button. Simply hitting
7427 * the "Enter" key will cause this button to activate. */
7428 gtk_widget_grab_default (button);
7429 gtk_widget_show (button);
7431 gtk_widget_show (window);
7440 Try playing with resizing the window. You'll notice how the scrollbars
7441 react. You may also wish to use the gtk_widget_set_usize() call to set
7442 the default size of the window or other widgets.
7444 <!-- ----------------------------------------------------------------- -->
7447 Button Boxes are a convenient way to quickly layout a group of
7448 buttons. They come in both horizontal and vertical flavours. You
7449 create a new Button Box with one of the following calls, which create
7450 a horizontal or vertical box, respectively:
7453 GtkWidget *gtk_hbutton_box_new( void );
7455 GtkWidget *gtk_vbutton_box_new( void );
7458 The only attributes pertaining to button boxes affect how the buttons
7459 are laid out. You can change the spacing between the buttons with:
7462 void gtk_hbutton_box_set_spacing_default( gint spacing );
7464 void gtk_vbutton_box_set_spacing_default( gint spacing );
7467 Similarly, the current spacing values can be queried using:
7470 gint gtk_hbutton_box_get_spacing_default( void );
7472 gint gtk_vbutton_box_get_spacing_default( void );
7475 The second attribute that we can access affects the layout of the
7476 buttons within the box. It is set using one of:
7479 void gtk_hbutton_box_set_layout_default( GtkButtonBoxStyle layout );
7481 void gtk_vbutton_box_set_layout_default( GtkButtonBoxStyle layout );
7484 The <tt/layout/ argument can take one of the following values:
7487 GTK_BUTTONBOX_DEFAULT_STYLE
7488 GTK_BUTTONBOX_SPREAD
7494 The current layout setting can be retrieved using:
7497 GtkButtonBoxStyle gtk_hbutton_box_get_layout_default( void );
7499 GtkButtonBoxStyle gtk_vbutton_box_get_layout_default( void );
7502 Buttons are added to a Button Box using the usual function:
7505 gtk_container_add( GTK_CONTAINER(button_box), child_widget );
7508 Here's an example that illustrates all the different layout settings
7512 /* example-start buttonbox buttonbox.c */
7514 #include <gtk/gtk.h>
7516 /* Create a Button Box with the specified parameters */
7517 GtkWidget *create_bbox( gint horizontal,
7528 frame = gtk_frame_new (title);
7531 bbox = gtk_hbutton_box_new ();
7533 bbox = gtk_vbutton_box_new ();
7535 gtk_container_set_border_width (GTK_CONTAINER (bbox), 5);
7536 gtk_container_add (GTK_CONTAINER (frame), bbox);
7538 /* Set the appearance of the Button Box */
7539 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), layout);
7540 gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), spacing);
7541 gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), child_w, child_h);
7543 button = gtk_button_new_with_label ("OK");
7544 gtk_container_add (GTK_CONTAINER (bbox), button);
7546 button = gtk_button_new_with_label ("Cancel");
7547 gtk_container_add (GTK_CONTAINER (bbox), button);
7549 button = gtk_button_new_with_label ("Help");
7550 gtk_container_add (GTK_CONTAINER (bbox), button);
7558 static GtkWidget* window = NULL;
7559 GtkWidget *main_vbox;
7562 GtkWidget *frame_horz;
7563 GtkWidget *frame_vert;
7565 /* Initialize GTK */
7566 gtk_init( &argc, &argv );
7568 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
7569 gtk_window_set_title (GTK_WINDOW (window), "Button Boxes");
7571 gtk_signal_connect (GTK_OBJECT (window), "destroy",
7572 GTK_SIGNAL_FUNC(gtk_main_quit),
7575 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
7577 main_vbox = gtk_vbox_new (FALSE, 0);
7578 gtk_container_add (GTK_CONTAINER (window), main_vbox);
7580 frame_horz = gtk_frame_new ("Horizontal Button Boxes");
7581 gtk_box_pack_start (GTK_BOX (main_vbox), frame_horz, TRUE, TRUE, 10);
7583 vbox = gtk_vbox_new (FALSE, 0);
7584 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
7585 gtk_container_add (GTK_CONTAINER (frame_horz), vbox);
7587 gtk_box_pack_start (GTK_BOX (vbox),
7588 create_bbox (TRUE, "Spread (spacing 40)", 40, 85, 20, GTK_BUTTONBOX_SPREAD),
7591 gtk_box_pack_start (GTK_BOX (vbox),
7592 create_bbox (TRUE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
7595 gtk_box_pack_start (GTK_BOX (vbox),
7596 create_bbox (TRUE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
7599 gtk_box_pack_start (GTK_BOX (vbox),
7600 create_bbox (TRUE, "End (spacing 10)", 10, 85, 20, GTK_BUTTONBOX_END),
7603 frame_vert = gtk_frame_new ("Vertical Button Boxes");
7604 gtk_box_pack_start (GTK_BOX (main_vbox), frame_vert, TRUE, TRUE, 10);
7606 hbox = gtk_hbox_new (FALSE, 0);
7607 gtk_container_set_border_width (GTK_CONTAINER (hbox), 10);
7608 gtk_container_add (GTK_CONTAINER (frame_vert), hbox);
7610 gtk_box_pack_start (GTK_BOX (hbox),
7611 create_bbox (FALSE, "Spread (spacing 5)", 5, 85, 20, GTK_BUTTONBOX_SPREAD),
7614 gtk_box_pack_start (GTK_BOX (hbox),
7615 create_bbox (FALSE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
7618 gtk_box_pack_start (GTK_BOX (hbox),
7619 create_bbox (FALSE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
7622 gtk_box_pack_start (GTK_BOX (hbox),
7623 create_bbox (FALSE, "End (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_END),
7626 gtk_widget_show_all (window);
7628 /* Enter the event loop */
7636 <!-- ----------------------------------------------------------------- -->
7639 Toolbars are usually used to group some number of widgets in order to
7640 simplify customization of their look and layout. Typically a toolbar
7641 consists of buttons with icons, labels and tooltips, but any other
7642 widget can also be put inside a toolbar. Finally, items can be
7643 arranged horizontally or vertically and buttons can be displayed with
7644 icons, labels, or both.
7646 Creating a toolbar is (as one may already suspect) done with the
7650 GtkWidget *gtk_toolbar_new( GtkOrientation orientation,
7651 GtkToolbarStyle style );
7654 where orientation may be one of:
7657 GTK_ORIENTATION_HORIZONTAL
7658 GTK_ORIENTATION_VERTICAL
7669 The style applies to all the buttons created with the `item' functions
7670 (not to buttons inserted into toolbar as separate widgets).
7672 After creating a toolbar one can append, prepend and insert items
7673 (that means simple text strings) or elements (that means any widget
7674 types) into the toolbar. To describe an item we need a label text, a
7675 tooltip text, a private tooltip text, an icon for the button and a
7676 callback function for it. For example, to append or prepend an item
7677 you may use the following functions:
7680 GtkWidget *gtk_toolbar_append_item( GtkToolbar *toolbar,
7682 const char *tooltip_text,
7683 const char *tooltip_private_text,
7685 GtkSignalFunc callback,
7686 gpointer user_data );
7688 GtkWidget *gtk_toolbar_prepend_item( GtkToolbar *toolbar,
7690 const char *tooltip_text,
7691 const char *tooltip_private_text,
7693 GtkSignalFunc callback,
7694 gpointer user_data );
7697 If you want to use gtk_toolbar_insert_item, the only additional
7698 parameter which must be specified is the position in which the item
7699 should be inserted, thus:
7702 GtkWidget *gtk_toolbar_insert_item( GtkToolbar *toolbar,
7704 const char *tooltip_text,
7705 const char *tooltip_private_text,
7707 GtkSignalFunc callback,
7712 To simplify adding spaces between toolbar items, you may use the
7713 following functions:
7716 void gtk_toolbar_append_space( GtkToolbar *toolbar );
7718 void gtk_toolbar_prepend_space( GtkToolbar *toolbar );
7720 void gtk_toolbar_insert_space( GtkToolbar *toolbar,
7725 While the size of the added space can be set globally for a
7726 whole toolbar with the function:
7729 void gtk_toolbar_set_space_size( GtkToolbar *toolbar,
7733 If it's required, the orientation of a toolbar and its style can be
7734 changed "on the fly" using the following functions:
7737 void gtk_toolbar_set_orientation( GtkToolbar *toolbar,
7738 GtkOrientation orientation );
7740 void gtk_toolbar_set_style( GtkToolbar *toolbar,
7741 GtkToolbarStyle style );
7743 void gtk_toolbar_set_tooltips( GtkToolbar *toolbar,
7747 Where <tt/orientation/ is one of <tt/GTK_ORIENTATION_HORIZONTAL/ or
7748 <tt/GTK_ORIENTATION_VERTICAL/. The <tt/style/ is used to set
7749 appearance of the toolbar items by using one of
7750 <tt/GTK_TOOLBAR_ICONS/, <tt/GTK_TOOLBAR_TEXT/, or
7751 <tt/GTK_TOOLBAR_BOTH/.
7753 To show some other things that can be done with a toolbar, let's take
7754 the following program (we'll interrupt the listing with some
7755 additional explanations):
7758 #include <gtk/gtk.h>
7762 /* This function is connected to the Close button or
7763 * closing the window from the WM */
7764 gint delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
7771 The above beginning seems for sure familiar to you if it's not your first
7772 GTK program. There is one additional thing though, we include a nice XPM
7773 picture to serve as an icon for all of the buttons.
7776 GtkWidget* close_button; /* This button will emit signal to close
7778 GtkWidget* tooltips_button; /* to enable/disable tooltips */
7779 GtkWidget* text_button,
7781 * both_button; /* radio buttons for toolbar style */
7782 GtkWidget* entry; /* a text entry to show packing any widget into
7786 In fact not all of the above widgets are needed here, but to make things
7787 clearer I put them all together.
7790 /* that's easy... when one of the buttons is toggled, we just
7791 * check which one is active and set the style of the toolbar
7793 * ATTENTION: our toolbar is passed as data to callback ! */
7794 void radio_event (GtkWidget *widget, gpointer data)
7796 if (GTK_TOGGLE_BUTTON (text_button)->active)
7797 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_TEXT);
7798 else if (GTK_TOGGLE_BUTTON (icon_button)->active)
7799 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_ICONS);
7800 else if (GTK_TOGGLE_BUTTON (both_button)->active)
7801 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_BOTH);
7804 /* even easier, just check given toggle button and enable/disable
7806 void toggle_event (GtkWidget *widget, gpointer data)
7808 gtk_toolbar_set_tooltips (GTK_TOOLBAR ( data ),
7809 GTK_TOGGLE_BUTTON (widget)->active );
7813 The above are just two callback functions that will be called when
7814 one of the buttons on a toolbar is pressed. You should already be
7815 familiar with things like this if you've already used toggle buttons (and
7819 int main (int argc, char *argv[])
7821 /* Here is our main window (a dialog) and a handle for the handlebox */
7823 GtkWidget* handlebox;
7825 /* Ok, we need a toolbar, an icon with a mask (one for all of
7826 the buttons) and an icon widget to put this icon in (but
7827 we'll create a separate widget for each button) */
7828 GtkWidget * toolbar;
7833 /* this is called in all GTK application. */
7834 gtk_init (&argc, &argv);
7836 /* create a new window with a given title, and nice size */
7837 dialog = gtk_dialog_new ();
7838 gtk_window_set_title ( GTK_WINDOW ( dialog ) , "GTKToolbar Tutorial");
7839 gtk_widget_set_usize( GTK_WIDGET ( dialog ) , 600 , 300 );
7840 GTK_WINDOW ( dialog ) ->allow_shrink = TRUE;
7842 /* typically we quit if someone tries to close us */
7843 gtk_signal_connect ( GTK_OBJECT ( dialog ), "delete_event",
7844 GTK_SIGNAL_FUNC ( delete_event ), NULL);
7846 /* we need to realize the window because we use pixmaps for
7847 * items on the toolbar in the context of it */
7848 gtk_widget_realize ( dialog );
7850 /* to make it nice we'll put the toolbar into the handle box,
7851 * so that it can be detached from the main window */
7852 handlebox = gtk_handle_box_new ();
7853 gtk_box_pack_start ( GTK_BOX ( GTK_DIALOG(dialog)->vbox ),
7854 handlebox, FALSE, FALSE, 5 );
7857 The above should be similar to any other GTK application. Just
7858 initialization of GTK, creating the window, etc. There is only one
7859 thing that probably needs some explanation: a handle box. A handle box
7860 is just another box that can be used to pack widgets in to. The
7861 difference between it and typical boxes is that it can be detached
7862 from a parent window (or, in fact, the handle box remains in the
7863 parent, but it is reduced to a very small rectangle, while all of its
7864 contents are reparented to a new freely floating window). It is
7865 usually nice to have a detachable toolbar, so these two widgets occur
7866 together quite often.
7869 /* toolbar will be horizontal, with both icons and text, and
7870 * with 5pxl spaces between items and finally,
7871 * we'll also put it into our handlebox */
7872 toolbar = gtk_toolbar_new ( GTK_ORIENTATION_HORIZONTAL,
7874 gtk_container_set_border_width ( GTK_CONTAINER ( toolbar ) , 5 );
7875 gtk_toolbar_set_space_size ( GTK_TOOLBAR ( toolbar ), 5 );
7876 gtk_container_add ( GTK_CONTAINER ( handlebox ) , toolbar );
7878 /* now we create icon with mask: we'll reuse it to create
7879 * icon widgets for toolbar items */
7880 icon = gdk_pixmap_create_from_xpm_d ( dialog->window, &mask,
7881 &dialog->style->white, gtk_xpm );
7884 Well, what we do above is just a straightforward initialization of
7885 the toolbar widget and creation of a GDK pixmap with its mask. If you
7886 want to know something more about using pixmaps, refer to GDK
7887 documentation or to the <ref id="sec_Pixmaps" name="Pixmaps"> section
7888 earlier in this tutorial.
7891 /* our first item is <close> button */
7892 iconw = gtk_pixmap_new ( icon, mask ); /* icon widget */
7894 gtk_toolbar_append_item ( GTK_TOOLBAR (toolbar), /* our toolbar */
7895 "Close", /* button label */
7896 "Closes this app", /* this button's tooltip */
7897 "Private", /* tooltip private info */
7898 iconw, /* icon widget */
7899 GTK_SIGNAL_FUNC (delete_event), /* a signal */
7901 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) ); /* space after item */
7904 In the above code you see the simplest case: adding a button to
7905 toolbar. Just before appending a new item, we have to construct a
7906 pixmap widget to serve as an icon for this item; this step will have
7907 to be repeated for each new item. Just after the item we also add a
7908 space, so the following items will not touch each other. As you see
7909 gtk_toolbar_append_item returns a pointer to our newly created button
7910 widget, so that we can work with it in the normal way.
7913 /* now, let's make our radio buttons group... */
7914 iconw = gtk_pixmap_new ( icon, mask );
7915 icon_button = gtk_toolbar_append_element(
7916 GTK_TOOLBAR(toolbar),
7917 GTK_TOOLBAR_CHILD_RADIOBUTTON, /* a type of element */
7918 NULL, /* pointer to widget */
7920 "Only icons in toolbar", /* tooltip */
7921 "Private", /* tooltip private string */
7923 GTK_SIGNAL_FUNC (radio_event), /* signal */
7924 toolbar); /* data for signal */
7925 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7928 Here we begin creating a radio buttons group. To do this we use
7929 gtk_toolbar_append_element. In fact, using this function one can also
7930 +add simple items or even spaces (type = <tt/GTK_TOOLBAR_CHILD_SPACE/
7931 or +<tt/GTK_TOOLBAR_CHILD_BUTTON/). In the above case we start
7932 creating a radio group. In creating other radio buttons for this group
7933 a pointer to the previous button in the group is required, so that a
7934 list of buttons can be easily constructed (see the section on <ref
7935 id="sec_Radio_Buttons" name="Radio Buttons"> earlier in this
7939 /* following radio buttons refer to previous ones */
7940 iconw = gtk_pixmap_new ( icon, mask );
7942 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
7943 GTK_TOOLBAR_CHILD_RADIOBUTTON,
7946 "Only texts in toolbar",
7949 GTK_SIGNAL_FUNC (radio_event),
7951 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7953 iconw = gtk_pixmap_new ( icon, mask );
7955 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
7956 GTK_TOOLBAR_CHILD_RADIOBUTTON,
7959 "Icons and text in toolbar",
7962 GTK_SIGNAL_FUNC (radio_event),
7964 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7965 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(both_button),TRUE);
7968 In the end we have to set the state of one of the buttons manually
7969 (otherwise they all stay in active state, preventing us from switching
7973 /* here we have just a simple toggle button */
7974 iconw = gtk_pixmap_new ( icon, mask );
7976 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
7977 GTK_TOOLBAR_CHILD_TOGGLEBUTTON,
7980 "Toolbar with or without tips",
7983 GTK_SIGNAL_FUNC (toggle_event),
7985 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7986 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tooltips_button),TRUE);
7989 A toggle button can be created in the obvious way (if one knows how to create
7990 radio buttons already).
7993 /* to pack a widget into toolbar, we only have to
7994 * create it and append it with an appropriate tooltip */
7995 entry = gtk_entry_new ();
7996 gtk_toolbar_append_widget( GTK_TOOLBAR (toolbar),
7998 "This is just an entry",
8001 /* well, it isn't created within thetoolbar, so we must still show it */
8002 gtk_widget_show ( entry );
8005 As you see, adding any kind of widget to a toolbar is simple. The
8006 one thing you have to remember is that this widget must be shown manually
8007 (contrary to other items which will be shown together with the toolbar).
8010 /* that's it ! let's show everything. */
8011 gtk_widget_show ( toolbar );
8012 gtk_widget_show (handlebox);
8013 gtk_widget_show ( dialog );
8015 /* rest in gtk_main and wait for the fun to begin! */
8022 So, here we are at the end of toolbar tutorial. Of course, to appreciate
8023 it in full you need also this nice XPM icon, so here it is:
8027 static char * gtk_xpm[] = {
8034 "................+...............",
8035 "..............+++++.............",
8036 "............+++++@@++...........",
8037 "..........+++++@@@@@@++.........",
8038 "........++++@@@@@@@@@@++........",
8039 "......++++@@++++++++@@@++.......",
8040 ".....+++@@@+++++++++++@@@++.....",
8041 "...+++@@@@+++@@@@@@++++@@@@+....",
8042 "..+++@@@@+++@@@@@@@@+++@@@@@++..",
8043 ".++@@@@@@+++@@@@@@@@@@@@@@@@@@++",
8044 ".+#+@@@@@@++@@@@+++@@@@@@@@@@@@+",
8045 ".+##++@@@@+++@@@+++++@@@@@@@@$@.",
8046 ".+###++@@@@+++@@@+++@@@@@++$$$@.",
8047 ".+####+++@@@+++++++@@@@@+@$$$$@.",
8048 ".+#####+++@@@@+++@@@@++@$$$$$$+.",
8049 ".+######++++@@@@@@@++@$$$$$$$$+.",
8050 ".+#######+##+@@@@+++$$$$$$@@$$+.",
8051 ".+###+++##+##+@@++@$$$$$$++$$$+.",
8052 ".+###++++##+##+@@$$$$$$$@+@$$@+.",
8053 ".+###++++++#+++@$$@+@$$@++$$$@+.",
8054 ".+####+++++++#++$$@+@$$++$$$$+..",
8055 ".++####++++++#++$$@+@$++@$$$$+..",
8056 ".+#####+++++##++$$++@+++$$$$$+..",
8057 ".++####+++##+#++$$+++++@$$$$$+..",
8058 ".++####+++####++$$++++++@$$$@+..",
8059 ".+#####++#####++$$+++@++++@$@+..",
8060 ".+#####++#####++$$++@$$@+++$@@..",
8061 ".++####++#####++$$++$$$$$+@$@++.",
8062 ".++####++#####++$$++$$$$$$$$+++.",
8063 ".+++####+#####++$$++$$$$$$$@+++.",
8064 "..+++#########+@$$+@$$$$$$+++...",
8065 "...+++########+@$$$$$$$$@+++....",
8066 ".....+++######+@$$$$$$$+++......",
8067 "......+++#####+@$$$$$@++........",
8068 ".......+++####+@$$$$+++.........",
8069 ".........++###+$$$@++...........",
8070 "..........++##+$@+++............",
8071 "...........+++++++..............",
8072 ".............++++..............."};
8075 <!-- ----------------------------------------------------------------- -->
8078 The NoteBook Widget is a collection of "pages" that overlap each
8079 other, each page contains different information with only one page
8080 visible at a time. This widget has become more common lately in GUI
8081 programming, and it is a good way to show blocks of similar
8082 information that warrant separation in their display.
8084 The first function call you will need to know, as you can probably
8085 guess by now, is used to create a new notebook widget.
8088 GtkWidget *gtk_notebook_new( void );
8091 Once the notebook has been created, there are a number of functions
8092 that operate on the notebook widget. Let's look at them individually.
8094 The first one we will look at is how to position the page indicators.
8095 These page indicators or "tabs" as they are referred to, can be
8096 positioned in four ways: top, bottom, left, or right.
8099 void gtk_notebook_set_tab_pos( GtkNotebook *notebook,
8100 GtkPositionType pos );
8103 GtkPositionType will be one of the following, which are pretty self
8112 <tt/GTK_POS_TOP/ is the default.
8114 Next we will look at how to add pages to the notebook. There are three
8115 ways to add pages to the NoteBook. Let's look at the first two
8116 together as they are quite similar.
8119 void gtk_notebook_append_page( GtkNotebook *notebook,
8121 GtkWidget *tab_label );
8123 void gtk_notebook_prepend_page( GtkNotebook *notebook,
8125 GtkWidget *tab_label );
8128 These functions add pages to the notebook by inserting them from the
8129 back of the notebook (append), or the front of the notebook (prepend).
8130 <tt/child/ is the widget that is placed within the notebook page, and
8131 <tt/tab_label/ is the label for the page being added. The <tt/child/
8132 widget must be created separately, and is typically a set of options
8133 setup witin one of the other container widgets, such as a table.
8135 The final function for adding a page to the notebook contains all of
8136 the properties of the previous two, but it allows you to specify what
8137 position you want the page to be in the notebook.
8140 void gtk_notebook_insert_page( GtkNotebook *notebook,
8142 GtkWidget *tab_label,
8146 The parameters are the same as _append_ and _prepend_ except it
8147 contains an extra parameter, <tt/position/. This parameter is used to
8148 specify what place this page will be inserted into the first page
8149 having position zero.
8151 Now that we know how to add a page, lets see how we can remove a page
8155 void gtk_notebook_remove_page( GtkNotebook *notebook,
8159 This function takes the page specified by <tt/page_num/ and removes it
8160 from the widget pointed to by <tt/notebook/.
8162 To find out what the current page is in a notebook use the function:
8165 gint gtk_notebook_get_current_page( GtkNotebook *notebook );
8168 These next two functions are simple calls to move the notebook page
8169 forward or backward. Simply provide the respective function call with
8170 the notebook widget you wish to operate on. Note: When the NoteBook is
8171 currently on the last page, and gtk_notebook_next_page is called, the
8172 notebook will wrap back to the first page. Likewise, if the NoteBook
8173 is on the first page, and gtk_notebook_prev_page is called, the
8174 notebook will wrap to the last page.
8177 void gtk_notebook_next_page( GtkNoteBook *notebook );
8179 void gtk_notebook_prev_page( GtkNoteBook *notebook );
8182 This next function sets the "active" page. If you wish the notebook to
8183 be opened to page 5 for example, you would use this function. Without
8184 using this function, the notebook defaults to the first page.
8187 void gtk_notebook_set_page( GtkNotebook *notebook,
8191 The next two functions add or remove the notebook page tabs and the
8192 notebook border respectively.
8195 void gtk_notebook_set_show_tabs( GtkNotebook *notebook,
8196 gboolean show_tabs);
8198 void gtk_notebook_set_show_border( GtkNotebook *notebook,
8199 gboolean show_border );
8202 The next function is useful when the you have a large number of pages,
8203 and the tabs don't fit on the page. It allows the tabs to be scrolled
8204 through using two arrow buttons.
8207 void gtk_notebook_set_scrollable( GtkNotebook *notebook,
8208 gboolean scrollable );
8211 <tt/show_tabs/, <tt/show_border/ and <tt/scrollable/ can be either
8214 Now let's look at an example, it is expanded from the testgtk.c code
8215 that comes with the GTK distribution. This small program creates a
8216 window with a notebook and six buttons. The notebook contains 11
8217 pages, added in three different ways, appended, inserted, and
8218 prepended. The buttons allow you rotate the tab positions, add/remove
8219 the tabs and border, remove a page, change pages in both a forward and
8220 backward manner, and exit the program.
8223 /* example-start notebook notebook.c */
8226 #include <gtk/gtk.h>
8228 /* This function rotates the position of the tabs */
8229 void rotate_book( GtkButton *button,
8230 GtkNotebook *notebook )
8232 gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos +1) %4);
8235 /* Add/Remove the page tabs and the borders */
8236 void tabsborder_book( GtkButton *button,
8237 GtkNotebook *notebook )
8241 if (notebook->show_tabs == 0)
8243 if (notebook->show_border == 0)
8246 gtk_notebook_set_show_tabs (notebook, tval);
8247 gtk_notebook_set_show_border (notebook, bval);
8250 /* Remove a page from the notebook */
8251 void remove_book( GtkButton *button,
8252 GtkNotebook *notebook )
8256 page = gtk_notebook_get_current_page(notebook);
8257 gtk_notebook_remove_page (notebook, page);
8258 /* Need to refresh the widget --
8259 This forces the widget to redraw itself. */
8260 gtk_widget_draw(GTK_WIDGET(notebook), NULL);
8263 gint delete( GtkWidget *widget,
8277 GtkWidget *notebook;
8280 GtkWidget *checkbutton;
8285 gtk_init (&argc, &argv);
8287 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
8289 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
8290 GTK_SIGNAL_FUNC (delete), NULL);
8292 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
8294 table = gtk_table_new(3,6,FALSE);
8295 gtk_container_add (GTK_CONTAINER (window), table);
8297 /* Create a new notebook, place the position of the tabs */
8298 notebook = gtk_notebook_new ();
8299 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
8300 gtk_table_attach_defaults(GTK_TABLE(table), notebook, 0,6,0,1);
8301 gtk_widget_show(notebook);
8303 /* Let's append a bunch of pages to the notebook */
8304 for (i=0; i < 5; i++) {
8305 sprintf(bufferf, "Append Frame %d", i+1);
8306 sprintf(bufferl, "Page %d", i+1);
8308 frame = gtk_frame_new (bufferf);
8309 gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
8310 gtk_widget_set_usize (frame, 100, 75);
8311 gtk_widget_show (frame);
8313 label = gtk_label_new (bufferf);
8314 gtk_container_add (GTK_CONTAINER (frame), label);
8315 gtk_widget_show (label);
8317 label = gtk_label_new (bufferl);
8318 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
8321 /* Now let's add a page to a specific spot */
8322 checkbutton = gtk_check_button_new_with_label ("Check me please!");
8323 gtk_widget_set_usize(checkbutton, 100, 75);
8324 gtk_widget_show (checkbutton);
8326 label = gtk_label_new ("Add page");
8327 gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, label, 2);
8329 /* Now finally let's prepend pages to the notebook */
8330 for (i=0; i < 5; i++) {
8331 sprintf(bufferf, "Prepend Frame %d", i+1);
8332 sprintf(bufferl, "PPage %d", i+1);
8334 frame = gtk_frame_new (bufferf);
8335 gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
8336 gtk_widget_set_usize (frame, 100, 75);
8337 gtk_widget_show (frame);
8339 label = gtk_label_new (bufferf);
8340 gtk_container_add (GTK_CONTAINER (frame), label);
8341 gtk_widget_show (label);
8343 label = gtk_label_new (bufferl);
8344 gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook), frame, label);
8347 /* Set what page to start at (page 4) */
8348 gtk_notebook_set_page (GTK_NOTEBOOK(notebook), 3);
8350 /* Create a bunch of buttons */
8351 button = gtk_button_new_with_label ("close");
8352 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
8353 GTK_SIGNAL_FUNC (delete), NULL);
8354 gtk_table_attach_defaults(GTK_TABLE(table), button, 0,1,1,2);
8355 gtk_widget_show(button);
8357 button = gtk_button_new_with_label ("next page");
8358 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
8359 (GtkSignalFunc) gtk_notebook_next_page,
8360 GTK_OBJECT (notebook));
8361 gtk_table_attach_defaults(GTK_TABLE(table), button, 1,2,1,2);
8362 gtk_widget_show(button);
8364 button = gtk_button_new_with_label ("prev page");
8365 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
8366 (GtkSignalFunc) gtk_notebook_prev_page,
8367 GTK_OBJECT (notebook));
8368 gtk_table_attach_defaults(GTK_TABLE(table), button, 2,3,1,2);
8369 gtk_widget_show(button);
8371 button = gtk_button_new_with_label ("tab position");
8372 gtk_signal_connect (GTK_OBJECT (button), "clicked",
8373 (GtkSignalFunc) rotate_book,
8374 GTK_OBJECT(notebook));
8375 gtk_table_attach_defaults(GTK_TABLE(table), button, 3,4,1,2);
8376 gtk_widget_show(button);
8378 button = gtk_button_new_with_label ("tabs/border on/off");
8379 gtk_signal_connect (GTK_OBJECT (button), "clicked",
8380 (GtkSignalFunc) tabsborder_book,
8381 GTK_OBJECT (notebook));
8382 gtk_table_attach_defaults(GTK_TABLE(table), button, 4,5,1,2);
8383 gtk_widget_show(button);
8385 button = gtk_button_new_with_label ("remove page");
8386 gtk_signal_connect (GTK_OBJECT (button), "clicked",
8387 (GtkSignalFunc) remove_book,
8388 GTK_OBJECT(notebook));
8389 gtk_table_attach_defaults(GTK_TABLE(table), button, 5,6,1,2);
8390 gtk_widget_show(button);
8392 gtk_widget_show(table);
8393 gtk_widget_show(window);
8402 I hope this helps you on your way with creating notebooks for your
8405 <!-- ***************************************************************** -->
8407 <!-- ***************************************************************** -->
8409 <!-- ----------------------------------------------------------------- -->
8411 The CList widget has replaced the List widget (which is still
8414 The CList widget is a multi-column list widget that is capable of
8415 handling literally thousands of rows of information. Each column can
8416 optionally have a title, which itself is optionally active, allowing
8417 us to bind a function to its selection.
8419 <!-- ----------------------------------------------------------------- -->
8420 <sect1>Creating a CList widget
8422 Creating a CList is quite straightforward, once you have learned
8423 about widgets in general. It provides the almost standard two ways,
8424 that is the hard way, and the easy way. But before we create it, there
8425 is one thing we should figure out beforehand: how many columns should
8428 Not all columns have to be visible and can be used to store data that
8429 is related to a certain cell in the list.
8432 GtkWidget *gtk_clist_new ( gint columns );
8434 GtkWidget *gtk_clist_new_with_titles( gint columns,
8438 The first form is very straightforward, the second might require some
8439 explanation. Each column can have a title associated with it, and this
8440 title can be a label or a button that reacts when we click on it. If
8441 we use the second form, we must provide pointers to the title texts,
8442 and the number of pointers should equal the number of columns
8443 specified. Of course we can always use the first form, and manually
8446 Note: The CList widget does not have its own scrollbars and should
8447 be placed within a ScrolledWindow widget if your require this
8448 functionality. This is a change from the GTK 1.0 implementation.
8450 <!-- ----------------------------------------------------------------- -->
8451 <sect1>Modes of operation
8453 There are several attributes that can be used to alter the behaviour of
8454 a CList. First there is
8457 void gtk_clist_set_selection_mode( GtkCList *clist,
8458 GtkSelectionMode mode );
8461 which, as the name implies, sets the selection mode of the
8462 CList. The first argument is the CList widget, and the second
8463 specifies the cell selection mode (they are defined in gtkenums.h). At
8464 the time of this writing, the following modes are available to us:
8467 <item> <tt/GTK_SELECTION_SINGLE/ - The selection is either NULL or contains
8468 a GList pointer for a single selected item.
8470 <item> <tt/GTK_SELECTION_BROWSE/ - The selection is NULL if the list
8471 contains no widgets or insensitive ones only, otherwise it contains a
8472 GList pointer for one GList structure, and therefore exactly one list
8475 <item> <tt/GTK_SELECTION_MULTIPLE/ - The selection is NULL if no list items
8476 are selected or a GList pointer for the first selected item. That in
8477 turn points to a GList structure for the second selected item and so
8478 on. This is currently the <bf>default</bf> for the CList widget.
8480 <item> <tt/GTK_SELECTION_EXTENDED/ - The selection is always NULL.
8483 Others might be added in later revisions of GTK.
8485 We can also define what the border of the CList widget should look
8486 like. It is done through
8489 void gtk_clist_set_shadow_type( GtkCList *clist,
8490 GtkShadowType border );
8493 The possible values for the second argument are
8499 GTK_SHADOW_ETCHED_IN
8500 GTK_SHADOW_ETCHED_OUT
8503 <!-- ----------------------------------------------------------------- -->
8504 <sect1>Working with titles
8506 When you create a CList widget, you will also get a set of title
8507 buttons automatically. They live in the top of the CList window, and
8508 can act either as normal buttons that respond to being pressed, or
8509 they can be passive, in which case they are nothing more than a
8510 title. There are four different calls that aid us in setting the
8511 status of the title buttons.
8514 void gtk_clist_column_title_active( GtkCList *clist,
8517 void gtk_clist_column_title_passive( GtkCList *clist,
8520 void gtk_clist_column_titles_active( GtkCList *clist );
8522 void gtk_clist_column_titles_passive( GtkCList *clist );
8525 An active title is one which acts as a normal button, a passive one is
8526 just a label. The first two calls above will activate/deactivate the
8527 title button above the specific column, while the last two calls
8528 activate/deactivate all title buttons in the supplied clist widget.
8530 But of course there are those cases when we don't want them at all,
8531 and so they can be hidden and shown at will using the following two
8535 void gtk_clist_column_titles_show( GtkCList *clist );
8537 void gtk_clist_column_titles_hide( GtkCList *clist );
8540 For titles to be really useful we need a mechanism to set and change
8541 them, and this is done using
8544 void gtk_clist_set_column_title( GtkCList *clist,
8549 Note that only the title of one column can be set at a time, so if all
8550 the titles are known from the beginning, then I really suggest using
8551 gtk_clist_new_with_titles (as described above) to set them. It saves
8552 you coding time, and makes your program smaller. There are some cases
8553 where getting the job done the manual way is better, and that's when
8554 not all titles will be text. CList provides us with title buttons
8555 that can in fact incorporate whole widgets, for example a pixmap. It's
8559 void gtk_clist_set_column_widget( GtkCList *clist,
8561 GtkWidget *widget );
8564 which should require no special explanation.
8566 <!-- ----------------------------------------------------------------- -->
8567 <sect1>Manipulating the list itself
8569 It is possible to change the justification for a column, and it is
8573 void gtk_clist_set_column_justification( GtkCList *clist,
8575 GtkJustification justification );
8578 The GtkJustification type can take the following values:
8581 <item><tt/GTK_JUSTIFY_LEFT/ - The text in the column will begin from the
8584 <item><tt/GTK_JUSTIFY_RIGHT/ - The text in the column will begin from the
8587 <item><tt/GTK_JUSTIFY_CENTER/ - The text is placed in the center of the
8590 <item><tt/GTK_JUSTIFY_FILL/ - The text will use up all available space in
8591 the column. It is normally done by inserting extra blank spaces
8592 between words (or between individual letters if it's a single
8593 word). Much in the same way as any ordinary WYSIWYG text editor.
8596 The next function is a very important one, and should be standard in
8597 the setup of all CList widgets. When the list is created, the width
8598 of the various columns are chosen to match their titles, and since
8599 this is seldom the right width we have to set it using
8602 void gtk_clist_set_column_width( GtkCList *clist,
8607 Note that the width is given in pixels and not letters. The same goes
8608 for the height of the cells in the columns, but as the default value
8609 is the height of the current font this isn't as critical to the
8610 application. Still, it is done through
8613 void gtk_clist_set_row_height( GtkCList *clist,
8617 Again, note that the height is given in pixels.
8619 We can also move the list around without user interaction, however, it
8620 does require that we know what we are looking for. Or in other words,
8621 we need the row and column of the item we want to scroll to.
8624 void gtk_clist_moveto( GtkCList *clist,
8631 The gfloat row_align is pretty important to understand. It's a value
8632 between 0.0 and 1.0, where 0.0 means that we should scroll the list so
8633 the row appears at the top, while if the value of row_align is 1.0,
8634 the row will appear at the bottom instead. All other values between
8635 0.0 and 1.0 are also valid and will place the row between the top and
8636 the bottom. The last argument, gfloat col_align works in the same way,
8637 though 0.0 marks left and 1.0 marks right instead.
8639 Depending on the application's needs, we don't have to scroll to an
8640 item that is already visible to us. So how do we know if it is
8641 visible? As usual, there is a function to find that out as well.
8644 GtkVisibility gtk_clist_row_is_visible( GtkCList *clist,
8648 The return value is is one of the following:
8652 GTK_VISIBILITY_PARTIAL
8656 Note that it will only tell us if a row is visible. Currently there is
8657 no way to determine this for a column. We can get partial information
8658 though, because if the return is <tt/GTK_VISIBILITY_PARTIAL/, then
8659 some of it is hidden, but we don't know if it is the row that is being
8660 cut by the lower edge of the listbox, or if the row has columns that
8663 We can also change both the foreground and background colors of a
8664 particular row. This is useful for marking the row selected by the
8665 user, and the two functions that is used to do it are
8668 void gtk_clist_set_foreground( GtkCList *clist,
8672 void gtk_clist_set_background( GtkCList *clist,
8677 Please note that the colors must have been previously allocated.
8679 <!-- ----------------------------------------------------------------- -->
8680 <sect1>Adding rows to the list
8682 We can add rows in three ways. They can be prepended or appended to
8686 gint gtk_clist_prepend( GtkCList *clist,
8689 gint gtk_clist_append( GtkCList *clist,
8693 The return value of these two functions indicate the index of the row
8694 that was just added. We can insert a row at a given place using
8697 void gtk_clist_insert( GtkCList *clist,
8702 In these calls we have to provide a collection of pointers that are
8703 the texts we want to put in the columns. The number of pointers should
8704 equal the number of columns in the list. If the text[] argument is
8705 NULL, then there will be no text in the columns of the row. This is
8706 useful, for example, if we want to add pixmaps instead (something that
8707 has to be done manually).
8709 Also, please note that the numbering of both rows and columns start at 0.
8711 To remove an individual row we use
8714 void gtk_clist_remove( GtkCList *clist,
8718 There is also a call that removes all rows in the list. This is a lot
8719 faster than calling gtk_clist_remove once for each row, which is the
8723 void gtk_clist_clear( GtkCList *clist );
8726 There are also two convenience functions that should be used when a
8727 lot of changes have to be made to the list. This is to prevent the
8728 list flickering while being repeatedly updated, which may be highly
8729 annoying to the user. So instead it is a good idea to freeze the list,
8730 do the updates to it, and finally thaw it which causes the list to be
8731 updated on the screen.
8734 void gtk_clist_freeze( GtkCList * clist );
8736 void gtk_clist_thaw( GtkCList * clist );
8739 <!-- ----------------------------------------------------------------- -->
8740 <sect1>Setting text and pixmaps in the cells
8742 A cell can contain a pixmap, text or both. To set them the following
8746 void gtk_clist_set_text( GtkCList *clist,
8749 const gchar *text );
8751 void gtk_clist_set_pixmap( GtkCList *clist,
8757 void gtk_clist_set_pixtext( GtkCList *clist,
8766 It's quite straightforward. All the calls have the CList as the first
8767 argument, followed by the row and column of the cell, followed by the
8768 data to be set. The <tt/spacing/ argument in gtk_clist_set_pixtext is
8769 the number of pixels between the pixmap and the beginning of the
8770 text. In all cases the data is copied into the widget.
8772 To read back the data, we instead use
8775 gint gtk_clist_get_text( GtkCList *clist,
8780 gint gtk_clist_get_pixmap( GtkCList *clist,
8786 gint gtk_clist_get_pixtext( GtkCList *clist,
8795 The returned pointers are all pointers to the data stored within the
8796 widget, so the referenced data should not be modified or released. It
8797 isn't necessary to read it all back in case you aren't interested. Any
8798 of the pointers that are meant for return values (all except the
8799 clist) can be NULL. So if we want to read back only the text from a
8800 cell that is of type pixtext, then we would do the following, assuming
8801 that clist, row and column already exist:
8806 gtk_clist_get_pixtext(clist, row, column, &mytext, NULL, NULL, NULL);
8809 There is one more call that is related to what's inside a cell in the
8813 GtkCellType gtk_clist_get_cell_type( GtkCList *clist,
8818 which returns the type of data in a cell. The return value is one of
8828 There is also a function that will let us set the indentation, both
8829 vertical and horizontal, of a cell. The indentation value is of type
8830 gint, given in pixels, and can be both positive and negative.
8833 void gtk_clist_set_shift( GtkCList *clist,
8840 <!-- ----------------------------------------------------------------- -->
8841 <sect1>Storing data pointers
8843 With a CList it is possible to set a data pointer for a row. This
8844 pointer will not be visible for the user, but is merely a convenience
8845 for the programmer to associate a row with a pointer to some
8848 The functions should be fairly self-explanatory by now.
8851 void gtk_clist_set_row_data( GtkCList *clist,
8855 void gtk_clist_set_row_data_full( GtkCList *clist,
8858 GtkDestroyNotify destroy );
8860 gpointer gtk_clist_get_row_data( GtkCList *clist,
8863 gint gtk_clist_find_row_from_data( GtkCList *clist,
8867 <!-- ----------------------------------------------------------------- -->
8868 <sect1>Working with selections
8870 There are also functions available that let us force the (un)selection
8874 void gtk_clist_select_row( GtkCList *clist,
8878 void gtk_clist_unselect_row( GtkCList *clist,
8883 And also a function that will take x and y coordinates (for example,
8884 read from the mousepointer), and map that onto the list, returning the
8885 corresponding row and column.
8888 gint gtk_clist_get_selection_info( GtkCList *clist,
8895 When we detect something of interest (it might be movement of the
8896 pointer, a click somewhere in the list) we can read the pointer
8897 coordinates and find out where in the list the pointer is. Cumbersome?
8898 Luckily, there is a simpler way...
8900 <!-- ----------------------------------------------------------------- -->
8901 <sect1>The signals that bring it together
8903 As with all other widgets, there are a few signals that can be used. The
8904 CList widget is derived from the Container widget, and so has all the
8905 same signals, but also adds the following:
8908 <item>select_row - This signal will send the following information, in
8909 order: GtkCList *clist, gint row, gint column, GtkEventButton *event
8911 <item>unselect_row - When the user unselects a row, this signal is
8912 activated. It sends the same information as select_row
8914 <item>click_column - Send GtkCList *clist, gint column
8917 So if we want to connect a callback to select_row, the callback
8918 function would be declared like this
8921 void select_row_callback(GtkWidget *widget,
8924 GdkEventButton *event,
8928 The callback is connected as usual with
8931 gtk_signal_connect(GTK_OBJECT( clist),
8933 GTK_SIGNAL_FUNC(select_row_callback),
8937 <!-- ----------------------------------------------------------------- -->
8938 <sect1>A CList example
8942 /* example-start clist clist.c */
8944 #include <gtk/gtk.h>
8946 /* User clicked the "Add List" button. */
8947 void button_add_clicked( gpointer data )
8951 /* Something silly to add to the list. 4 rows of 2 columns each */
8952 gchar *drink[4][2] = { { "Milk", "3 Oz" },
8955 { "Snakes", "55" } };
8957 /* Here we do the actual adding of the text. It's done once for
8960 for ( indx=0 ; indx < 4 ; indx++ )
8961 gtk_clist_append( (GtkCList *) data, drink[indx]);
8966 /* User clicked the "Clear List" button. */
8967 void button_clear_clicked( gpointer data )
8969 /* Clear the list using gtk_clist_clear. This is much faster than
8970 * calling gtk_clist_remove once for each row.
8972 gtk_clist_clear( (GtkCList *) data);
8977 /* The user clicked the "Hide/Show titles" button. */
8978 void button_hide_show_clicked( gpointer data )
8980 /* Just a flag to remember the status. 0 = currently visible */
8981 static short int flag = 0;
8985 /* Hide the titles and set the flag to 1 */
8986 gtk_clist_column_titles_hide((GtkCList *) data);
8991 /* Show the titles and reset flag to 0 */
8992 gtk_clist_column_titles_show((GtkCList *) data);
8999 /* If we come here, then the user has selected a row in the list. */
9000 void selection_made( GtkWidget *clist,
9003 GdkEventButton *event,
9008 /* Get the text that is stored in the selected row and column
9009 * which was clicked in. We will receive it as a pointer in the
9012 gtk_clist_get_text(GTK_CLIST(clist), row, column, &text);
9014 /* Just prints some information about the selected row */
9015 g_print("You selected row %d. More specifically you clicked in "
9016 "column %d, and the text in this cell is %s\n\n",
9026 GtkWidget *vbox, *hbox;
9027 GtkWidget *scrolled_window, *clist;
9028 GtkWidget *button_add, *button_clear, *button_hide_show;
9029 gchar *titles[2] = { "Ingredients", "Amount" };
9031 gtk_init(&argc, &argv);
9033 window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
9034 gtk_widget_set_usize(GTK_WIDGET(window), 300, 150);
9036 gtk_window_set_title(GTK_WINDOW(window), "GtkCList Example");
9037 gtk_signal_connect(GTK_OBJECT(window),
9039 GTK_SIGNAL_FUNC(gtk_main_quit),
9042 vbox=gtk_vbox_new(FALSE, 5);
9043 gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
9044 gtk_container_add(GTK_CONTAINER(window), vbox);
9045 gtk_widget_show(vbox);
9047 /* Create a scrolled window to pack the CList widget into */
9048 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
9049 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
9050 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
9052 gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0);
9053 gtk_widget_show (scrolled_window);
9055 /* Create the CList. For this example we use 2 columns */
9056 clist = gtk_clist_new_with_titles( 2, titles);
9058 /* When a selection is made, we want to know about it. The callback
9059 * used is selection_made, and its code can be found further down */
9060 gtk_signal_connect(GTK_OBJECT(clist), "select_row",
9061 GTK_SIGNAL_FUNC(selection_made),
9064 /* It isn't necessary to shadow the border, but it looks nice :) */
9065 gtk_clist_set_shadow_type (GTK_CLIST(clist), GTK_SHADOW_OUT);
9067 /* What however is important, is that we set the column widths as
9068 * they will never be right otherwise. Note that the columns are
9069 * numbered from 0 and up (to 1 in this case).
9071 gtk_clist_set_column_width (GTK_CLIST(clist), 0, 150);
9073 /* Add the CList widget to the vertical box and show it. */
9074 gtk_container_add(GTK_CONTAINER(scrolled_window), clist);
9075 gtk_widget_show(clist);
9077 /* Create the buttons and add them to the window. See the button
9078 * tutorial for more examples and comments on this.
9080 hbox = gtk_hbox_new(FALSE, 0);
9081 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
9082 gtk_widget_show(hbox);
9084 button_add = gtk_button_new_with_label("Add List");
9085 button_clear = gtk_button_new_with_label("Clear List");
9086 button_hide_show = gtk_button_new_with_label("Hide/Show titles");
9088 gtk_box_pack_start(GTK_BOX(hbox), button_add, TRUE, TRUE, 0);
9089 gtk_box_pack_start(GTK_BOX(hbox), button_clear, TRUE, TRUE, 0);
9090 gtk_box_pack_start(GTK_BOX(hbox), button_hide_show, TRUE, TRUE, 0);
9092 /* Connect our callbacks to the three buttons */
9093 gtk_signal_connect_object(GTK_OBJECT(button_add), "clicked",
9094 GTK_SIGNAL_FUNC(button_add_clicked),
9096 gtk_signal_connect_object(GTK_OBJECT(button_clear), "clicked",
9097 GTK_SIGNAL_FUNC(button_clear_clicked),
9099 gtk_signal_connect_object(GTK_OBJECT(button_hide_show), "clicked",
9100 GTK_SIGNAL_FUNC(button_hide_show_clicked),
9103 gtk_widget_show(button_add);
9104 gtk_widget_show(button_clear);
9105 gtk_widget_show(button_hide_show);
9107 /* The interface is completely set up so we show the window and
9108 * enter the gtk_main loop.
9110 gtk_widget_show(window);
9118 <!-- ***************************************************************** -->
9119 <sect> Tree Widget <label id="sec_Tree_Widgets">
9120 <!-- ***************************************************************** -->
9122 The purpose of tree widgets is to display hierarchically-organized
9123 data. The Tree widget itself is a vertical container for widgets of
9124 type TreeItem. Tree itself is not terribly different from
9125 CList - both are derived directly from Container, and the
9126 Container methods work in the same way on Tree widgets as on
9127 CList widgets. The difference is that Tree widgets can be nested
9128 within other Tree widgets. We'll see how to do this shortly.
9130 The Tree widget has its own window, and defaults to a white
9131 background, as does CList. Also, most of the Tree methods work in
9132 the same way as the corresponding CList ones. However, Tree is
9133 not derived from CList, so you cannot use them interchangeably.
9136 <sect1> Creating a Tree
9138 A Tree is created in the usual way, using:
9141 GtkWidget *gtk_tree_new( void );
9144 Like the CList widget, a Tree will simply keep growing as more
9145 items are added to it, as well as when subtrees are expanded. For
9146 this reason, they are almost always packed into a
9147 ScrolledWindow. You might want to use gtk_widget_set_usize() on the
9148 scrolled window to ensure that it is big enough to see the tree's
9149 items, as the default size for ScrolledWindow is quite small.
9151 Now that you have a tree, you'll probably want to add some items to
9152 it. <ref id="sec_Tree_Item_Widget" name="The Tree Item Widget"> below
9153 explains the gory details of TreeItem. For now, it'll suffice to
9157 GtkWidget *gtk_tree_item_new_with_label( gchar *label );
9160 You can then add it to the tree using one of the following (see
9161 <ref id="sec_Tree_Functions" name="Functions and Macros">
9162 below for more options):
9165 void gtk_tree_append( GtkTree *tree,
9166 GtkWidget *tree_item );
9168 void gtk_tree_prepend( GtkTree *tree,
9169 GtkWidget *tree_item );
9172 Note that you must add items to a Tree one at a time - there is no
9173 equivalent to gtk_list_*_items().
9175 <!-- ----------------------------------------------------------------- -->
9176 <sect1> Adding a Subtree
9178 A subtree is created like any other Tree widget. A subtree is added
9179 to another tree beneath a tree item, using:
9182 void gtk_tree_item_set_subtree( GtkTreeItem *tree_item,
9183 GtkWidget *subtree );
9186 You do not need to call gtk_widget_show() on a subtree before or after
9187 adding it to a TreeItem. However, you <em>must</em> have added the
9188 TreeItem in question to a parent tree before calling
9189 gtk_tree_item_set_subtree(). This is because, technically, the parent
9190 of the subtree is <em>not</em> the GtkTreeItem which "owns" it, but
9191 rather the GtkTree which holds that GtkTreeItem.
9193 When you add a subtree to a TreeItem, a plus or minus sign appears
9194 beside it, which the user can click on to "expand" or "collapse" it,
9195 meaning, to show or hide its subtree. TreeItems are collapsed by
9196 default. Note that when you collapse a TreeItem, any selected
9197 items in its subtree remain selected, which may not be what the user
9200 <!-- ----------------------------------------------------------------- -->
9201 <sect1> Handling the Selection List
9203 As with CList, the Tree type has a <tt>selection</tt> field, and
9204 it is possible to control the behaviour of the tree (somewhat) by
9205 setting the selection type using:
9208 void gtk_tree_set_selection_mode( GtkTree *tree,
9209 GtkSelectionMode mode );
9212 The semantics associated with the various selection modes are
9213 described in the section on the CList widget. As with the CList
9214 widget, the "select_child", "unselect_child" (not really - see <ref
9215 id="sec_Tree_Signals" name="Signals"> below for an explanation),
9216 and "selection_changed" signals are emitted when list items are
9217 selected or unselected. However, in order to take advantage of these
9218 signals, you need to know <em>which</em> Tree widget they will be
9219 emitted by, and where to find the list of selected items.
9221 This is a source of potential confusion. The best way to explain this
9222 is that though all Tree widgets are created equal, some are more equal
9223 than others. All Tree widgets have their own X window, and can
9224 therefore receive events such as mouse clicks (if their TreeItems or
9225 their children don't catch them first!). However, to make
9226 <tt/GTK_SELECTION_SINGLE/ and <tt/GTK_SELECTION_BROWSE/ selection
9227 types behave in a sane manner, the list of selected items is specific
9228 to the topmost Tree widget in a hierarchy, known as the "root tree".
9230 Thus, accessing the <tt>selection</tt> field directly in an arbitrary
9231 Tree widget is not a good idea unless you <em>know</em> it's the root
9232 tree. Instead, use the <tt/GTK_TREE_SELECTION (Tree)/ macro, which
9233 gives the root tree's selection list as a GList pointer. Of course,
9234 this list can include items that are not in the subtree in question if
9235 the selection type is <tt/GTK_SELECTION_MULTIPLE/.
9237 Finally, the "select_child" (and "unselect_child", in theory) signals
9238 are emitted by all trees, but the "selection_changed" signal is only
9239 emitted by the root tree. Consequently, if you want to handle the
9240 "select_child" signal for a tree and all its subtrees, you will have
9241 to call gtk_signal_connect() for every subtree.
9243 <sect1> Tree Widget Internals
9245 The Tree's struct definition looks like this:
9250 GtkContainer container;
9254 GtkTree* root_tree; /* owner of selection list */
9255 GtkWidget* tree_owner;
9259 guint current_indent;
9260 guint selection_mode : 2;
9261 guint view_mode : 1;
9262 guint view_line : 1;
9266 The perils associated with accessing the <tt>selection</tt> field
9267 directly have already been mentioned. The other important fields of
9268 the struct can also be accessed with handy macros or class functions.
9269 <tt/GTK_IS_ROOT_TREE (Tree)/ returns a boolean value which
9270 indicates whether a tree is the root tree in a Tree hierarchy, while
9271 <tt/GTK_TREE_ROOT_TREE (Tree)/ returns the root tree, an object of
9272 type GtkTree (so, remember to cast it using <tt/GTK_WIDGET (Tree)/ if
9273 you want to use one of the gtk_widget_*() functions on it).
9275 Instead of directly accessing the children field of a Tree widget,
9276 it's probably best to cast it using >tt/GTK_CONTAINER (Tree)/, and
9277 pass it to the gtk_container_children() function. This creates a
9278 duplicate of the original list, so it's advisable to free it up using
9279 g_list_free() after you're done with it, or to iterate on it
9280 destructively, like this:
9283 children = gtk_container_children (GTK_CONTAINER (tree));
9285 do_something_nice (GTK_TREE_ITEM (children->data));
9286 children = g_list_remove_link (children, children);
9290 The <tt>tree_owner</tt> field is defined only in subtrees, where it
9291 points to the TreeItem widget which holds the tree in question.
9292 The <tt>level</tt> field indicates how deeply nested a particular tree
9293 is; root trees have level 0, and each successive level of subtrees has
9294 a level one greater than the parent level. This field is set only
9295 after a Tree widget is actually mapped (i.e. drawn on the screen).
9297 <sect2> Signals<label id="sec_Tree_Signals">
9300 void selection_changed( GtkTree *tree );
9303 This signal will be emitted whenever the <tt>selection</tt> field of a
9304 Tree has changed. This happens when a child of the Tree is
9305 selected or deselected.
9308 void select_child( GtkTree *tree,
9312 This signal is emitted when a child of the Tree is about to get
9313 selected. This happens on calls to gtk_tree_select_item(),
9314 gtk_tree_select_child(), on <em>all</em> button presses and calls to
9315 gtk_tree_item_toggle() and gtk_item_toggle(). It may sometimes be
9316 indirectly triggered on other occasions where children get added to or
9317 removed from the Tree.
9320 void unselect_child (GtkTree *tree,
9324 This signal is emitted when a child of the Tree is about to get
9325 deselected. As of GTK 1.0.4, this seems to only occur on calls to
9326 gtk_tree_unselect_item() or gtk_tree_unselect_child(), and perhaps on
9327 other occasions, but <em>not</em> when a button press deselects a
9328 child, nor on emission of the "toggle" signal by gtk_item_toggle().
9330 <sect2> Functions and Macros<label id="sec_Tree_Functions">
9333 guint gtk_tree_get_type( void );
9336 Returns the "GtkTree" type identifier.
9339 GtkWidget* gtk_tree_new( void );
9342 Create a new Tree object. The new widget is returned as a pointer to a
9343 GtkWidget object. NULL is returned on failure.
9346 void gtk_tree_append( GtkTree *tree,
9347 GtkWidget *tree_item );
9350 Append a tree item to a Tree.
9353 void gtk_tree_prepend( GtkTree *tree,
9354 GtkWidget *tree_item );
9357 Prepend a tree item to a Tree.
9360 void gtk_tree_insert( GtkTree *tree,
9361 GtkWidget *tree_item,
9365 Insert a tree item into a Tree at the position in the list
9366 specified by <tt>position.</tt>
9369 void gtk_tree_remove_items( GtkTree *tree,
9373 Remove a list of items (in the form of a GList *) from a Tree.
9374 Note that removing an item from a tree dereferences (and thus usually)
9375 destroys it <em>and</em> its subtree, if it has one, <em>and</em> all
9376 subtrees in that subtree. If you want to remove only one item, you
9377 can use gtk_container_remove().
9380 void gtk_tree_clear_items( GtkTree *tree,
9385 Remove the items from position <tt>start</tt> to position <tt>end</tt>
9386 from a Tree. The same warning about dereferencing applies here, as
9387 gtk_tree_clear_items() simply constructs a list and passes it to
9388 gtk_tree_remove_items().
9391 void gtk_tree_select_item( GtkTree *tree,
9395 Emits the "select_item" signal for the child at position
9396 <tt>item</tt>, thus selecting the child (unless you unselect it in a
9400 void gtk_tree_unselect_item( GtkTree *tree,
9404 Emits the "unselect_item" signal for the child at position
9405 <tt>item</tt>, thus unselecting the child.
9408 void gtk_tree_select_child( GtkTree *tree,
9409 GtkWidget *tree_item );
9412 Emits the "select_item" signal for the child <tt>tree_item</tt>, thus
9416 void gtk_tree_unselect_child( GtkTree *tree,
9417 GtkWidget *tree_item );
9420 Emits the "unselect_item" signal for the child <tt>tree_item</tt>,
9421 thus unselecting it.
9424 gint gtk_tree_child_position( GtkTree *tree,
9428 Returns the position in the tree of <tt>child</tt>, unless
9429 <tt>child</tt> is not in the tree, in which case it returns -1.
9432 void gtk_tree_set_selection_mode( GtkTree *tree,
9433 GtkSelectionMode mode );
9436 Sets the selection mode, which can be one of <tt/GTK_SELECTION_SINGLE/ (the
9437 default), <tt/GTK_SELECTION_BROWSE/, <tt/GTK_SELECTION_MULTIPLE/, or
9438 <tt/GTK_SELECTION_EXTENDED/. This is only defined for root trees, which
9439 makes sense, since the root tree "owns" the selection. Setting it for
9440 subtrees has no effect at all; the value is simply ignored.
9443 void gtk_tree_set_view_mode( GtkTree *tree,
9444 GtkTreeViewMode mode );
9447 Sets the "view mode", which can be either <tt/GTK_TREE_VIEW_LINE/ (the
9448 default) or <tt/GTK_TREE_VIEW_ITEM/. The view mode propagates from a
9449 tree to its subtrees, and can't be set exclusively to a subtree (this
9450 is not exactly true - see the example code comments).
9452 The term "view mode" is rather ambiguous - basically, it controls the
9453 way the highlight is drawn when one of a tree's children is selected.
9454 If it's <tt/GTK_TREE_VIEW_LINE/, the entire TreeItem widget is
9455 highlighted, while for <tt/GTK_TREE_VIEW_ITEM/, only the child widget
9456 (i.e., usually the label) is highlighted.
9459 void gtk_tree_set_view_lines( GtkTree *tree,
9463 Controls whether connecting lines between tree items are drawn.
9464 <tt>flag</tt> is either TRUE, in which case they are, or FALSE, in
9465 which case they aren't.
9468 GtkTree *GTK_TREE (gpointer obj);
9471 Cast a generic pointer to "GtkTree *".
9474 GtkTreeClass *GTK_TREE_CLASS (gpointer class);
9477 Cast a generic pointer to "GtkTreeClass *".
9480 gint GTK_IS_TREE (gpointer obj);
9483 Determine if a generic pointer refers to a "GtkTree" object.
9486 gint GTK_IS_ROOT_TREE (gpointer obj)
9489 Determine if a generic pointer refers to a "GtkTree" object
9490 <em>and</em> is a root tree. Though this will accept any pointer, the
9491 results of passing it a pointer that does not refer to a Tree are
9492 undefined and possibly harmful.
9495 GtkTree *GTK_TREE_ROOT_TREE (gpointer obj)
9498 Return the root tree of a pointer to a "GtkTree" object. The above
9502 GList *GTK_TREE_SELECTION( gpointer obj)
9505 Return the selection list of the root tree of a "GtkTree" object. The
9506 above warning applies here, too.
9508 <sect1> Tree Item Widget<label id="sec_Tree_Item_Widget">
9510 The TreeItem widget, like CListItem, is derived from Item,
9511 which in turn is derived from Bin. Therefore, the item itself is a
9512 generic container holding exactly one child widget, which can be of
9513 any type. The TreeItem widget has a number of extra fields, but
9514 the only one we need be concerned with is the <tt>subtree</tt> field.
9516 The definition for the TreeItem struct looks like this:
9524 GtkWidget *pixmaps_box;
9525 GtkWidget *plus_pix_widget, *minus_pix_widget;
9527 GList *pixmaps; /* pixmap node for this items color depth */
9533 The <tt>pixmaps_box</tt> field is an EventBox which catches clicks on
9534 the plus/minus symbol which controls expansion and collapsing. The
9535 <tt>pixmaps</tt> field points to an internal data structure. Since
9536 you can always obtain the subtree of a TreeItem in a (relatively)
9537 type-safe manner with the <tt/GTK_TREE_ITEM_SUBTREE (Item)/ macro,
9538 it's probably advisable never to touch the insides of a TreeItem
9539 unless you <em>really</em> know what you're doing.
9541 Since it is directly derived from an Item it can be treated as such by
9542 using the <tt/GTK_ITEM (TreeItem)/ macro. A TreeItem usually holds a
9543 label, so the convenience function gtk_list_item_new_with_label() is
9544 provided. The same effect can be achieved using code like the
9545 following, which is actually copied verbatim from
9546 gtk_tree_item_new_with_label():
9549 tree_item = gtk_tree_item_new ();
9550 label_widget = gtk_label_new (label);
9551 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
9553 gtk_container_add (GTK_CONTAINER (tree_item), label_widget);
9554 gtk_widget_show (label_widget);
9557 As one is not forced to add a Label to a TreeItem, you could
9558 also add an HBox or an Arrow, or even a Notebook (though your
9559 app will likely be quite unpopular in this case) to the TreeItem.
9561 If you remove all the items from a subtree, it will be destroyed and
9562 unparented, unless you reference it beforehand, and the TreeItem
9563 which owns it will be collapsed. So, if you want it to stick around,
9564 do something like the following:
9567 gtk_widget_ref (tree);
9568 owner = GTK_TREE(tree)->tree_owner;
9569 gtk_container_remove (GTK_CONTAINER(tree), item);
9570 if (tree->parent == NULL){
9571 gtk_tree_item_expand (GTK_TREE_ITEM(owner));
9572 gtk_tree_item_set_subtree (GTK_TREE_ITEM(owner), tree);
9575 gtk_widget_unref (tree);
9578 Finally, drag-n-drop <em>does</em> work with TreeItems. You just
9579 have to make sure that the TreeItem you want to make into a drag
9580 item or a drop site has not only been added to a Tree, but that
9581 each successive parent widget has a parent itself, all the way back to
9582 a toplevel or dialog window, when you call gtk_widget_dnd_drag_set()
9583 or gtk_widget_dnd_drop_set(). Otherwise, strange things will happen.
9587 TreeItem inherits the "select", "deselect", and "toggle" signals
9588 from Item. In addition, it adds two signals of its own, "expand"
9592 void select( GtkItem *tree_item );
9595 This signal is emitted when an item is about to be selected, either
9596 after it has been clicked on by the user, or when the program calls
9597 gtk_tree_item_select(), gtk_item_select(), or gtk_tree_select_child().
9600 void deselect( GtkItem *tree_item );
9603 This signal is emitted when an item is about to be unselected, either
9604 after it has been clicked on by the user, or when the program calls
9605 gtk_tree_item_deselect() or gtk_item_deselect(). In the case of
9606 TreeItems, it is also emitted by gtk_tree_unselect_child(), and
9607 sometimes gtk_tree_select_child().
9610 void toggle( GtkItem *tree_item );
9613 This signal is emitted when the program calls gtk_item_toggle(). The
9614 effect it has when emitted on a TreeItem is to call
9615 gtk_tree_select_child() (and never gtk_tree_unselect_child()) on the
9616 item's parent tree, if the item has a parent tree. If it doesn't,
9617 then the highlight is reversed on the item.
9620 void expand( GtkTreeItem *tree_item );
9623 This signal is emitted when the tree item's subtree is about to be
9624 expanded, that is, when the user clicks on the plus sign next to the
9625 item, or when the program calls gtk_tree_item_expand().
9628 void collapse( GtkTreeItem *tree_item );
9631 This signal is emitted when the tree item's subtree is about to be
9632 collapsed, that is, when the user clicks on the minus sign next to the
9633 item, or when the program calls gtk_tree_item_collapse().
9635 <sect2> Functions and Macros
9638 guint gtk_tree_item_get_type( void );
9641 Returns the "GtkTreeItem" type identifier.
9644 GtkWidget* gtk_tree_item_new( void );
9647 Create a new TreeItem object. The new widget is returned as a
9648 pointer to a GtkWidget object. NULL is returned on failure.
9651 GtkWidget* gtk_tree_item_new_with_label (gchar *label);
9654 Create a new TreeItem object, having a single GtkLabel as the sole
9655 child. The new widget is returned as a pointer to a GtkWidget
9656 object. NULL is returned on failure.
9659 void gtk_tree_item_select( GtkTreeItem *tree_item );
9662 This function is basically a wrapper around a call to
9663 <tt>gtk_item_select (GTK_ITEM (tree_item))</tt> which will emit the
9667 void gtk_tree_item_deselect( GtkTreeItem *tree_item );
9670 This function is basically a wrapper around a call to
9671 gtk_item_deselect (GTK_ITEM (tree_item)) which will emit the deselect
9675 void gtk_tree_item_set_subtree( GtkTreeItem *tree_item,
9676 GtkWidget *subtree );
9679 This function adds a subtree to tree_item, showing it if tree_item is
9680 expanded, or hiding it if tree_item is collapsed. Again, remember that
9681 the tree_item must have already been added to a tree for this to work.
9684 void gtk_tree_item_remove_subtree( GtkTreeItem *tree_item );
9687 This removes all of tree_item's subtree's children (thus unreferencing
9688 and destroying it, any of its children's subtrees, and so on...), then
9689 removes the subtree itself, and hides the plus/minus sign.
9692 void gtk_tree_item_expand( GtkTreeItem *tree_item );
9695 This emits the "expand" signal on tree_item, which expands it.
9698 void gtk_tree_item_collapse( GtkTreeItem *tree_item );
9701 This emits the "collapse" signal on tree_item, which collapses it.
9704 GtkTreeItem *GTK_TREE_ITEM (gpointer obj)
9707 Cast a generic pointer to "GtkTreeItem *".
9710 GtkTreeItemClass *GTK_TREE_ITEM_CLASS (gpointer obj)
9713 Cast a generic pointer to "GtkTreeItemClass".
9716 gint GTK_IS_TREE_ITEM (gpointer obj)
9719 Determine if a generic pointer refers to a "GtkTreeItem" object.
9722 GtkWidget GTK_TREE_ITEM_SUBTREE (gpointer obj)
9725 Returns a tree item's subtree (<tt/obj/ should point to a
9726 "GtkTreeItem" object).
9728 <sect1> Tree Example
9730 This is somewhat like the tree example in testgtk.c, but a lot less
9731 complete (although much better commented). It puts up a window with a
9732 tree, and connects all the signals for the relevant objects, so you
9733 can see when they are emitted.
9736 /* example-start tree tree.c */
9738 #include <gtk/gtk.h>
9740 /* for all the GtkItem:: and GtkTreeItem:: signals */
9741 static void cb_itemsignal( GtkWidget *item,
9747 /* It's a Bin, so it has one child, which we know to be a
9748 label, so get that */
9749 label = GTK_LABEL (GTK_BIN (item)->child);
9750 /* Get the text of the label */
9751 gtk_label_get (label, &name);
9752 /* Get the level of the tree which the item is in */
9753 g_print ("%s called for item %s->%p, level %d\n", signame, name,
9754 item, GTK_TREE (item->parent)->level);
9757 /* Note that this is never called */
9758 static void cb_unselect_child( GtkWidget *root_tree,
9760 GtkWidget *subtree )
9762 g_print ("unselect_child called for root tree %p, subtree %p, child %p\n",
9763 root_tree, subtree, child);
9766 /* Note that this is called every time the user clicks on an item,
9767 whether it is already selected or not. */
9768 static void cb_select_child (GtkWidget *root_tree, GtkWidget *child,
9771 g_print ("select_child called for root tree %p, subtree %p, child %p\n",
9772 root_tree, subtree, child);
9775 static void cb_selection_changed( GtkWidget *tree )
9779 g_print ("selection_change called for tree %p\n", tree);
9780 g_print ("selected objects are:\n");
9782 i = GTK_TREE_SELECTION(tree);
9788 /* Get a GtkWidget pointer from the list node */
9789 item = GTK_WIDGET (i->data);
9790 label = GTK_LABEL (GTK_BIN (item)->child);
9791 gtk_label_get (label, &name);
9792 g_print ("\t%s on level %d\n", name, GTK_TREE
9793 (item->parent)->level);
9801 GtkWidget *window, *scrolled_win, *tree;
9802 static gchar *itemnames[] = {"Foo", "Bar", "Baz", "Quux",
9806 gtk_init (&argc, &argv);
9808 /* a generic toplevel window */
9809 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9810 gtk_signal_connect (GTK_OBJECT(window), "delete_event",
9811 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
9812 gtk_container_set_border_width (GTK_CONTAINER(window), 5);
9814 /* A generic scrolled window */
9815 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
9816 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
9817 GTK_POLICY_AUTOMATIC,
9818 GTK_POLICY_AUTOMATIC);
9819 gtk_widget_set_usize (scrolled_win, 150, 200);
9820 gtk_container_add (GTK_CONTAINER(window), scrolled_win);
9821 gtk_widget_show (scrolled_win);
9823 /* Create the root tree */
9824 tree = gtk_tree_new();
9825 g_print ("root tree is %p\n", tree);
9826 /* connect all GtkTree:: signals */
9827 gtk_signal_connect (GTK_OBJECT(tree), "select_child",
9828 GTK_SIGNAL_FUNC(cb_select_child), tree);
9829 gtk_signal_connect (GTK_OBJECT(tree), "unselect_child",
9830 GTK_SIGNAL_FUNC(cb_unselect_child), tree);
9831 gtk_signal_connect (GTK_OBJECT(tree), "selection_changed",
9832 GTK_SIGNAL_FUNC(cb_selection_changed), tree);
9833 /* Add it to the scrolled window */
9834 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW(scrolled_win),
9836 /* Set the selection mode */
9837 gtk_tree_set_selection_mode (GTK_TREE(tree),
9838 GTK_SELECTION_MULTIPLE);
9840 gtk_widget_show (tree);
9842 for (i = 0; i < 5; i++){
9843 GtkWidget *subtree, *item;
9846 /* Create a tree item */
9847 item = gtk_tree_item_new_with_label (itemnames[i]);
9848 /* Connect all GtkItem:: and GtkTreeItem:: signals */
9849 gtk_signal_connect (GTK_OBJECT(item), "select",
9850 GTK_SIGNAL_FUNC(cb_itemsignal), "select");
9851 gtk_signal_connect (GTK_OBJECT(item), "deselect",
9852 GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
9853 gtk_signal_connect (GTK_OBJECT(item), "toggle",
9854 GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
9855 gtk_signal_connect (GTK_OBJECT(item), "expand",
9856 GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
9857 gtk_signal_connect (GTK_OBJECT(item), "collapse",
9858 GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
9859 /* Add it to the parent tree */
9860 gtk_tree_append (GTK_TREE(tree), item);
9861 /* Show it - this can be done at any time */
9862 gtk_widget_show (item);
9863 /* Create this item's subtree */
9864 subtree = gtk_tree_new();
9865 g_print ("-> item %s->%p, subtree %p\n", itemnames[i], item,
9868 /* This is still necessary if you want these signals to be called
9869 for the subtree's children. Note that selection_change will be
9870 signalled for the root tree regardless. */
9871 gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
9872 GTK_SIGNAL_FUNC(cb_select_child), subtree);
9873 gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
9874 GTK_SIGNAL_FUNC(cb_unselect_child), subtree);
9875 /* This has absolutely no effect, because it is completely ignored
9877 gtk_tree_set_selection_mode (GTK_TREE(subtree),
9878 GTK_SELECTION_SINGLE);
9879 /* Neither does this, but for a rather different reason - the
9880 view_mode and view_line values of a tree are propagated to
9881 subtrees when they are mapped. So, setting it later on would
9882 actually have a (somewhat unpredictable) effect */
9883 gtk_tree_set_view_mode (GTK_TREE(subtree), GTK_TREE_VIEW_ITEM);
9884 /* Set this item's subtree - note that you cannot do this until
9885 AFTER the item has been added to its parent tree! */
9886 gtk_tree_item_set_subtree (GTK_TREE_ITEM(item), subtree);
9888 for (j = 0; j < 5; j++){
9891 /* Create a subtree item, in much the same way */
9892 subitem = gtk_tree_item_new_with_label (itemnames[j]);
9893 /* Connect all GtkItem:: and GtkTreeItem:: signals */
9894 gtk_signal_connect (GTK_OBJECT(subitem), "select",
9895 GTK_SIGNAL_FUNC(cb_itemsignal), "select");
9896 gtk_signal_connect (GTK_OBJECT(subitem), "deselect",
9897 GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
9898 gtk_signal_connect (GTK_OBJECT(subitem), "toggle",
9899 GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
9900 gtk_signal_connect (GTK_OBJECT(subitem), "expand",
9901 GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
9902 gtk_signal_connect (GTK_OBJECT(subitem), "collapse",
9903 GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
9904 g_print ("-> -> item %s->%p\n", itemnames[j], subitem);
9905 /* Add it to its parent tree */
9906 gtk_tree_append (GTK_TREE(subtree), subitem);
9908 gtk_widget_show (subitem);
9912 /* Show the window and loop endlessly */
9913 gtk_widget_show (window);
9920 <!-- ***************************************************************** -->
9922 <!-- ***************************************************************** -->
9924 There are two ways to create menus: there's the easy way, and there's
9925 the hard way. Both have their uses, but you can usually use the
9926 Itemfactory (the easy way). The "hard" way is to create all the menus
9927 using the calls directly. The easy way is to use the gtk_item_factory
9928 calls. This is much simpler, but there are advantages and
9929 disadvantages to each approach.
9931 The Itemfactory is much easier to use, and to add new menus to,
9932 although writing a few wrapper functions to create menus using the
9933 manual method could go a long way towards usability. With the
9934 Itemfactory, it is not possible to add images or the character '/' to
9937 <!-- ----------------------------------------------------------------- -->
9938 <sect1>Manual Menu Creation
9940 In the true tradition of teaching, we'll show you the hard way
9943 There are three widgets that go into making a menubar and submenus:
9945 <item>a menu item, which is what the user wants to select, e.g.,
9947 <item>a menu, which acts as a container for the menu items, and
9948 <item>a menubar, which is a container for each of the individual
9952 This is slightly complicated by the fact that menu item widgets are
9953 used for two different things. They are both the widgets that are
9954 packed into the menu, and the widget that is packed into the menubar,
9955 which, when selected, activates the menu.
9957 Let's look at the functions that are used to create menus and
9958 menubars. This first function is used to create a new menubar.
9962 GtkWidget *gtk_menu_bar_new( void );
9966 This rather self explanatory function creates a new menubar. You use
9967 gtk_container_add to pack this into a window, or the box_pack
9968 functions to pack it into a box - the same as buttons.
9971 GtkWidget *gtk_menu_new( void );
9974 This function returns a pointer to a new menu; it is never actually
9975 shown (with gtk_widget_show), it is just a container for the menu
9976 items. I hope this will become more clear when you look at the
9979 The next two calls are used to create menu items that are packed into
9980 the menu (and menubar).
9983 GtkWidget *gtk_menu_item_new( void );
9989 GtkWidget *gtk_menu_item_new_with_label( const char *label );
9992 These calls are used to create the menu items that are to be
9993 displayed. Remember to differentiate between a "menu" as created with
9994 gtk_menu_new and a "menu item" as created by the gtk_menu_item_new
9995 functions. The menu item will be an actual button with an associated
9996 action, whereas a menu will be a container holding menu items.
9998 The gtk_menu_new_with_label and gtk_menu_new functions are just as
9999 you'd expect after reading about the buttons. One creates a new menu
10000 item with a label already packed into it, and the other just creates a
10003 Once you've created a menu item you have to put it into a menu. This
10004 is done using the function gtk_menu_append. In order to capture when
10005 the item is selected by the user, we need to connect to the
10006 <tt/activate/ signal in the usual way. So, if we wanted to create a
10007 standard <tt/File/ menu, with the options <tt/Open/, <tt/Save/, and
10008 <tt/Quit/, the code would look something like:
10011 file_menu = gtk_menu_new (); /* Don't need to show menus */
10013 /* Create the menu items */
10014 open_item = gtk_menu_item_new_with_label ("Open");
10015 save_item = gtk_menu_item_new_with_label ("Save");
10016 quit_item = gtk_menu_item_new_with_label ("Quit");
10018 /* Add them to the menu */
10019 gtk_menu_append (GTK_MENU (file_menu), open_item);
10020 gtk_menu_append (GTK_MENU (file_menu), save_item);
10021 gtk_menu_append (GTK_MENU (file_menu), quit_item);
10023 /* Attach the callback functions to the activate signal */
10024 gtk_signal_connect_object (GTK_OBJECT (open_items), "activate",
10025 GTK_SIGNAL_FUNC (menuitem_response),
10026 (gpointer) "file.open");
10027 gtk_signal_connect_object (GTK_OBJECT (save_items), "activate",
10028 GTK_SIGNAL_FUNC (menuitem_response),
10029 (gpointer) "file.save");
10031 /* We can attach the Quit menu item to our exit function */
10032 gtk_signal_connect_object (GTK_OBJECT (quit_items), "activate",
10033 GTK_SIGNAL_FUNC (destroy),
10034 (gpointer) "file.quit");
10036 /* We do need to show menu items */
10037 gtk_widget_show (open_item);
10038 gtk_widget_show (save_item);
10039 gtk_widget_show (quit_item);
10042 At this point we have our menu. Now we need to create a menubar and a
10043 menu item for the <tt/File/ entry, to which we add our menu. The code
10047 menu_bar = gtk_menu_bar_new ();
10048 gtk_container_add (GTK_CONTAINER (window), menu_bar);
10049 gtk_widget_show (menu_bar);
10051 file_item = gtk_menu_item_new_with_label ("File");
10052 gtk_widget_show (file_item);
10055 Now we need to associate the menu with <tt/file_item/. This is done
10059 void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
10060 GtkWidget *submenu );
10063 So, our example would continue with
10066 gtk_menu_item_set_submenu (GTK_MENU_ITEM (file_item), file_menu);
10069 All that is left to do is to add the menu to the menubar, which is
10070 accomplished using the function
10073 void gtk_menu_bar_append( GtkMenuBar *menu_bar,
10074 GtkWidget *menu_item );
10077 which in our case looks like this:
10080 gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), file_item);
10083 If we wanted the menu right justified on the menubar, such as help
10084 menus often are, we can use the following function (again on
10085 <tt/file_item/ in the current example) before attaching it to the
10089 void gtk_menu_item_right_justify( GtkMenuItem *menu_item );
10092 Here is a summary of the steps needed to create a menu bar with menus
10096 <item> Create a new menu using gtk_menu_new()
10097 <item> Use multiple calls to gtk_menu_item_new() for each item you
10098 wish to have on your menu. And use gtk_menu_append() to put each of
10099 these new items on to the menu.
10100 <item> Create a menu item using gtk_menu_item_new(). This will be the
10101 root of the menu, the text appearing here will be on the menubar
10103 <item>Use gtk_menu_item_set_submenu() to attach the menu to the root
10104 menu item (the one created in the above step).
10105 <item> Create a new menubar using gtk_menu_bar_new. This step only
10106 needs to be done once when creating a series of menus on one menu bar.
10107 <item> Use gtk_menu_bar_append() to put the root menu onto the menubar.
10110 Creating a popup menu is nearly the same. The difference is that the
10111 menu is not posted "automatically" by a menubar, but explicitly by
10112 calling the function gtk_menu_popup() from a button-press event, for
10113 example. Take these steps:
10116 <item>Create an event handling function. It needs to have the
10119 static gint handler (GtkWidget *widget,
10122 and it will use the event to find out where to pop up the menu.
10123 <item>In the event handler, if the event is a mouse button press,
10124 treat <tt>event</tt> as a button event (which it is) and use it as
10125 shown in the sample code to pass information to gtk_menu_popup().
10126 <item>Bind that event handler to a widget with
10128 gtk_signal_connect_object (GTK_OBJECT (widget), "event",
10129 GTK_SIGNAL_FUNC (handler),
10130 GTK_OBJECT (menu));
10132 where <tt>widget</tt> is the widget you are binding to,
10133 <tt>handler</tt> is the handling function, and <tt>menu</tt> is a menu
10134 created with gtk_menu_new(). This can be a menu which is also posted
10135 by a menu bar, as shown in the sample code.
10138 <!-- ----------------------------------------------------------------- -->
10139 <sect1>Manual Menu Example
10141 That should about do it. Let's take a look at an example to help clarify.
10144 /* example-start menu menu.c */
10147 #include <gtk/gtk.h>
10149 static gint button_press (GtkWidget *, GdkEvent *);
10150 static void menuitem_response (gchar *);
10152 int main( int argc,
10158 GtkWidget *menu_bar;
10159 GtkWidget *root_menu;
10160 GtkWidget *menu_items;
10166 gtk_init (&argc, &argv);
10168 /* create a new window */
10169 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
10170 gtk_widget_set_usize (GTK_WIDGET (window), 200, 100);
10171 gtk_window_set_title (GTK_WINDOW (window), "GTK Menu Test");
10172 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
10173 (GtkSignalFunc) gtk_main_quit, NULL);
10175 /* Init the menu-widget, and remember -- never
10176 * gtk_show_widget() the menu widget!!
10177 * This is the menu that holds the menu items, the one that
10178 * will pop up when you click on the "Root Menu" in the app */
10179 menu = gtk_menu_new ();
10181 /* Next we make a little loop that makes three menu-entries for "test-menu".
10182 * Notice the call to gtk_menu_append. Here we are adding a list of
10183 * menu items to our menu. Normally, we'd also catch the "clicked"
10184 * signal on each of the menu items and setup a callback for it,
10185 * but it's omitted here to save space. */
10187 for (i = 0; i < 3; i++)
10189 /* Copy the names to the buf. */
10190 sprintf (buf, "Test-undermenu - %d", i);
10192 /* Create a new menu-item with a name... */
10193 menu_items = gtk_menu_item_new_with_label (buf);
10195 /* ...and add it to the menu. */
10196 gtk_menu_append (GTK_MENU (menu), menu_items);
10198 /* Do something interesting when the menuitem is selected */
10199 gtk_signal_connect_object (GTK_OBJECT (menu_items), "activate",
10200 GTK_SIGNAL_FUNC (menuitem_response), (gpointer) g_strdup (buf));
10202 /* Show the widget */
10203 gtk_widget_show (menu_items);
10206 /* This is the root menu, and will be the label
10207 * displayed on the menu bar. There won't be a signal handler attached,
10208 * as it only pops up the rest of the menu when pressed. */
10209 root_menu = gtk_menu_item_new_with_label ("Root Menu");
10211 gtk_widget_show (root_menu);
10213 /* Now we specify that we want our newly created "menu" to be the menu
10214 * for the "root menu" */
10215 gtk_menu_item_set_submenu (GTK_MENU_ITEM (root_menu), menu);
10217 /* A vbox to put a menu and a button in: */
10218 vbox = gtk_vbox_new (FALSE, 0);
10219 gtk_container_add (GTK_CONTAINER (window), vbox);
10220 gtk_widget_show (vbox);
10222 /* Create a menu-bar to hold the menus and add it to our main window */
10223 menu_bar = gtk_menu_bar_new ();
10224 gtk_box_pack_start (GTK_BOX (vbox), menu_bar, FALSE, FALSE, 2);
10225 gtk_widget_show (menu_bar);
10227 /* Create a button to which to attach menu as a popup */
10228 button = gtk_button_new_with_label ("press me");
10229 gtk_signal_connect_object (GTK_OBJECT (button), "event",
10230 GTK_SIGNAL_FUNC (button_press), GTK_OBJECT (menu));
10231 gtk_box_pack_end (GTK_BOX (vbox), button, TRUE, TRUE, 2);
10232 gtk_widget_show (button);
10234 /* And finally we append the menu-item to the menu-bar -- this is the
10235 * "root" menu-item I have been raving about =) */
10236 gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), root_menu);
10238 /* always display the window as the last step so it all splashes on
10239 * the screen at once. */
10240 gtk_widget_show (window);
10247 /* Respond to a button-press by posting a menu passed in as widget.
10249 * Note that the "widget" argument is the menu being posted, NOT
10250 * the button that was pressed.
10253 static gint button_press( GtkWidget *widget,
10257 if (event->type == GDK_BUTTON_PRESS) {
10258 GdkEventButton *bevent = (GdkEventButton *) event;
10259 gtk_menu_popup (GTK_MENU (widget), NULL, NULL, NULL, NULL,
10260 bevent->button, bevent->time);
10261 /* Tell calling code that we have handled this event; the buck
10266 /* Tell calling code that we have not handled this event; pass it on. */
10271 /* Print a string when a menu item is selected */
10273 static void menuitem_response( gchar *string )
10275 printf ("%s\n", string);
10280 You may also set a menu item to be insensitive and, using an accelerator
10281 table, bind keys to menu functions.
10283 <!-- ----------------------------------------------------------------- -->
10284 <sect1>Using ItemFactory
10286 Now that we've shown you the hard way, here's how you do it using the
10287 gtk_item_factory calls.
10289 <!-- ----------------------------------------------------------------- -->
10290 <sect1>Item Factory Example
10292 Here is an example using the GTK item factory.
10295 /* example-start menu itemfactory.c */
10297 #include <gtk/gtk.h>
10298 #include <strings.h>
10300 /* Obligatory basic callback */
10301 static void print_hello( GtkWidget *w,
10304 g_message ("Hello, World!\n");
10307 /* This is the GtkItemFactoryEntry structure used to generate new menus.
10308 Item 1: The menu path. The letter after the underscore indicates an
10309 accelerator key once the menu is open.
10310 Item 2: The accelerator key for the entry
10311 Item 3: The callback function.
10312 Item 4: The callback action. This changes the parameters with
10313 which the function is called. The default is 0.
10314 Item 5: The item type, used to define what kind of an item it is.
10315 Here are the possible values:
10319 "<Title>" -> create a title item
10320 "<Item>" -> create a simple item
10321 "<CheckItem>" -> create a check item
10322 "<ToggleItem>" -> create a toggle item
10323 "<RadioItem>" -> create a radio item
10324 <path> -> path of a radio item to link against
10325 "<Separator>" -> create a separator
10326 "<Branch>" -> create an item to hold sub items (optional)
10327 "<LastBranch>" -> create a right justified branch
10330 static GtkItemFactoryEntry menu_items[] = {
10331 { "/_File", NULL, NULL, 0, "<Branch>" },
10332 { "/File/_New", "<control>N", print_hello, 0, NULL },
10333 { "/File/_Open", "<control>O", print_hello, 0, NULL },
10334 { "/File/_Save", "<control>S", print_hello, 0, NULL },
10335 { "/File/Save _As", NULL, NULL, 0, NULL },
10336 { "/File/sep1", NULL, NULL, 0, "<Separator>" },
10337 { "/File/Quit", "<control>Q", gtk_main_quit, 0, NULL },
10338 { "/_Options", NULL, NULL, 0, "<Branch>" },
10339 { "/Options/Test", NULL, NULL, 0, NULL },
10340 { "/_Help", NULL, NULL, 0, "<LastBranch>" },
10341 { "/_Help/About", NULL, NULL, 0, NULL },
10345 void get_main_menu( GtkWidget *window,
10346 GtkWidget **menubar )
10348 GtkItemFactory *item_factory;
10349 GtkAccelGroup *accel_group;
10350 gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
10352 accel_group = gtk_accel_group_new ();
10354 /* This function initializes the item factory.
10355 Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
10356 or GTK_TYPE_OPTION_MENU.
10357 Param 2: The path of the menu.
10358 Param 3: A pointer to a gtk_accel_group. The item factory sets up
10359 the accelerator table while generating menus.
10362 item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>",
10365 /* This function generates the menu items. Pass the item factory,
10366 the number of items in the array, the array itself, and any
10367 callback data for the the menu items. */
10368 gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
10370 /* Attach the new accelerator group to the window. */
10371 gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
10374 /* Finally, return the actual menu bar created by the item factory. */
10375 *menubar = gtk_item_factory_get_widget (item_factory, "<main>");
10378 int main( int argc,
10382 GtkWidget *main_vbox;
10383 GtkWidget *menubar;
10385 gtk_init (&argc, &argv);
10387 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
10388 gtk_signal_connect (GTK_OBJECT (window), "destroy",
10389 GTK_SIGNAL_FUNC (gtk_main_quit),
10391 gtk_window_set_title (GTK_WINDOW(window), "Item Factory");
10392 gtk_widget_set_usize (GTK_WIDGET(window), 300, 200);
10394 main_vbox = gtk_vbox_new (FALSE, 1);
10395 gtk_container_border_width (GTK_CONTAINER (main_vbox), 1);
10396 gtk_container_add (GTK_CONTAINER (window), main_vbox);
10397 gtk_widget_show (main_vbox);
10399 get_main_menu (window, &menubar);
10400 gtk_box_pack_start (GTK_BOX (main_vbox), menubar, FALSE, TRUE, 0);
10401 gtk_widget_show (menubar);
10403 gtk_widget_show (window);
10412 For now, there's only this example. An explanation and lots 'o' comments
10415 <!-- ***************************************************************** -->
10417 <!-- ***************************************************************** -->
10419 The Text widget allows multiple lines of text to be displayed and
10420 edited. It supports both multi-colored and multi-font text, allowing
10421 them to be mixed in any way we wish. It also has a wide set of key
10422 based text editing commands, which are compatible with Emacs.
10424 The text widget supports full cut-and-paste facilities, including the
10425 use of double- and triple-click to select a word and a whole line,
10428 <!-- ----------------------------------------------------------------- -->
10429 <sect1>Creating and Configuring a Text box
10431 There is only one function for creating a new Text widget.
10434 GtkWidget *gtk_text_new( GtkAdjustment *hadj,
10435 GtkAdjustment *vadj );
10438 The arguments allow us to give the Text widget pointers to Adjustments
10439 that can be used to track the viewing position of the widget. Passing
10440 NULL values to either or both of these arguments will cause the
10441 gtk_text_new function to create its own.
10444 void gtk_text_set_adjustments( GtkText *text,
10445 GtkAdjustment *hadj,
10446 GtkAdjustment *vadj );
10449 The above function allows the horizontal and vertical adjustments of a
10450 text widget to be changed at any time.
10452 The text widget will not automatically create its own scrollbars when
10453 the amount of text to be displayed is too long for the display
10454 window. We therefore have to create and add them to the display layout
10458 vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
10459 gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, FALSE, 0);
10460 gtk_widget_show (vscrollbar);
10463 The above code snippet creates a new vertical scrollbar, and attaches
10464 it to the vertical adjustment of the text widget, <tt/text/. It then
10465 packs it into a box in the normal way.
10467 Note, currently the Text widget does not support horizontal
10470 There are two main ways in which a Text widget can be used: to allow
10471 the user to edit a body of text, or to allow us to display multiple
10472 lines of text to the user. In order for us to switch between these
10473 modes of operation, the text widget has the following function:
10476 void gtk_text_set_editable( GtkText *text,
10480 The <tt/editable/ argument is a TRUE or FALSE value that specifies
10481 whether the user is permitted to edit the contents of the Text
10482 widget. When the text widget is editable, it will display a cursor at
10483 the current insertion point.
10485 You are not, however, restricted to just using the text widget in
10486 these two modes. You can toggle the editable state of the text widget
10487 at any time, and can insert text at any time.
10489 The text widget wraps lines of text that are too long to fit onto a
10490 single line of the display window. Its default behaviour is to break
10491 words across line breaks. This can be changed using the next function:
10494 void gtk_text_set_word_wrap( GtkText *text,
10498 Using this function allows us to specify that the text widget should
10499 wrap long lines on word boundaries. The <tt/word_wrap/ argument is a
10500 TRUE or FALSE value.
10502 <!-- ----------------------------------------------------------------- -->
10503 <sect1>Text Manipulation
10505 The current insertion point of a Text widget can be set using
10507 void gtk_text_set_point( GtkText *text,
10511 where <tt/index/ is the position to set the insertion point.
10513 Analogous to this is the function for getting the current insertion
10517 guint gtk_text_get_point( GtkText *text );
10520 A function that is useful in combination with the above two functions
10524 guint gtk_text_get_length( GtkText *text );
10527 which returns the current length of the Text widget. The length is the
10528 number of characters that are within the text block of the widget,
10529 including characters such as newline, which marks the end of
10532 In order to insert text at the current insertion point of a Text
10533 widget, the function gtk_text_insert is used, which also allows us to
10534 specify background and foreground colors and a font for the text.
10537 void gtk_text_insert( GtkText *text,
10545 Passing a value of <tt/NULL/ in as the value for the foreground color,
10546 background color or font will result in the values set within the
10547 widget style to be used. Using a value of <tt/-1/ for the length
10548 parameter will result in the whole of the text string given being
10551 The text widget is one of the few within GTK that redraws itself
10552 dynamically, outside of the gtk_main function. This means that all
10553 changes to the contents of the text widget take effect
10554 immediately. This may be undesirable when performing multiple changes
10555 to the text widget. In order to allow us to perform multiple updates
10556 to the text widget without it continuously redrawing, we can freeze
10557 the widget, which temporarily stops it from automatically redrawing
10558 itself every time it is changed. We can then thaw the widget after our
10559 updates are complete.
10561 The following two functions perform this freeze and thaw action:
10564 void gtk_text_freeze( GtkText *text );
10566 void gtk_text_thaw( GtkText *text );
10569 Text is deleted from the text widget relative to the current insertion
10570 point by the following two functions. The return value is a TRUE or
10571 FALSE indicator of whether the operation was successful.
10574 gint gtk_text_backward_delete( GtkText *text,
10577 gint gtk_text_forward_delete ( GtkText *text,
10581 If you want to retrieve the contents of the text widget, then the
10582 macro <tt/GTK_TEXT_INDEX(t, index)/ allows you to retrieve the
10583 character at position <tt/index/ within the text widget <tt/t/.
10585 To retrieve larger blocks of text, we can use the function
10588 gchar *gtk_editable_get_chars( GtkEditable *editable,
10593 This is a function of the parent class of the text widget. A value of
10594 -1 as <tt/end_pos/ signifies the end of the text. The index of the
10597 The function allocates a new chunk of memory for the text block, so
10598 don't forget to free it with a call to g_free when you have finished
10601 <!-- ----------------------------------------------------------------- -->
10602 <sect1>Keyboard Shortcuts
10604 The text widget has a number of pre-installed keyboard shortcuts for
10605 common editing, motion and selection functions. These are accessed
10606 using Control and Alt key combinations.
10608 In addition to these, holding down the Control key whilst using cursor
10609 key movement will move the cursor by words rather than
10610 characters. Holding down Shift whilst using cursor movement will
10611 extend the selection.
10613 <sect2>Motion Shortcuts
10616 <item> Ctrl-A Beginning of line
10617 <item> Ctrl-E End of line
10618 <item> Ctrl-N Next Line
10619 <item> Ctrl-P Previous Line
10620 <item> Ctrl-B Backward one character
10621 <item> Ctrl-F Forward one character
10622 <item> Alt-B Backward one word
10623 <item> Alt-F Forward one word
10626 <sect2>Editing Shortcuts
10629 <item> Ctrl-H Delete Backward Character (Backspace)
10630 <item> Ctrl-D Delete Forward Character (Delete)
10631 <item> Ctrl-W Delete Backward Word
10632 <item> Alt-D Delete Forward Word
10633 <item> Ctrl-K Delete to end of line
10634 <item> Ctrl-U Delete line
10637 <sect2>Selection Shortcuts
10640 <item> Ctrl-X Cut to clipboard
10641 <item> Ctrl-C Copy to clipboard
10642 <item> Ctrl-V Paste from clipboard
10645 <!-- ----------------------------------------------------------------- -->
10646 <sect1>A GtkText Example
10649 /* example-start text text.c */
10654 #include <gtk/gtk.h>
10656 void text_toggle_editable (GtkWidget *checkbutton,
10659 gtk_text_set_editable(GTK_TEXT(text),
10660 GTK_TOGGLE_BUTTON(checkbutton)->active);
10663 void text_toggle_word_wrap (GtkWidget *checkbutton,
10666 gtk_text_set_word_wrap(GTK_TEXT(text),
10667 GTK_TOGGLE_BUTTON(checkbutton)->active);
10670 void close_application( GtkWidget *widget,
10676 int main( int argc,
10685 GtkWidget *separator;
10687 GtkWidget *vscrollbar;
10691 GdkFont *fixed_font;
10695 gtk_init (&argc, &argv);
10697 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
10698 gtk_widget_set_usize (window, 600, 500);
10699 gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, FALSE);
10700 gtk_signal_connect (GTK_OBJECT (window), "destroy",
10701 GTK_SIGNAL_FUNC(close_application),
10703 gtk_window_set_title (GTK_WINDOW (window), "Text Widget Example");
10704 gtk_container_set_border_width (GTK_CONTAINER (window), 0);
10707 box1 = gtk_vbox_new (FALSE, 0);
10708 gtk_container_add (GTK_CONTAINER (window), box1);
10709 gtk_widget_show (box1);
10712 box2 = gtk_vbox_new (FALSE, 10);
10713 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
10714 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
10715 gtk_widget_show (box2);
10718 table = gtk_table_new (2, 2, FALSE);
10719 gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
10720 gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
10721 gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
10722 gtk_widget_show (table);
10724 /* Create the GtkText widget */
10725 text = gtk_text_new (NULL, NULL);
10726 gtk_text_set_editable (GTK_TEXT (text), TRUE);
10727 gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
10728 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
10729 GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
10730 gtk_widget_show (text);
10732 /* Add a vertical scrollbar to the GtkText widget */
10733 vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
10734 gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
10735 GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
10736 gtk_widget_show (vscrollbar);
10738 /* Get the system color map and allocate the color red */
10739 cmap = gdk_colormap_get_system();
10740 color.red = 0xffff;
10743 if (!gdk_color_alloc(cmap, &color)) {
10744 g_error("couldn't allocate color");
10747 /* Load a fixed font */
10748 fixed_font = gdk_font_load ("-misc-fixed-medium-r-*-*-*-140-*-*-*-*-*-*");
10750 /* Realizing a widget creates a window for it,
10751 * ready for us to insert some text */
10752 gtk_widget_realize (text);
10754 /* Freeze the text widget, ready for multiple updates */
10755 gtk_text_freeze (GTK_TEXT (text));
10757 /* Insert some colored text */
10758 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
10760 gtk_text_insert (GTK_TEXT (text), NULL, &color, NULL,
10762 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
10763 "text and different ", -1);
10764 gtk_text_insert (GTK_TEXT (text), fixed_font, &text->style->black, NULL,
10767 /* Load the file text.c into the text window */
10769 infile = fopen("text.c", "r");
10777 nchars = fread(buffer, 1, 1024, infile);
10778 gtk_text_insert (GTK_TEXT (text), fixed_font, NULL,
10779 NULL, buffer, nchars);
10788 /* Thaw the text widget, allowing the updates to become visible */
10789 gtk_text_thaw (GTK_TEXT (text));
10791 hbox = gtk_hbutton_box_new ();
10792 gtk_box_pack_start (GTK_BOX (box2), hbox, FALSE, FALSE, 0);
10793 gtk_widget_show (hbox);
10795 check = gtk_check_button_new_with_label("Editable");
10796 gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, FALSE, 0);
10797 gtk_signal_connect (GTK_OBJECT(check), "toggled",
10798 GTK_SIGNAL_FUNC(text_toggle_editable), text);
10799 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);
10800 gtk_widget_show (check);
10801 check = gtk_check_button_new_with_label("Wrap Words");
10802 gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, TRUE, 0);
10803 gtk_signal_connect (GTK_OBJECT(check), "toggled",
10804 GTK_SIGNAL_FUNC(text_toggle_word_wrap), text);
10805 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), FALSE);
10806 gtk_widget_show (check);
10808 separator = gtk_hseparator_new ();
10809 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
10810 gtk_widget_show (separator);
10812 box2 = gtk_vbox_new (FALSE, 10);
10813 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
10814 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
10815 gtk_widget_show (box2);
10817 button = gtk_button_new_with_label ("close");
10818 gtk_signal_connect (GTK_OBJECT (button), "clicked",
10819 GTK_SIGNAL_FUNC(close_application),
10821 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
10822 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
10823 gtk_widget_grab_default (button);
10824 gtk_widget_show (button);
10826 gtk_widget_show (window);
10836 <!-- ***************************************************************** -->
10837 <sect> Undocumented Widgets
10838 <!-- ***************************************************************** -->
10840 These all require authors! :) Please consider contributing to our
10843 If you must use one of these widgets that are undocumented, I strongly
10844 suggest you take a look at their respective header files in the GTK
10845 distribution. GTK's function names are very descriptive. Once you
10846 have an understanding of how things work, it's not difficult to figure
10847 out how to use a widget simply by looking at its function
10848 declarations. This, along with a few examples from others' code, and
10849 it should be no problem.
10851 When you do come to understand all the functions of a new undocumented
10852 widget, please consider writing a tutorial on it so others may benefit
10855 <!-- ----------------------------------------------------------------- -->
10858 <!-- ----------------------------------------------------------------- -->
10861 <!-- ----------------------------------------------------------------- -->
10862 <sect1> Drawing Area
10864 <!-- ----------------------------------------------------------------- -->
10865 <sect1> Font Selection Dialog
10867 <!-- ----------------------------------------------------------------- -->
10868 <sect1> Gamma Curve
10870 <!-- ----------------------------------------------------------------- -->
10873 <!-- ----------------------------------------------------------------- -->
10876 <!-- ----------------------------------------------------------------- -->
10877 <sect1> Plugs and Sockets
10879 <!-- ----------------------------------------------------------------- -->
10885 (This may need to be rewritten to follow the style of the rest of the tutorial)
10889 Previews serve a number of purposes in GIMP/GTK. The most important one is
10890 this. High quality images may take up to tens of megabytes of memory - easily!
10891 Any operation on an image that big is bound to take a long time. If it takes
10892 you 5-10 trial-and-errors (i.e., 10-20 steps, since you have to revert after
10893 you make an error) to choose the desired modification, it make take you
10894 literally hours to make the right one - if you don't run out of memory
10895 first. People who have spent hours in color darkrooms know the feeling.
10896 Previews to the rescue!
10898 But the annoyance of the delay is not the only issue. Oftentimes it is
10899 helpful to compare the Before and After versions side-by-side or at least
10900 back-to-back. If you're working with big images and 10 second delays,
10901 obtaining the Before and After impressions is, to say the least, difficult.
10902 For 30M images (4"x6", 600dpi, 24 bit) the side-by-side comparison is right
10903 out for most people, while back-to-back is more like back-to-1001, 1002,
10904 ..., 1010-back! Previews to the rescue!
10906 But there's more. Previews allow for side-by-side pre-previews. In other
10907 words, you write a plug-in (e.g., the filterpack simulation) which would have
10908 a number of here's-what-it-would-look-like-if-you-were-to-do-this previews.
10909 An approach like this acts as a sort of a preview palette and is very
10910 effective for subtle changes. Let's go previews!
10912 There's more. For certain plug-ins real-time image-specific human
10913 intervention maybe necessary. In the SuperNova plug-in, for example, the
10914 user is asked to enter the coordinates of the center of the future
10915 supernova. The easiest way to do this, really, is to present the user with a
10916 preview and ask him to interactively select the spot. Let's go previews!
10918 Finally, a couple of misc uses. One can use previews even when not working
10919 with big images. For example, they are useful when rendering complicated
10920 patterns. (Just check out the venerable Diffraction plug-in + many other
10921 ones!) As another example, take a look at the colormap rotation plug-in
10922 (work in progress). You can also use previews for little logos inside you
10923 plug-ins and even for an image of yourself, The Author. Let's go previews!
10925 When Not to Use Previews
10927 Don't use previews for graphs, drawing, etc. GDK is much faster for that. Use
10928 previews only for rendered images!
10932 You can stick a preview into just about anything. In a vbox, an hbox, a
10933 table, a button, etc. But they look their best in tight frames around them.
10934 Previews by themselves do not have borders and look flat without them. (Of
10935 course, if the flat look is what you want...) Tight frames provide the
10940 Previews in many ways are like any other widgets in GTK (whatever that
10941 means) except they possess an additional feature: they need to be filled with
10942 some sort of an image! First, we will deal exclusively with the GTK aspect
10943 of previews and then we'll discuss how to fill them.
10945 GtkWidget *preview!
10949 /* Create a preview widget,
10950 set its size, an show it */
10951 GtkWidget *preview;
10952 preview=gtk_preview_new(GTK_PREVIEW_COLOR)
10954 GTK_PREVIEW_GRAYSCALE);*/
10955 gtk_preview_size (GTK_PREVIEW (preview), WIDTH, HEIGHT);
10956 gtk_widget_show(preview);
10957 my_preview_rendering_function(preview);
10959 Oh yeah, like I said, previews look good inside frames, so how about:
10961 GtkWidget *create_a_preview(int Width,
10965 GtkWidget *preview;
10968 frame = gtk_frame_new(NULL);
10969 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
10970 gtk_container_set_border_width (GTK_CONTAINER(frame),0);
10971 gtk_widget_show(frame);
10973 preview=gtk_preview_new (Colorfulness?GTK_PREVIEW_COLOR
10974 :GTK_PREVIEW_GRAYSCALE);
10975 gtk_preview_size (GTK_PREVIEW (preview), Width, Height);
10976 gtk_container_add(GTK_CONTAINER(frame),preview);
10977 gtk_widget_show(preview);
10979 my_preview_rendering_function(preview);
10983 That's my basic preview. This routine returns the "parent" frame so you can
10984 place it somewhere else in your interface. Of course, you can pass the
10985 parent frame to this routine as a parameter. In many situations, however,
10986 the contents of the preview are changed continually by your application. In
10987 this case you may want to pass a pointer to the preview to a
10988 "create_a_preview()" and thus have control of it later.
10990 One more important note that may one day save you a lot of time. Sometimes
10991 it is desirable to label you preview. For example, you may label the preview
10992 containing the original image as "Original" and the one containing the
10993 modified image as "Less Original". It might occur to you to pack the
10994 preview along with the appropriate label into a vbox. The unexpected caveat
10995 is that if the label is wider than the preview (which may happen for a
10996 variety of reasons unforseeable to you, from the dynamic decision on the
10997 size of the preview to the size of the font) the frame expands and no longer
10998 fits tightly over the preview. The same problem can probably arise in other
10999 situations as well.
11003 The solution is to place the preview and the label into a 2x1 table and by
11004 attaching them with the following parameters (this is one possible variations
11005 of course. The key is no GTK_FILL in the second attachment):
11007 gtk_table_attach(GTK_TABLE(table),label,0,1,0,1,
11009 GTK_EXPAND|GTK_FILL,
11011 gtk_table_attach(GTK_TABLE(table),frame,0,1,1,2,
11017 And here's the result:
11023 Making a preview clickable is achieved most easily by placing it in a
11024 button. It also adds a nice border around the preview and you may not even
11025 need to place it in a frame. See the Filter Pack Simulation plug-in for an
11028 This is pretty much it as far as GTK is concerned.
11030 Filling In a Preview
11032 In order to familiarize ourselves with the basics of filling in previews,
11033 let's create the following pattern (contrived by trial and error):
11038 my_preview_rendering_function(GtkWidget *preview)
11041 #define HALF (SIZE/2)
11043 guchar *row=(guchar *) malloc(3*SIZE); /* 3 bits per dot */
11044 gint i, j; /* Coordinates */
11045 double r, alpha, x, y;
11047 if (preview==NULL) return; /* I usually add this when I want */
11048 /* to avoid silly crashes. You */
11049 /* should probably make sure that */
11050 /* everything has been nicely */
11052 for (j=0; j < ABS(cos(2*alpha)) ) { /* Are we inside the shape? */
11053 /* glib.h contains ABS(x). */
11054 row[i*3+0] = sqrt(1-r)*255; /* Define Red */
11055 row[i*3+1] = 128; /* Define Green */
11056 row[i*3+2] = 224; /* Define Blue */
11057 } /* "+0" is for alignment! */
11059 row[i*3+0] = r*255;
11060 row[i*3+1] = ABS(sin((float)i/SIZE*2*PI))*255;
11061 row[i*3+2] = ABS(sin((float)j/SIZE*2*PI))*255;
11064 gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,j,SIZE);
11065 /* Insert "row" into "preview" starting at the point with */
11066 /* coordinates (0,j) first column, j_th row extending SIZE */
11067 /* pixels to the right */
11070 free(row); /* save some space */
11071 gtk_widget_draw(preview,NULL); /* what does this do? */
11072 gdk_flush(); /* or this? */
11075 Non-GIMP users can have probably seen enough to do a lot of things already.
11076 For the GIMP users I have a few pointers to add.
11080 It is probably wise to keep a reduced version of the image around with just
11081 enough pixels to fill the preview. This is done by selecting every n'th
11082 pixel where n is the ratio of the size of the image to the size of the
11083 preview. All further operations (including filling in the previews) are then
11084 performed on the reduced number of pixels only. The following is my
11085 implementation of reducing the image. (Keep in mind that I've had only basic
11088 (UNTESTED CODE ALERT!!!)
11100 SELECTION_IN_CONTEXT,
11104 ReducedImage *Reduce_The_Image(GDrawable *drawable,
11109 /* This function reduced the image down to the the selected preview size */
11110 /* The preview size is determine by LongerSize, i.e., the greater of the */
11111 /* two dimensions. Works for RGB images only! */
11112 gint RH, RW; /* Reduced height and reduced width */
11113 gint width, height; /* Width and Height of the area being reduced */
11114 gint bytes=drawable->bpp;
11115 ReducedImage *temp=(ReducedImage *)malloc(sizeof(ReducedImage));
11117 guchar *tempRGB, *src_row, *tempmask, *src_mask_row,R,G,B;
11118 gint i, j, whichcol, whichrow, x1, x2, y1, y2;
11119 GPixelRgn srcPR, srcMask;
11120 gint NoSelectionMade=TRUE; /* Assume that we're dealing with the entire */
11123 gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
11126 /* If there's a SELECTION, we got its bounds!)
11128 if (width != drawable->width && height != drawable->height)
11129 NoSelectionMade=FALSE;
11130 /* Become aware of whether the user has made an active selection */
11131 /* This will become important later, when creating a reduced mask. */
11133 /* If we want to preview the entire image, overrule the above! */
11134 /* Of course, if no selection has been made, this does nothing! */
11135 if (Selection==ENTIRE_IMAGE) {
11137 x2=drawable->width;
11139 y2=drawable->height;
11142 /* If we want to preview a selection with some surrounding area we */
11143 /* have to expand it a little bit. Consider it a bit of a riddle. */
11144 if (Selection==SELECTION_IN_CONTEXT) {
11145 x1=MAX(0, x1-width/2.0);
11146 x2=MIN(drawable->width, x2+width/2.0);
11147 y1=MAX(0, y1-height/2.0);
11148 y2=MIN(drawable->height, y2+height/2.0);
11151 /* How we can determine the width and the height of the area being */
11156 /* The lines below determine which dimension is to be the longer */
11157 /* side. The idea borrowed from the supernova plug-in. I suspect I */
11158 /* could've thought of it myself, but the truth must be told. */
11159 /* Plagiarism stinks! */
11160 if (width>height) {
11162 RH=(float) height * (float) LongerSize/ (float) width;
11166 RW=(float)width * (float) LongerSize/ (float) height;
11169 /* The entire image is stretched into a string! */
11170 tempRGB = (guchar *) malloc(RW*RH*bytes);
11171 tempmask = (guchar *) malloc(RW*RH);
11173 gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height,
11175 gimp_pixel_rgn_init (&srcMask, mask, x1, y1, width, height,
11178 /* Grab enough to save a row of image and a row of mask. */
11179 src_row = (guchar *) malloc (width*bytes);
11180 src_mask_row = (guchar *) malloc (width);
11182 for (i=0; i < RH; i++) {
11183 whichrow=(float)i*(float)height/(float)RH;
11184 gimp_pixel_rgn_get_row (&srcPR, src_row, x1, y1+whichrow, width);
11185 gimp_pixel_rgn_get_row (&srcMask, src_mask_row, x1, y1+whichrow, width);
11187 for (j=0; j < RW; j++) {
11188 whichcol=(float)j*(float)width/(float)RW;
11190 /* No selection made = each point is completely selected! */
11191 if (NoSelectionMade)
11192 tempmask[i*RW+j]=255;
11194 tempmask[i*RW+j]=src_mask_row[whichcol];
11196 /* Add the row to the one long string which now contains the image! */
11197 tempRGB[i*RW*bytes+j*bytes+0]=src_row[whichcol*bytes+0];
11198 tempRGB[i*RW*bytes+j*bytes+1]=src_row[whichcol*bytes+1];
11199 tempRGB[i*RW*bytes+j*bytes+2]=src_row[whichcol*bytes+2];
11201 /* Hold on to the alpha as well */
11203 tempRGB[i*RW*bytes+j*bytes+3]=src_row[whichcol*bytes+3];
11210 temp->mask=tempmask;
11214 The following is a preview function which used the same ReducedImage type!
11215 Note that it uses fakes transparency (if one is present by means of
11216 fake_transparency which is defined as follows:
11218 gint fake_transparency(gint i, gint j)
11220 if ( ((i%20)- 10) * ((j%20)- 10)>0 )
11226 Now here's the preview function:
11229 my_preview_render_function(GtkWidget *preview,
11233 gint Inten, bytes=drawable->bpp;
11236 gint RW=reduced->width;
11237 gint RH=reduced->height;
11238 guchar *row=malloc(bytes*RW);;
11241 for (i=0; i < RH; i++) {
11242 for (j=0; j < RW; j++) {
11244 row[j*3+0] = reduced->rgb[i*RW*bytes + j*bytes + 0];
11245 row[j*3+1] = reduced->rgb[i*RW*bytes + j*bytes + 1];
11246 row[j*3+2] = reduced->rgb[i*RW*bytes + j*bytes + 2];
11249 for (k=0; k<3; k++) {
11250 float transp=reduced->rgb[i*RW*bytes+j*bytes+3]/255.0;
11251 row[3*j+k]=transp*a[3*j+k]+(1-transp)*fake_transparency(i,j);
11254 gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,i,RW);
11258 gtk_widget_draw(preview,NULL);
11262 Applicable Routines
11264 guint gtk_preview_get_type (void);
11266 void gtk_preview_uninit (void);
11268 GtkWidget* gtk_preview_new (GtkPreviewType type);
11269 /* Described above */
11270 void gtk_preview_size (GtkPreview *preview,
11273 /* Allows you to resize an existing preview. */
11274 /* Apparently there's a bug in GTK which makes */
11275 /* this process messy. A way to clean up a mess */
11276 /* is to manually resize the window containing */
11277 /* the preview after resizing the preview. */
11279 void gtk_preview_put (GtkPreview *preview,
11290 void gtk_preview_put_row (GtkPreview *preview,
11298 void gtk_preview_draw_row (GtkPreview *preview,
11303 /* Described in the text */
11305 void gtk_preview_set_expand (GtkPreview *preview,
11309 /* No clue for any of the below but */
11310 /* should be standard for most widgets */
11311 void gtk_preview_set_gamma (double gamma);
11312 void gtk_preview_set_color_cube (guint nred_shades,
11313 guint ngreen_shades,
11314 guint nblue_shades,
11315 guint ngray_shades);
11316 void gtk_preview_set_install_cmap (gint install_cmap);
11317 void gtk_preview_set_reserved (gint nreserved);
11318 GdkVisual* gtk_preview_get_visual (void);
11319 GdkColormap* gtk_preview_get_cmap (void);
11320 GtkPreviewInfo* gtk_preview_get_info (void);
11328 <!-- ***************************************************************** -->
11329 <sect>Setting Widget Attributes<label id="sec_setting_widget_attributes">
11330 <!-- ***************************************************************** -->
11332 This describes the functions used to operate on widgets. These can be
11333 used to set style, padding, size, etc.
11335 (Maybe I should make a whole section on accelerators.)
11338 void gtk_widget_install_accelerator( GtkWidget *widget,
11339 GtkAcceleratorTable *table,
11340 gchar *signal_name,
11342 guint8 modifiers );
11344 void gtk_widget_remove_accelerator ( GtkWidget *widget,
11345 GtkAcceleratorTable *table,
11346 gchar *signal_name);
11348 void gtk_widget_activate( GtkWidget *widget );
11350 void gtk_widget_set_name( GtkWidget *widget,
11353 gchar *gtk_widget_get_name( GtkWidget *widget );
11355 void gtk_widget_set_sensitive( GtkWidget *widget,
11358 void gtk_widget_set_style( GtkWidget *widget,
11361 GtkStyle *gtk_widget_get_style( GtkWidget *widget );
11363 GtkStyle *gtk_widget_get_default_style( void );
11365 void gtk_widget_set_uposition( GtkWidget *widget,
11369 void gtk_widget_set_usize( GtkWidget *widget,
11373 void gtk_widget_grab_focus( GtkWidget *widget );
11375 void gtk_widget_show( GtkWidget *widget );
11377 void gtk_widget_hide( GtkWidget *widget );
11380 <!-- ***************************************************************** -->
11381 <sect>Timeouts, IO and Idle Functions<label id="sec_timeouts">
11382 <!-- ***************************************************************** -->
11384 <!-- ----------------------------------------------------------------- -->
11387 You may be wondering how you make GTK do useful work when in gtk_main.
11388 Well, you have several options. Using the following function you can
11389 create a timeout function that will be called every "interval"
11393 gint gtk_timeout_add( guint32 interval,
11394 GtkFunction function,
11398 The first argument is the number of milliseconds between calls to your
11399 function. The second argument is the function you wish to have called,
11400 and the third, the data passed to this callback function. The return
11401 value is an integer "tag" which may be used to stop the timeout by
11405 void gtk_timeout_remove( gint tag );
11408 You may also stop the timeout function by returning zero or FALSE from
11409 your callback function. Obviously this means if you want your function
11410 to continue to be called, it should return a non-zero value,
11413 The declaration of your callback should look something like this:
11416 gint timeout_callback( gpointer data );
11419 <!-- ----------------------------------------------------------------- -->
11420 <sect1>Monitoring IO
11422 A nifty feature of GDK (the library that underlies GTK), is the
11423 ability to have it check for data on a file descriptor for you (as
11424 returned by open(2) or socket(2)). This is especially useful for
11425 networking applications. The function:
11428 gint gdk_input_add( gint source,
11429 GdkInputCondition condition,
11430 GdkInputFunction function,
11434 Where the first argument is the file descriptor you wish to have
11435 watched, and the second specifies what you want GDK to look for. This
11439 <item><tt/GDK_INPUT_READ/ - Call your function when there is data
11440 ready for reading on your file descriptor.
11442 <item>><tt/GDK_INPUT_WRITE/ - Call your function when the file
11443 descriptor is ready for writing.
11446 As I'm sure you've figured out already, the third argument is the
11447 function you wish to have called when the above conditions are
11448 satisfied, and the fourth is the data to pass to this function.
11450 The return value is a tag that may be used to stop GDK from monitoring
11451 this file descriptor using the following function.
11454 void gdk_input_remove( gint tag );
11457 The callback function should be declared as:
11460 void input_callback( gpointer data,
11462 GdkInputCondition condition );
11465 Where <tt/source/ and <tt/condition/ are as specified above.
11467 <!-- ----------------------------------------------------------------- -->
11468 <sect1>Idle Functions
11470 <!-- TODO: Need to check on idle priorities - TRG -->
11471 What if you have a function which you want to be called when nothing
11472 else is happening ?
11475 gint gtk_idle_add( GtkFunction function,
11479 This causes GTK to call the specified function whenever nothing else
11483 void gtk_idle_remove( gint tag );
11486 I won't explain the meaning of the arguments as they follow very much
11487 like the ones above. The function pointed to by the first argument to
11488 gtk_idle_add will be called whenever the opportunity arises. As with
11489 the others, returning FALSE will stop the idle function from being
11492 <!-- ***************************************************************** -->
11493 <sect>Advanced Event and Signal Handling<label id="sec_Adv_Events_and_Signals">
11494 <!-- ***************************************************************** -->
11496 <!-- ----------------------------------------------------------------- -->
11497 <sect1>Signal Functions
11499 <!-- ----------------------------------------------------------------- -->
11500 <sect2>Connecting and Disconnecting Signal Handlers
11504 guint gtk_signal_connect( GtkObject *object,
11506 GtkSignalFunc func,
11507 gpointer func_data );
11509 guint gtk_signal_connect_after( GtkObject *object,
11511 GtkSignalFunc func,
11512 gpointer func_data );
11514 guint gtk_signal_connect_object( GtkObject *object,
11516 GtkSignalFunc func,
11517 GtkObject *slot_object );
11519 guint gtk_signal_connect_object_after( GtkObject *object,
11521 GtkSignalFunc func,
11522 GtkObject *slot_object );
11524 guint gtk_signal_connect_full( GtkObject *object,
11526 GtkSignalFunc func,
11527 GtkCallbackMarshal marshal,
11529 GtkDestroyNotify destroy_func,
11530 gint object_signal,
11533 guint gtk_signal_connect_interp( GtkObject *object,
11535 GtkCallbackMarshal func,
11537 GtkDestroyNotify destroy_func,
11540 void gtk_signal_connect_object_while_alive( GtkObject *object,
11541 const gchar *signal,
11542 GtkSignalFunc func,
11543 GtkObject *alive_object );
11545 void gtk_signal_connect_while_alive( GtkObject *object,
11546 const gchar *signal,
11547 GtkSignalFunc func,
11548 gpointer func_data,
11549 GtkObject *alive_object );
11551 void gtk_signal_disconnect( GtkObject *object,
11552 guint handler_id );
11554 void gtk_signal_disconnect_by_func( GtkObject *object,
11555 GtkSignalFunc func,
11559 <!-- ----------------------------------------------------------------- -->
11560 <sect2>Blocking and Unblocking Signal Handlers
11563 void gtk_signal_handler_block( GtkObject *object,
11566 void gtk_signal_handler_block_by_func( GtkObject *object,
11567 GtkSignalFunc func,
11570 void gtk_signal_handler_block_by_data( GtkObject *object,
11573 void gtk_signal_handler_unblock( GtkObject *object,
11574 guint handler_id );
11576 void gtk_signal_handler_unblock_by_func( GtkObject *object,
11577 GtkSignalFunc func,
11580 void gtk_signal_handler_unblock_by_data( GtkObject *object,
11584 <!-- ----------------------------------------------------------------- -->
11585 <sect2>Emitting and Stopping Signals
11588 void gtk_signal_emit( GtkObject *object,
11592 void gtk_signal_emit_by_name( GtkObject *object,
11596 void gtk_signal_emitv( GtkObject *object,
11600 void gtk_signal_emitv_by_name( GtkObject *object,
11604 guint gtk_signal_n_emissions( GtkObject *object,
11607 guint gtk_signal_n_emissions_by_name( GtkObject *object,
11608 const gchar *name );
11610 void gtk_signal_emit_stop( GtkObject *object,
11613 void gtk_signal_emit_stop_by_name( GtkObject *object,
11614 const gchar *name );
11617 <!-- ----------------------------------------------------------------- -->
11618 <sect1>Signal Emission and Propagation
11620 Signal emission is the process whereby GTK runs all handlers for a
11621 specific object and signal.
11623 First, note that the return value from a signal emission is the return
11624 value of the <em>last</em> handler executed. Since event signals are
11625 all of type <tt/GTK_RUN_LAST/, this will be the default (GTK supplied)
11626 handler, unless you connect with gtk_signal_connect_after().
11628 The way an event (say "button_press_event") is handled, is:
11630 <item>Start with the widget where the event occured.
11632 <item>Emit the generic "event" signal. If that signal handler returns
11633 a value of TRUE, stop all processing.
11635 <item>Otherwise, emit a specific, "button_press_event" signal. If that
11636 returns TRUE, stop all processing.
11638 <item>Otherwise, go to the widget's parent, and repeat the above two
11641 <item>Continue until some signal handler returns TRUE, or until the
11642 top-level widget is reached.
11645 Some consequences of the above are:
11647 <item>Your handler's return value will have no effect if there is a
11648 default handler, unless you connect with gtk_signal_connect_after().
11650 <item>To prevent the default handler from being run, you need to
11651 connect with gtk_signal_connect() and use
11652 gtk_signal_emit_stop_by_name() - the return value only affects whether
11653 the signal is propagated, not the current emission.
11656 <!-- ***************************************************************** -->
11657 <sect>Managing Selections
11658 <!-- ***************************************************************** -->
11660 <!-- ----------------------------------------------------------------- -->
11663 One type of interprocess communication supported by X and GTK is
11664 <em>selections</em>. A selection identifies a chunk of data, for
11665 instance, a portion of text, selected by the user in some fashion, for
11666 instance, by dragging with the mouse. Only one application on a
11667 display (the <em>owner</em>) can own a particular selection at one
11668 time, so when a selection is claimed by one application, the previous
11669 owner must indicate to the user that selection has been
11670 relinquished. Other applications can request the contents of a
11671 selection in different forms, called <em>targets</em>. There can be
11672 any number of selections, but most X applications only handle one, the
11673 <em>primary selection</em>.
11675 In most cases, it isn't necessary for a GTK application to deal with
11676 selections itself. The standard widgets, such as the Entry widget,
11677 already have the capability to claim the selection when appropriate
11678 (e.g., when the user drags over text), and to retrieve the contents of
11679 the selection owned by another widget or another application (e.g.,
11680 when the user clicks the second mouse button). However, there may be
11681 cases in which you want to give other widgets the ability to supply
11682 the selection, or you wish to retrieve targets not supported by
11685 A fundamental concept needed to understand selection handling is that
11686 of the <em>atom</em>. An atom is an integer that uniquely identifies a
11687 string (on a certain display). Certain atoms are predefined by the X
11688 server, and in some cases there are constants in <tt>gtk.h</tt>
11689 corresponding to these atoms. For instance the constant
11690 <tt>GDK_PRIMARY_SELECTION</tt> corresponds to the string "PRIMARY".
11691 In other cases, you should use the functions
11692 <tt>gdk_atom_intern()</tt>, to get the atom corresponding to a string,
11693 and <tt>gdk_atom_name()</tt>, to get the name of an atom. Both
11694 selections and targets are identified by atoms.
11696 <!-- ----------------------------------------------------------------- -->
11697 <sect1> Retrieving the selection
11699 Retrieving the selection is an asynchronous process. To start the
11703 gint gtk_selection_convert( GtkWidget *widget,
11709 This <em>converts</em> the selection into the form specified by
11710 <tt/target/. If at all possible, the time field should be the time
11711 from the event that triggered the selection. This helps make sure that
11712 events occur in the order that the user requested them. However, if it
11713 is not available (for instance, if the conversion was triggered by a
11714 "clicked" signal), then you can use the constant
11715 <tt>GDK_CURRENT_TIME</tt>.
11717 When the selection owner responds to the request, a
11718 "selection_received" signal is sent to your application. The handler
11719 for this signal receives a pointer to a <tt>GtkSelectionData</tt>
11720 structure, which is defined as:
11723 struct _GtkSelectionData
11734 <tt>selection</tt> and <tt>target</tt> are the values you gave in your
11735 <tt>gtk_selection_convert()</tt> call. <tt>type</tt> is an atom that
11736 identifies the type of data returned by the selection owner. Some
11737 possible values are "STRING", a string of latin-1 characters, "ATOM",
11738 a series of atoms, "INTEGER", an integer, etc. Most targets can only
11739 return one type. <tt/format/ gives the length of the units (for
11740 instance characters) in bits. Usually, you don't care about this when
11741 receiving data. <tt>data</tt> is a pointer to the returned data, and
11742 <tt>length</tt> gives the length of the returned data, in bytes. If
11743 <tt>length</tt> is negative, then an error occurred and the selection
11744 could not be retrieved. This might happen if no application owned the
11745 selection, or if you requested a target that the application didn't
11746 support. The buffer is actually guaranteed to be one byte longer than
11747 <tt>length</tt>; the extra byte will always be zero, so it isn't
11748 necessary to make a copy of strings just to null terminate them.
11750 In the following example, we retrieve the special target "TARGETS",
11751 which is a list of all targets into which the selection can be
11755 /* example-start selection gettargets.c */
11757 #include <gtk/gtk.h>
11759 void selection_received( GtkWidget *widget,
11760 GtkSelectionData *selection_data,
11763 /* Signal handler invoked when user clicks on the "Get Targets" button */
11764 void get_targets( GtkWidget *widget,
11767 static GdkAtom targets_atom = GDK_NONE;
11769 /* Get the atom corresponding to the string "TARGETS" */
11770 if (targets_atom == GDK_NONE)
11771 targets_atom = gdk_atom_intern ("TARGETS", FALSE);
11773 /* And request the "TARGETS" target for the primary selection */
11774 gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
11778 /* Signal handler called when the selections owner returns the data */
11779 void selection_received( GtkWidget *widget,
11780 GtkSelectionData *selection_data,
11787 /* **** IMPORTANT **** Check to see if retrieval succeeded */
11788 if (selection_data->length < 0)
11790 g_print ("Selection retrieval failed\n");
11793 /* Make sure we got the data in the expected form */
11794 if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
11796 g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
11800 /* Print out the atoms we received */
11801 atoms = (GdkAtom *)selection_data->data;
11804 for (i=0; i<selection_data->length/sizeof(GdkAtom); i++)
11807 name = gdk_atom_name (atoms[i]);
11809 g_print ("%s\n",name);
11811 g_print ("(bad atom)\n");
11817 int main( int argc,
11823 gtk_init (&argc, &argv);
11825 /* Create the toplevel window */
11827 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11828 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
11829 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
11831 gtk_signal_connect (GTK_OBJECT (window), "destroy",
11832 GTK_SIGNAL_FUNC (gtk_exit), NULL);
11834 /* Create a button the user can click to get targets */
11836 button = gtk_button_new_with_label ("Get Targets");
11837 gtk_container_add (GTK_CONTAINER (window), button);
11839 gtk_signal_connect (GTK_OBJECT(button), "clicked",
11840 GTK_SIGNAL_FUNC (get_targets), NULL);
11841 gtk_signal_connect (GTK_OBJECT(button), "selection_received",
11842 GTK_SIGNAL_FUNC (selection_received), NULL);
11844 gtk_widget_show (button);
11845 gtk_widget_show (window);
11854 <!-- ----------------------------------------------------------------- -->
11855 <sect1> Supplying the selection
11857 Supplying the selection is a bit more complicated. You must register
11858 handlers that will be called when your selection is requested. For
11859 each selection/target pair you will handle, you make a call to:
11862 void gtk_selection_add_target (GtkWidget *widget,
11868 <tt/widget/, <tt/selection/, and <tt/target/ identify the requests
11869 this handler will manage. When a request for a selection is received,
11870 the "selection_get" signal will be called. <tt/info/ can be used as an
11871 enumerator to identify the specific target within the callback function.
11873 The callback function has the signature:
11876 void "selection_get" (GtkWidget *widget,
11877 GtkSelectionData *selection_data,
11882 The GtkSelectionData is the same as above, but this time, we're
11883 responsible for filling in the fields <tt/type/, <tt/format/,
11884 <tt/data/, and <tt/length/. (The <tt/format/ field is actually
11885 important here - the X server uses it to figure out whether the data
11886 needs to be byte-swapped or not. Usually it will be 8 - <em/i.e./ a
11887 character - or 32 - <em/i.e./ a. integer.) This is done by calling the
11891 void gtk_selection_data_set( GtkSelectionData *selection_data,
11898 This function takes care of properly making a copy of the data so that
11899 you don't have to worry about keeping it around. (You should not fill
11900 in the fields of the GtkSelectionData structure by hand.)
11902 When prompted by the user, you claim ownership of the selection by
11906 gint gtk_selection_owner_set( GtkWidget *widget,
11911 If another application claims ownership of the selection, you will
11912 receive a "selection_clear_event".
11914 As an example of supplying the selection, the following program adds
11915 selection functionality to a toggle button. When the toggle button is
11916 depressed, the program claims the primary selection. The only target
11917 supported (aside from certain targets like "TARGETS" supplied by GTK
11918 itself), is the "STRING" target. When this target is requested, a
11919 string representation of the time is returned.
11922 /* example-start selection setselection.c */
11924 #include <gtk/gtk.h>
11927 /* Callback when the user toggles the selection */
11928 void selection_toggled( GtkWidget *widget,
11929 gint *have_selection )
11931 if (GTK_TOGGLE_BUTTON(widget)->active)
11933 *have_selection = gtk_selection_owner_set (widget,
11934 GDK_SELECTION_PRIMARY,
11936 /* if claiming the selection failed, we return the button to
11938 if (!*have_selection)
11939 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), FALSE);
11943 if (*have_selection)
11945 /* Before clearing the selection by setting the owner to NULL,
11946 we check if we are the actual owner */
11947 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
11948 gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
11950 *have_selection = FALSE;
11955 /* Called when another application claims the selection */
11956 gint selection_clear( GtkWidget *widget,
11957 GdkEventSelection *event,
11958 gint *have_selection )
11960 *have_selection = FALSE;
11961 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), FALSE);
11966 /* Supplies the current time as the selection. */
11967 void selection_handle( GtkWidget *widget,
11968 GtkSelectionData *selection_data,
11974 time_t current_time;
11976 current_time = time(NULL);
11977 timestr = asctime (localtime(&current_time));
11978 /* When we return a single string, it should not be null terminated.
11979 That will be done for us */
11981 gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
11982 8, timestr, strlen(timestr));
11985 int main( int argc,
11989 GtkWidget *selection_button;
11991 static int have_selection = FALSE;
11993 gtk_init (&argc, &argv);
11995 /* Create the toplevel window */
11997 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11998 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
11999 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
12001 gtk_signal_connect (GTK_OBJECT (window), "destroy",
12002 GTK_SIGNAL_FUNC (gtk_exit), NULL);
12004 /* Create a toggle button to act as the selection */
12006 selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
12007 gtk_container_add (GTK_CONTAINER (window), selection_button);
12008 gtk_widget_show (selection_button);
12010 gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
12011 GTK_SIGNAL_FUNC (selection_toggled), &have_selection);
12012 gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
12013 GTK_SIGNAL_FUNC (selection_clear), &have_selection);
12015 gtk_selection_add_target (selection_button,
12016 GDK_SELECTION_PRIMARY,
12017 GDK_SELECTION_TYPE_STRING,
12019 gtk_signal_connect (GTK_OBJECT(selection_button), "selection_get",
12020 GTK_SIGNAL_FUNC (selection_handle), &have_selection);
12022 gtk_widget_show (selection_button);
12023 gtk_widget_show (window);
12033 <!-- ***************************************************************** -->
12034 <sect>GLib<label id="sec_glib">
12035 <!-- ***************************************************************** -->
12037 GLib is a lower-level library that provides many useful definitions
12038 and functions available for use when creating GDK and GTK
12039 applications. These include definitions for basic types and their
12040 limits, standard macros, type conversions, byte order, memory
12041 allocation, warnings and assertions, message logging, timers, string
12042 utilities, hook functions, a lexical scanner, dynamic loading of
12043 modules, and automatic string completion. A number of data structures
12044 (and their related operations) are also defined, including memory
12045 chunks, doubly-linked lists, singly-linked lists, hash tables, strings
12046 (which can grow dynamically), string chunks (groups of strings),
12047 arrays (which can grow in size as elements are added), balanced binary
12048 trees, N-ary trees, quarks (a two-way association of a string and a
12049 unique integer identifier), keyed data lists (lists of data elements
12050 accessible by a string or integer id), relations and tuples (tables of
12051 data which can be indexed on any number of fields), and caches.
12053 A summary of some of GLib's capabilities follows; not every function,
12054 data structure, or operation is covered here. For more complete
12055 information about the GLib routines, see the GLib documentation. One
12056 source of GLib documentation is <htmlurl url="http://www.gtk.org/"
12057 name="http://www.gtk.org/">.
12059 If you are using a language other than C, you should consult your
12060 language's binding documentation. In some cases your language may
12061 have equivalent functionality built-in, while in other cases it may
12064 <!-- ----------------------------------------------------------------- -->
12067 Definitions for the extremes of many of the standard types are:
12082 Also, the following typedefs. The ones left unspecified are dynamically set
12083 depending on the architecture. Remember to avoid counting on the size of a
12084 pointer if you want to be portable! E.g., a pointer on an Alpha is 8
12085 bytes, but 4 on Intel 80x86 family CPUs.
12094 unsigned char guchar;
12095 unsigned short gushort;
12096 unsigned long gulong;
12097 unsigned int guint;
12101 long double gldouble;
12113 <!-- ----------------------------------------------------------------- -->
12114 <sect1>Doubly Linked Lists
12116 The following functions are used to create, manage, and destroy
12117 standard doubly linked lists. Each element in the list contains a
12118 piece of data, together with pointers which link to the previous and
12119 next elements in the list. This enables easy movement in either
12120 direction through the list. The data item is of type "gpointer",
12121 which means the data can be a pointer to your real data or (through
12122 casting) a numeric value (but do not assume that int and gpointer have
12123 the same size!). These routines internally allocate list elements in
12124 blocks, which is more efficient than allocating elements individually.
12126 There is no function to specifically create a list. Instead, simply
12127 create a variable of type GList* and set its value to NULL; NULL is
12128 considered to be the empty list.
12130 To add elements to a list, use the g_list_append(), g_list_prepend(),
12131 g_list_insert(), or g_list_insert_sorted() routines. In all cases
12132 they accept a pointer to the beginning of the list, and return the
12133 (possibly changed) pointer to the beginning of the list. Thus, for
12134 all of the operations that add or remove elements, be sure to save the
12138 GList *g_list_append( GList *list,
12142 This adds a new element (with value <tt/data/) onto the end of the
12146 GList *g_list_prepend( GList *list,
12150 This adds a new element (with value <tt/data/) to the beginning of the
12154 GList *g_list_insert( GList *list,
12160 This inserts a new element (with value data) into the list at the
12161 given position. If position is 0, this is just like g_list_prepend();
12162 if position is less than 0, this is just like g_list_append().
12165 GList *g_list_remove( GList *list,
12169 This removes the element in the list with the value <tt/data/;
12170 if the element isn't there, the list is unchanged.
12173 void g_list_free( GList *list );
12176 This frees all of the memory used by a GList. If the list elements
12177 refer to dynamically-allocated memory, then they should be freed
12180 There are many other GLib functions that support doubly linked lists;
12181 see the glib documentation for more information. Here are a few of
12182 the more useful functions' signatures:
12185 GList *g_list_remove_link( GList *list,
12188 GList *g_list_reverse( GList *list );
12190 GList *g_list_nth( GList *list,
12193 GList *g_list_find( GList *list,
12196 GList *g_list_last( GList *list );
12198 GList *g_list_first( GList *list );
12200 gint g_list_length( GList *list );
12202 void g_list_foreach( GList *list,
12204 gpointer user_data );
12207 <!-- ----------------------------------------------------------------- -->
12208 <sect1>Singly Linked Lists
12210 Many of the above functions for singly linked lists are identical to the
12211 above. Here is a list of some of their operations:
12214 GSList *g_slist_append( GSList *list,
12217 GSList *g_slist_prepend( GSList *list,
12220 GSList *g_slist_insert( GSList *list,
12224 GSList *g_slist_remove( GSList *list,
12227 GSList *g_slist_remove_link( GSList *list,
12230 GSList *g_slist_reverse( GSList *list );
12232 GSList *g_slist_nth( GSList *list,
12235 GSList *g_slist_find( GSList *list,
12238 GSList *g_slist_last( GSList *list );
12240 gint g_slist_length( GSList *list );
12242 void g_slist_foreach( GSList *list,
12244 gpointer user_data );
12248 <!-- ----------------------------------------------------------------- -->
12249 <sect1>Memory Management
12252 gpointer g_malloc( gulong size );
12255 This is a replacement for malloc(). You do not need to check the return
12256 value as it is done for you in this function. If the memory allocation
12257 fails for whatever reasons, your applications will be terminated.
12260 gpointer g_malloc0( gulong size );
12263 Same as above, but zeroes the memory before returning a pointer to it.
12266 gpointer g_realloc( gpointer mem,
12270 Relocates "size" bytes of memory starting at "mem". Obviously, the
12271 memory should have been previously allocated.
12274 void g_free( gpointer mem );
12277 Frees memory. Easy one. If <tt/mem/ is NULL it simply returns.
12280 void g_mem_profile( void );
12283 Dumps a profile of used memory, but requires that you add <tt>#define
12284 MEM_PROFILE</tt> to the top of glib/gmem.c and re-make and make install.
12287 void g_mem_check( gpointer mem );
12290 Checks that a memory location is valid. Requires you add <tt>#define
12291 MEM_CHECK</tt> to the top of gmem.c and re-make and make install.
12293 <!-- ----------------------------------------------------------------- -->
12296 Timer functions can be used to time operations (e.g., to see how much
12297 time has elapsed). First, you create a new timer with g_timer_new().
12298 You can then use g_timer_start() to start timing an operation,
12299 g_timer_stop() to stop timing an operation, and g_timer_elapsed() to
12300 determine the elapsed time.
12303 GTimer *g_timer_new( void );
12305 void g_timer_destroy( GTimer *timer );
12307 void g_timer_start( GTimer *timer );
12309 void g_timer_stop( GTimer *timer );
12311 void g_timer_reset( GTimer *timer );
12313 gdouble g_timer_elapsed( GTimer *timer,
12314 gulong *microseconds );
12317 <!-- ----------------------------------------------------------------- -->
12318 <sect1>String Handling
12320 GLib defines a new type called a GString, which is similar to a
12321 standard C string but one that grows automatically. Its string data
12322 is null-terminated. What this gives you is protection from buffer
12323 overflow programming errors within your program. This is a very
12324 important feature, and hence I recommend that you make use of
12325 GStrings. GString itself has a simple public definition:
12330 gchar *str; /* Points to the string's current \0-terminated value. */
12331 gint len; /* Current length */
12335 As you might expect, there are a number of operations you can do with
12339 GString *g_string_new( gchar *init );
12342 This constructs a GString, copying the string value of <tt/init/
12343 into the GString and returning a pointer to it. NULL may be given as
12344 the argument for an initially empty GString.
12348 void g_string_free( GString *string,
12349 gint free_segment );
12352 This frees the memory for the given GString. If <tt/free_segment/ is
12353 TRUE, then this also frees its character data.
12357 GString *g_string_assign( GString *lval,
12358 const gchar *rval );
12361 This copies the characters from rval into lval, destroying the
12362 previous contents of lval. Note that lval will be lengthened as
12363 necessary to hold the string's contents, unlike the standard strcpy()
12366 The rest of these functions should be relatively obvious (the _c
12367 versions accept a character instead of a string):
12370 GString *g_string_truncate( GString *string,
12373 GString *g_string_append( GString *string,
12376 GString *g_string_append_c( GString *string,
12379 GString *g_string_prepend( GString *string,
12382 GString *g_string_prepend_c( GString *string,
12385 void g_string_sprintf( GString *string,
12389 void g_string_sprintfa ( GString *string,
12394 <!-- ----------------------------------------------------------------- -->
12395 <sect1>Utility and Error Functions
12398 gchar *g_strdup( const gchar *str );
12401 Replacement strdup function. Copies the original strings contents to
12402 newly allocated memory, and returns a pointer to it.
12405 gchar *g_strerror( gint errnum );
12408 I recommend using this for all error messages. It's much nicer, and more
12409 portable than perror() or others. The output is usually of the form:
12412 program name:function that failed:file or further description:strerror
12415 Here's an example of one such call used in our hello_world program:
12418 g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
12422 void g_error( gchar *format, ... );
12425 Prints an error message. The format is just like printf, but it
12426 prepends "** ERROR **: " to your message, and exits the program.
12427 Use only for fatal errors.
12430 void g_warning( gchar *format, ... );
12433 Same as above, but prepends "** WARNING **: ", and does not exit the
12437 void g_message( gchar *format, ... );
12440 Prints "message: " prepended to the string you pass in.
12443 void g_print( gchar *format, ... );
12446 Replacement for printf().
12448 And our last function:
12451 gchar *g_strsignal( gint signum );
12454 Prints out the name of the Unix system signal given the signal number.
12455 Useful in generic signal handling functions.
12457 All of the above are more or less just stolen from glib.h. If anyone cares
12458 to document any function, just send me an email!
12460 <!-- ***************************************************************** -->
12461 <sect>GTK's rc Files <label id="sec_gtkrc_files">
12462 <!-- ***************************************************************** -->
12464 GTK has its own way of dealing with application defaults, by using rc
12465 files. These can be used to set the colors of just about any widget, and
12466 can also be used to tile pixmaps onto the background of some widgets.
12468 <!-- ----------------------------------------------------------------- -->
12469 <sect1>Functions For rc Files
12471 When your application starts, you should include a call to:
12474 void gtk_rc_parse( char *filename );
12477 Passing in the filename of your rc file. This will cause GTK to parse
12478 this file, and use the style settings for the widget types defined
12481 If you wish to have a special set of widgets that can take on a
12482 different style from others, or any other logical division of widgets,
12486 void gtk_widget_set_name( GtkWidget *widget,
12490 Passing your newly created widget as the first argument, and the name
12491 you wish to give it as the second. This will allow you to change the
12492 attributes of this widget by name through the rc file.
12494 If we use a call something like this:
12497 button = gtk_button_new_with_label ("Special Button");
12498 gtk_widget_set_name (button, "special button");
12501 Then this button is given the name "special button" and may be addressed by
12502 name in the rc file as "special button.GtkButton". [<--- Verify ME!]
12504 The example rc file below, sets the properties of the main window, and lets
12505 all children of that main window inherit the style described by the "main
12506 button" style. The code used in the application is:
12509 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
12510 gtk_widget_set_name (window, "main window");
12513 And then the style is defined in the rc file using:
12516 widget "main window.*GtkButton*" style "main_button"
12519 Which sets all the Button widgets in the "main window" to the
12520 "main_buttons" style as defined in the rc file.
12522 As you can see, this is a fairly powerful and flexible system. Use your
12523 imagination as to how best to take advantage of this.
12525 <!-- ----------------------------------------------------------------- -->
12526 <sect1>GTK's rc File Format
12528 The format of the GTK file is illustrated in the example below. This is
12529 the testgtkrc file from the GTK distribution, but I've added a
12530 few comments and things. You may wish to include this explanation in
12531 your application to allow the user to fine tune his application.
12533 There are several directives to change the attributes of a widget.
12536 <item>fg - Sets the foreground color of a widget.
12537 <item>bg - Sets the background color of a widget.
12538 <item>bg_pixmap - Sets the background of a widget to a tiled pixmap.
12539 <item>font - Sets the font to be used with the given widget.
12542 In addition to this, there are several states a widget can be in, and you
12543 can set different colors, pixmaps and fonts for each state. These states are:
12546 <item>NORMAL - The normal state of a widget, without the mouse over top of
12547 it, and not being pressed, etc.
12548 <item>PRELIGHT - When the mouse is over top of the widget, colors defined
12549 using this state will be in effect.
12550 <item>ACTIVE - When the widget is pressed or clicked it will be active, and
12551 the attributes assigned by this tag will be in effect.
12552 <item>INSENSITIVE - When a widget is set insensitive, and cannot be
12553 activated, it will take these attributes.
12554 <item>SELECTED - When an object is selected, it takes these attributes.
12557 When using the "fg" and "bg" keywords to set the colors of widgets, the
12561 fg[<STATE>] = { Red, Green, Blue }
12564 Where STATE is one of the above states (PRELIGHT, ACTIVE, etc), and the Red,
12565 Green and Blue are values in the range of 0 - 1.0, { 1.0, 1.0, 1.0 } being
12566 white. They must be in float form, or they will register as 0, so a straight
12567 "1" will not work, it must be "1.0". A straight "0" is fine because it
12568 doesn't matter if it's not recognized. Unrecognized values are set to 0.
12570 bg_pixmap is very similar to the above, except the colors are replaced by a
12573 pixmap_path is a list of paths separated by ":"'s. These paths will be
12574 searched for any pixmap you specify.
12576 The font directive is simply:
12578 font = "<font name>"
12581 The only hard part is figuring out the font string. Using xfontsel or
12582 a similar utility should help.
12584 The "widget_class" sets the style of a class of widgets. These classes are
12585 listed in the widget overview on the class hierarchy.
12587 The "widget" directive sets a specifically named set of widgets to a
12588 given style, overriding any style set for the given widget class.
12589 These widgets are registered inside the application using the
12590 gtk_widget_set_name() call. This allows you to specify the attributes of a
12591 widget on a per widget basis, rather than setting the attributes of an
12592 entire widget class. I urge you to document any of these special widgets so
12593 users may customize them.
12595 When the keyword <tt>parent</> is used as an attribute, the widget will take on
12596 the attributes of its parent in the application.
12598 When defining a style, you may assign the attributes of a previously defined
12599 style to this new one.
12602 style "main_button" = "button"
12604 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
12605 bg[PRELIGHT] = { 0.75, 0, 0 }
12609 This example takes the "button" style, and creates a new "main_button" style
12610 simply by changing the font and prelight background color of the "button"
12613 Of course, many of these attributes don't apply to all widgets. It's a
12614 simple matter of common sense really. Anything that could apply, should.
12616 <!-- ----------------------------------------------------------------- -->
12617 <sect1>Example rc file
12621 # pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
12623 pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
12625 # style <name> [= <name>]
12630 # widget <widget_set> style <style_name>
12631 # widget_class <widget_class_set> style <style_name>
12634 # Here is a list of all the possible states. Note that some do not apply to
12637 # NORMAL - The normal state of a widget, without the mouse over top of
12638 # it, and not being pressed, etc.
12640 # PRELIGHT - When the mouse is over top of the widget, colors defined
12641 # using this state will be in effect.
12643 # ACTIVE - When the widget is pressed or clicked it will be active, and
12644 # the attributes assigned by this tag will be in effect.
12646 # INSENSITIVE - When a widget is set insensitive, and cannot be
12647 # activated, it will take these attributes.
12649 # SELECTED - When an object is selected, it takes these attributes.
12651 # Given these states, we can set the attributes of the widgets in each of
12652 # these states using the following directives.
12654 # fg - Sets the foreground color of a widget.
12655 # fg - Sets the background color of a widget.
12656 # bg_pixmap - Sets the background of a widget to a tiled pixmap.
12657 # font - Sets the font to be used with the given widget.
12660 # This sets a style called "button". The name is not really important, as
12661 # it is assigned to the actual widgets at the bottom of the file.
12665 #This sets the padding around the window to the pixmap specified.
12666 #bg_pixmap[<STATE>] = "<pixmap filename>"
12667 bg_pixmap[NORMAL] = "warning.xpm"
12672 #Sets the foreground color (font color) to red when in the "NORMAL"
12675 fg[NORMAL] = { 1.0, 0, 0 }
12677 #Sets the background pixmap of this widget to that of its parent.
12678 bg_pixmap[NORMAL] = "<parent>"
12683 # This shows all the possible states for a button. The only one that
12684 # doesn't apply is the SELECTED state.
12686 fg[PRELIGHT] = { 0, 1.0, 1.0 }
12687 bg[PRELIGHT] = { 0, 0, 1.0 }
12688 bg[ACTIVE] = { 1.0, 0, 0 }
12689 fg[ACTIVE] = { 0, 1.0, 0 }
12690 bg[NORMAL] = { 1.0, 1.0, 0 }
12691 fg[NORMAL] = { .99, 0, .99 }
12692 bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
12693 fg[INSENSITIVE] = { 1.0, 0, 1.0 }
12696 # In this example, we inherit the attributes of the "button" style and then
12697 # override the font and background color when prelit to create a new
12698 # "main_button" style.
12700 style "main_button" = "button"
12702 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
12703 bg[PRELIGHT] = { 0.75, 0, 0 }
12706 style "toggle_button" = "button"
12708 fg[NORMAL] = { 1.0, 0, 0 }
12709 fg[ACTIVE] = { 1.0, 0, 0 }
12711 # This sets the background pixmap of the toggle_button to that of its
12712 # parent widget (as defined in the application).
12713 bg_pixmap[NORMAL] = "<parent>"
12718 bg_pixmap[NORMAL] = "marble.xpm"
12719 fg[NORMAL] = { 1.0, 1.0, 1.0 }
12724 font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
12727 # pixmap_path "~/.pixmaps"
12729 # These set the widget types to use the styles defined above.
12730 # The widget types are listed in the class hierarchy, but could probably be
12731 # just listed in this document for the users reference.
12733 widget_class "GtkWindow" style "window"
12734 widget_class "GtkDialog" style "window"
12735 widget_class "GtkFileSelection" style "window"
12736 widget_class "*Gtk*Scale" style "scale"
12737 widget_class "*GtkCheckButton*" style "toggle_button"
12738 widget_class "*GtkRadioButton*" style "toggle_button"
12739 widget_class "*GtkButton*" style "button"
12740 widget_class "*Ruler" style "ruler"
12741 widget_class "*GtkText" style "text"
12743 # This sets all the buttons that are children of the "main window" to
12744 # the main_button style. These must be documented to be taken advantage of.
12745 widget "main window.*GtkButton*" style "main_button"
12748 <!-- ***************************************************************** -->
12749 <sect>Writing Your Own Widgets
12750 <!-- ***************************************************************** -->
12752 <!-- ----------------------------------------------------------------- -->
12755 Although the GTK distribution comes with many types of widgets that
12756 should cover most basic needs, there may come a time when you need to
12757 create your own new widget type. Since GTK uses widget inheritance
12758 extensively, and there is already a widget that is close to what you want,
12759 it is often possible to make a useful new widget type in
12760 just a few lines of code. But before starting work on a new widget, check
12761 around first to make sure that someone has not already written
12762 it. This will prevent duplication of effort and keep the number of
12763 GTK widgets out there to a minimum, which will help keep both the code
12764 and the interface of different applications consistent. As a flip side
12765 to this, once you finish your widget, announce it to the world so
12766 other people can benefit. The best place to do this is probably the
12769 Complete sources for the example widgets are available at the place you
12770 got this tutorial, or from:
12772 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
12773 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
12776 <!-- ----------------------------------------------------------------- -->
12777 <sect1> The Anatomy Of A Widget
12779 In order to create a new widget, it is important to have an
12780 understanding of how GTK objects work. This section is just meant as a
12781 brief overview. See the reference documentation for the details.
12783 GTK widgets are implemented in an object oriented fashion. However,
12784 they are implemented in standard C. This greatly improves portability
12785 and stability over using current generation C++ compilers; however,
12786 it does mean that the widget writer has to pay attention to some of
12787 the implementation details. The information common to all instances of
12788 one class of widgets (e.g., to all Button widgets) is stored in the
12789 <em>class structure</em>. There is only one copy of this in
12790 which is stored information about the class's signals
12791 (which act like virtual functions in C). To support inheritance, the
12792 first field in the class structure must be a copy of the parent's
12793 class structure. The declaration of the class structure of GtkButtton
12797 struct _GtkButtonClass
12799 GtkContainerClass parent_class;
12801 void (* pressed) (GtkButton *button);
12802 void (* released) (GtkButton *button);
12803 void (* clicked) (GtkButton *button);
12804 void (* enter) (GtkButton *button);
12805 void (* leave) (GtkButton *button);
12809 When a button is treated as a container (for instance, when it is
12810 resized), its class structure can be cast to GtkContainerClass, and
12811 the relevant fields used to handle the signals.
12813 There is also a structure for each widget that is created on a
12814 per-instance basis. This structure has fields to store information that
12815 is different for each instance of the widget. We'll call this
12816 structure the <em>object structure</em>. For the Button class, it looks
12822 GtkContainer container;
12826 guint in_button : 1;
12827 guint button_down : 1;
12831 Note that, similar to the class structure, the first field is the
12832 object structure of the parent class, so that this structure can be
12833 cast to the parent class' object structure as needed.
12835 <!-- ----------------------------------------------------------------- -->
12836 <sect1> Creating a Composite widget
12838 <!-- ----------------------------------------------------------------- -->
12839 <sect2> Introduction
12841 One type of widget that you may be interested in creating is a
12842 widget that is merely an aggregate of other GTK widgets. This type of
12843 widget does nothing that couldn't be done without creating new
12844 widgets, but provides a convenient way of packaging user interface
12845 elements for reuse. The FileSelection and ColorSelection widgets in
12846 the standard distribution are examples of this type of widget.
12848 The example widget that we'll create in this section is the Tictactoe
12849 widget, a 3x3 array of toggle buttons which triggers a signal when all
12850 three buttons in a row, column, or on one of the diagonals are
12853 <!-- ----------------------------------------------------------------- -->
12854 <sect2> Choosing a parent class
12856 The parent class for a composite widget is typically the container
12857 class that holds all of the elements of the composite widget. For
12858 example, the parent class of the FileSelection widget is the
12859 Dialog class. Since our buttons will be arranged in a table, it
12860 might seem natural to make our parent class the Table
12861 class. Unfortunately, this turns out not to work. The creation of a
12862 widget is divided among two functions - a <tt/WIDGETNAME_new()/
12863 function that the user calls, and a <tt/WIDGETNAME_init()/ function
12864 which does the basic work of initializing the widget which is
12865 independent of the arguments passed to the <tt/_new()/
12866 function. Descendant widgets only call the <tt/_init/ function of
12867 their parent widget. But this division of labor doesn't work well for
12868 tables, which when created need to know the number of rows and
12869 columns in the table. Unless we want to duplicate most of the
12870 functionality of <tt/gtk_table_new()/ in our Tictactoe widget, we had
12871 best avoid deriving it from Table. For that reason, we derive it
12872 from VBox instead, and stick our table inside the VBox.
12874 <!-- ----------------------------------------------------------------- -->
12875 <sect2> The header file
12877 Each widget class has a header file which declares the object and
12878 class structures for that widget, along with public functions.
12879 A couple of features are worth pointing out. To prevent duplicate
12880 definitions, we wrap the entire header file in:
12883 #ifndef __TICTACTOE_H__
12884 #define __TICTACTOE_H__
12888 #endif /* __TICTACTOE_H__ */
12891 And to keep C++ programs that include the header file happy, in:
12896 #endif /* __cplusplus */
12902 #endif /* __cplusplus */
12905 Along with the functions and structures, we declare three standard
12906 macros in our header file, <tt/TICTACTOE(obj)/,
12907 <tt/TICTACTOE_CLASS(klass)/, and <tt/IS_TICTACTOE(obj)/, which cast a
12908 pointer into a pointer to the object or class structure, and check
12909 if an object is a Tictactoe widget respectively.
12911 Here is the complete header file:
12916 #ifndef __TICTACTOE_H__
12917 #define __TICTACTOE_H__
12919 #include <gdk/gdk.h>
12920 #include <gtk/gtkvbox.h>
12924 #endif /* __cplusplus */
12926 #define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
12927 #define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
12928 #define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
12931 typedef struct _Tictactoe Tictactoe;
12932 typedef struct _TictactoeClass TictactoeClass;
12938 GtkWidget *buttons[3][3];
12941 struct _TictactoeClass
12943 GtkVBoxClass parent_class;
12945 void (* tictactoe) (Tictactoe *ttt);
12948 guint tictactoe_get_type (void);
12949 GtkWidget* tictactoe_new (void);
12950 void tictactoe_clear (Tictactoe *ttt);
12954 #endif /* __cplusplus */
12956 #endif /* __TICTACTOE_H__ */
12960 <!-- ----------------------------------------------------------------- -->
12961 <sect2> The <tt/_get_type()/ function.
12963 We now continue on to the implementation of our widget. A core
12964 function for every widget is the function
12965 <tt/WIDGETNAME_get_type()/. This function, when first called, tells
12966 GTK about the widget class, and gets an ID that uniquely identifies
12967 the widget class. Upon subsequent calls, it just returns the ID.
12971 tictactoe_get_type ()
12973 static guint ttt_type = 0;
12977 GtkTypeInfo ttt_info =
12980 sizeof (Tictactoe),
12981 sizeof (TictactoeClass),
12982 (GtkClassInitFunc) tictactoe_class_init,
12983 (GtkObjectInitFunc) tictactoe_init,
12984 (GtkArgSetFunc) NULL,
12985 (GtkArgGetFunc) NULL
12988 ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
12995 The GtkTypeInfo structure has the following definition:
12998 struct _GtkTypeInfo
13003 GtkClassInitFunc class_init_func;
13004 GtkObjectInitFunc object_init_func;
13005 GtkArgSetFunc arg_set_func;
13006 GtkArgGetFunc arg_get_func;
13010 The fields of this structure are pretty self-explanatory. We'll ignore
13011 the <tt/arg_set_func/ and <tt/arg_get_func/ fields here: they have an important,
13013 unimplemented, role in allowing widget options to be conveniently set
13014 from interpreted languages. Once GTK has a correctly filled in copy of
13015 this structure, it knows how to create objects of a particular widget
13018 <!-- ----------------------------------------------------------------- -->
13019 <sect2> The <tt/_class_init()/ function
13021 The <tt/WIDGETNAME_class_init()/ function initializes the fields of
13022 the widget's class structure, and sets up any signals for the
13023 class. For our Tictactoe widget it looks like:
13032 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
13035 tictactoe_class_init (TictactoeClass *class)
13037 GtkObjectClass *object_class;
13039 object_class = (GtkObjectClass*) class;
13041 tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
13043 object_class->type,
13044 GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
13045 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
13048 gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
13050 class->tictactoe = NULL;
13054 Our widget has just one signal, the <tt/tictactoe/ signal that is
13055 invoked when a row, column, or diagonal is completely filled in. Not
13056 every composite widget needs signals, so if you are reading this for
13057 the first time, you may want to skip to the next section now, as
13058 things are going to get a bit complicated.
13063 gint gtk_signal_new( const gchar *name,
13064 GtkSignalRunType run_type,
13065 GtkType object_type,
13066 gint function_offset,
13067 GtkSignalMarshaller marshaller,
13068 GtkType return_val,
13073 Creates a new signal. The parameters are:
13076 <item> <tt/name/: The name of the signal.
13077 <item> <tt/run_type/: Whether the default handler runs before or after
13078 user handlers. Usually this will be <tt/GTK_RUN_FIRST/, or <tt/GTK_RUN_LAST/,
13079 although there are other possibilities.
13080 <item> <tt/object_type/: The ID of the object that this signal applies
13081 to. (It will also apply to that objects descendants.)
13082 <item> <tt/function_offset/: The offset within the class structure of
13083 a pointer to the default handler.
13084 <item> <tt/marshaller/: A function that is used to invoke the signal
13085 handler. For signal handlers that have no arguments other than the
13086 object that emitted the signal and user data, we can use the
13087 pre-supplied marshaller function <tt/gtk_signal_default_marshaller/.
13088 <item> <tt/return_val/: The type of the return val.
13089 <item> <tt/nparams/: The number of parameters of the signal handler
13090 (other than the two default ones mentioned above)
13091 <item> <tt/.../: The types of the parameters.
13094 When specifying types, the <tt/GtkType/ enumeration is used:
13119 /* it'd be great if the next two could be removed eventually */
13121 GTK_TYPE_C_CALLBACK,
13125 } GtkFundamentalType;
13128 <tt/gtk_signal_new()/ returns a unique integer identifier for the
13129 signal, that we store in the <tt/tictactoe_signals/ array, which we
13130 index using an enumeration. (Conventionally, the enumeration elements
13131 are the signal name, uppercased, but here there would be a conflict
13132 with the <tt/TICTACTOE()/ macro, so we called it <tt/TICTACTOE_SIGNAL/
13135 After creating our signals, we need to tell GTK to associate our
13136 signals with the Tictactoe class. We do that by calling
13137 <tt/gtk_object_class_add_signals()/. We then set the pointer which
13138 points to the default handler for the "tictactoe" signal to NULL,
13139 indicating that there is no default action.
13141 <!-- ----------------------------------------------------------------- -->
13142 <sect2> The <tt/_init()/ function.
13144 Each widget class also needs a function to initialize the object
13145 structure. Usually, this function has the fairly limited role of
13146 setting the fields of the structure to default values. For composite
13147 widgets, however, this function also creates the component widgets.
13151 tictactoe_init (Tictactoe *ttt)
13156 table = gtk_table_new (3, 3, TRUE);
13157 gtk_container_add (GTK_CONTAINER(ttt), table);
13158 gtk_widget_show (table);
13163 ttt->buttons[i][j] = gtk_toggle_button_new ();
13164 gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
13166 gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
13167 GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
13168 gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
13169 gtk_widget_show (ttt->buttons[i][j]);
13174 <!-- ----------------------------------------------------------------- -->
13175 <sect2> And the rest...
13177 There is one more function that every widget (except for base widget
13178 types like Bin that cannot be instantiated) needs to have - the
13179 function that the user calls to create an object of that type. This is
13180 conventionally called <tt/WIDGETNAME_new()/. In some
13181 widgets, though not for the Tictactoe widgets, this function takes
13182 arguments, and does some setup based on the arguments. The other two
13183 functions are specific to the Tictactoe widget.
13185 <tt/tictactoe_clear()/ is a public function that resets all the
13186 buttons in the widget to the up position. Note the use of
13187 <tt/gtk_signal_handler_block_by_data()/ to keep our signal handler for
13188 button toggles from being triggered unnecessarily.
13190 <tt/tictactoe_toggle()/ is the signal handler that is invoked when the
13191 user clicks on a button. It checks to see if there are any winning
13192 combinations that involve the toggled button, and if so, emits
13193 the "tictactoe" signal.
13199 return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
13203 tictactoe_clear (Tictactoe *ttt)
13210 gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
13211 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
13213 gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
13218 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
13222 static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
13223 { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
13224 { 0, 1, 2 }, { 0, 1, 2 } };
13225 static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
13226 { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
13227 { 0, 1, 2 }, { 2, 1, 0 } };
13229 int success, found;
13231 for (k=0; k<8; k++)
13238 success = success &&
13239 GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
13241 ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
13244 if (success && found)
13246 gtk_signal_emit (GTK_OBJECT (ttt),
13247 tictactoe_signals[TICTACTOE_SIGNAL]);
13254 And finally, an example program using our Tictactoe widget:
13257 #include <gtk/gtk.h>
13258 #include "tictactoe.h"
13260 /* Invoked when a row, column or diagonal is completed */
13262 win (GtkWidget *widget, gpointer data)
13264 g_print ("Yay!\n");
13265 tictactoe_clear (TICTACTOE (widget));
13269 main (int argc, char *argv[])
13274 gtk_init (&argc, &argv);
13276 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
13278 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
13280 gtk_signal_connect (GTK_OBJECT (window), "destroy",
13281 GTK_SIGNAL_FUNC (gtk_exit), NULL);
13283 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
13285 /* Create a new Tictactoe widget */
13286 ttt = tictactoe_new ();
13287 gtk_container_add (GTK_CONTAINER (window), ttt);
13288 gtk_widget_show (ttt);
13290 /* And attach to its "tictactoe" signal */
13291 gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
13292 GTK_SIGNAL_FUNC (win), NULL);
13294 gtk_widget_show (window);
13303 <!-- ----------------------------------------------------------------- -->
13304 <sect1> Creating a widget from scratch.
13306 <!-- ----------------------------------------------------------------- -->
13307 <sect2> Introduction
13309 In this section, we'll learn more about how widgets display themselves
13310 on the screen and interact with events. As an example of this, we'll
13311 create an analog dial widget with a pointer that the user can drag to
13314 <!-- ----------------------------------------------------------------- -->
13315 <sect2> Displaying a widget on the screen
13317 There are several steps that are involved in displaying on the screen.
13318 After the widget is created with a call to <tt/WIDGETNAME_new()/,
13319 several more functions are needed:
13322 <item> <tt/WIDGETNAME_realize()/ is responsible for creating an X
13323 window for the widget if it has one.
13324 <item> <tt/WIDGETNAME_map()/ is invoked after the user calls
13325 <tt/gtk_widget_show()/. It is responsible for making sure the widget
13326 is actually drawn on the screen (<em/mapped/). For a container class,
13327 it must also make calls to <tt/map()/> functions of any child widgets.
13328 <item> <tt/WIDGETNAME_draw()/ is invoked when <tt/gtk_widget_draw()/
13329 is called for the widget or one of its ancestors. It makes the actual
13330 calls to the drawing functions to draw the widget on the screen. For
13331 container widgets, this function must make calls to
13332 <tt/gtk_widget_draw()/ for its child widgets.
13333 <item> <tt/WIDGETNAME_expose()/ is a handler for expose events for the
13334 widget. It makes the necessary calls to the drawing functions to draw
13335 the exposed portion on the screen. For container widgets, this
13336 function must generate expose events for its child widgets which don't
13337 have their own windows. (If they have their own windows, then X will
13338 generate the necessary expose events.)
13341 You might notice that the last two functions are quite similar - each
13342 is responsible for drawing the widget on the screen. In fact many
13343 types of widgets don't really care about the difference between the
13344 two. The default <tt/draw()/ function in the widget class simply
13345 generates a synthetic expose event for the redrawn area. However, some
13346 types of widgets can save work by distinguishing between the two
13347 functions. For instance, if a widget has multiple X windows, then
13348 since expose events identify the exposed window, it can redraw only
13349 the affected window, which is not possible for calls to <tt/draw()/.
13351 Container widgets, even if they don't care about the difference for
13352 themselves, can't simply use the default <tt/draw()/ function because
13353 their child widgets might care about the difference. However,
13354 it would be wasteful to duplicate the drawing code between the two
13355 functions. The convention is that such widgets have a function called
13356 <tt/WIDGETNAME_paint()/ that does the actual work of drawing the
13357 widget, that is then called by the <tt/draw()/ and <tt/expose()/
13360 In our example approach, since the dial widget is not a container
13361 widget, and only has a single window, we can take the simplest
13362 approach and use the default <tt/draw()/ function and only implement
13363 an <tt/expose()/ function.
13365 <!-- ----------------------------------------------------------------- -->
13366 <sect2> The origins of the Dial Widget
13368 Just as all land animals are just variants on the first amphibian that
13369 crawled up out of the mud, GTK widgets tend to start off as variants
13370 of some other, previously written widget. Thus, although this section
13371 is entitled "Creating a Widget from Scratch", the Dial widget really
13372 began with the source code for the Range widget. This was picked as a
13373 starting point because it would be nice if our Dial had the same
13374 interface as the Scale widgets which are just specialized descendants
13375 of the Range widget. So, though the source code is presented below in
13376 finished form, it should not be implied that it was written, <em>ab
13377 initio</em> in this fashion. Also, if you aren't yet familiar with
13378 how scale widgets work from the application writer's point of view, it
13379 would be a good idea to look them over before continuing.
13381 <!-- ----------------------------------------------------------------- -->
13384 Quite a bit of our widget should look pretty familiar from the
13385 Tictactoe widget. First, we have a header file:
13388 /* GTK - The GTK+ Toolkit
13389 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
13391 * This library is free software; you can redistribute it and/or
13392 * modify it under the terms of the GNU Library General Public
13393 * License as published by the Free Software Foundation; either
13394 * version 2 of the License, or (at your option) any later version.
13396 * This library is distributed in the hope that it will be useful,
13397 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13398 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13399 * Library General Public License for more details.
13401 * You should have received a copy of the GNU Library General Public
13402 * License along with this library; if not, write to the Free
13403 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
13406 #ifndef __GTK_DIAL_H__
13407 #define __GTK_DIAL_H__
13409 #include <gdk/gdk.h>
13410 #include <gtk/gtkadjustment.h>
13411 #include <gtk/gtkwidget.h>
13416 #endif /* __cplusplus */
13419 #define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
13420 #define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
13421 #define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
13424 typedef struct _GtkDial GtkDial;
13425 typedef struct _GtkDialClass GtkDialClass;
13431 /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
13434 /* Button currently pressed or 0 if none */
13437 /* Dimensions of dial components */
13439 gint pointer_width;
13441 /* ID of update timer, or 0 if none */
13444 /* Current angle */
13447 /* Old values from adjustment stored so we know when something changes */
13452 /* The adjustment object that stores the data for this dial */
13453 GtkAdjustment *adjustment;
13456 struct _GtkDialClass
13458 GtkWidgetClass parent_class;
13462 GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
13463 guint gtk_dial_get_type (void);
13464 GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
13465 void gtk_dial_set_update_policy (GtkDial *dial,
13466 GtkUpdateType policy);
13468 void gtk_dial_set_adjustment (GtkDial *dial,
13469 GtkAdjustment *adjustment);
13472 #endif /* __cplusplus */
13475 #endif /* __GTK_DIAL_H__ */
13478 Since there is quite a bit more going on in this widget than the last
13479 one, we have more fields in the data structure, but otherwise things
13480 are pretty similar.
13482 Next, after including header files and declaring a few constants,
13483 we have some functions to provide information about the widget
13489 #include <gtk/gtkmain.h>
13490 #include <gtk/gtksignal.h>
13492 #include "gtkdial.h"
13494 #define SCROLL_DELAY_LENGTH 300
13495 #define DIAL_DEFAULT_SIZE 100
13497 /* Forward declarations */
13499 [ omitted to save space ]
13503 static GtkWidgetClass *parent_class = NULL;
13506 gtk_dial_get_type ()
13508 static guint dial_type = 0;
13512 GtkTypeInfo dial_info =
13516 sizeof (GtkDialClass),
13517 (GtkClassInitFunc) gtk_dial_class_init,
13518 (GtkObjectInitFunc) gtk_dial_init,
13519 (GtkArgSetFunc) NULL,
13520 (GtkArgGetFunc) NULL,
13523 dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info);
13530 gtk_dial_class_init (GtkDialClass *class)
13532 GtkObjectClass *object_class;
13533 GtkWidgetClass *widget_class;
13535 object_class = (GtkObjectClass*) class;
13536 widget_class = (GtkWidgetClass*) class;
13538 parent_class = gtk_type_class (gtk_widget_get_type ());
13540 object_class->destroy = gtk_dial_destroy;
13542 widget_class->realize = gtk_dial_realize;
13543 widget_class->expose_event = gtk_dial_expose;
13544 widget_class->size_request = gtk_dial_size_request;
13545 widget_class->size_allocate = gtk_dial_size_allocate;
13546 widget_class->button_press_event = gtk_dial_button_press;
13547 widget_class->button_release_event = gtk_dial_button_release;
13548 widget_class->motion_notify_event = gtk_dial_motion_notify;
13552 gtk_dial_init (GtkDial *dial)
13555 dial->policy = GTK_UPDATE_CONTINUOUS;
13558 dial->pointer_width = 0;
13560 dial->old_value = 0.0;
13561 dial->old_lower = 0.0;
13562 dial->old_upper = 0.0;
13563 dial->adjustment = NULL;
13567 gtk_dial_new (GtkAdjustment *adjustment)
13571 dial = gtk_type_new (gtk_dial_get_type ());
13574 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
13576 gtk_dial_set_adjustment (dial, adjustment);
13578 return GTK_WIDGET (dial);
13582 gtk_dial_destroy (GtkObject *object)
13586 g_return_if_fail (object != NULL);
13587 g_return_if_fail (GTK_IS_DIAL (object));
13589 dial = GTK_DIAL (object);
13591 if (dial->adjustment)
13592 gtk_object_unref (GTK_OBJECT (dial->adjustment));
13594 if (GTK_OBJECT_CLASS (parent_class)->destroy)
13595 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
13599 Note that this <tt/init()/ function does less than for the Tictactoe
13600 widget, since this is not a composite widget, and the <tt/new()/
13601 function does more, since it now has an argument. Also, note that when
13602 we store a pointer to the Adjustment object, we increment its
13603 reference count, (and correspondingly decrement it when we no longer
13604 use it) so that GTK can keep track of when it can be safely destroyed.
13607 Also, there are a few function to manipulate the widget's options:
13611 gtk_dial_get_adjustment (GtkDial *dial)
13613 g_return_val_if_fail (dial != NULL, NULL);
13614 g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
13616 return dial->adjustment;
13620 gtk_dial_set_update_policy (GtkDial *dial,
13621 GtkUpdateType policy)
13623 g_return_if_fail (dial != NULL);
13624 g_return_if_fail (GTK_IS_DIAL (dial));
13626 dial->policy = policy;
13630 gtk_dial_set_adjustment (GtkDial *dial,
13631 GtkAdjustment *adjustment)
13633 g_return_if_fail (dial != NULL);
13634 g_return_if_fail (GTK_IS_DIAL (dial));
13636 if (dial->adjustment)
13638 gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
13639 gtk_object_unref (GTK_OBJECT (dial->adjustment));
13642 dial->adjustment = adjustment;
13643 gtk_object_ref (GTK_OBJECT (dial->adjustment));
13645 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
13646 (GtkSignalFunc) gtk_dial_adjustment_changed,
13648 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
13649 (GtkSignalFunc) gtk_dial_adjustment_value_changed,
13652 dial->old_value = adjustment->value;
13653 dial->old_lower = adjustment->lower;
13654 dial->old_upper = adjustment->upper;
13656 gtk_dial_update (dial);
13660 <sect2> <tt/gtk_dial_realize()/
13663 Now we come to some new types of functions. First, we have a function
13664 that does the work of creating the X window. Notice that a mask is
13665 passed to the function <tt/gdk_window_new()/ which specifies which fields of
13666 the GdkWindowAttr structure actually have data in them (the remaining
13667 fields will be given default values). Also worth noting is the way the
13668 event mask of the widget is created. We call
13669 <tt/gtk_widget_get_events()/ to retrieve the event mask that the user
13670 has specified for this widget (with <tt/gtk_widget_set_events()/), and
13671 add the events that we are interested in ourselves.
13674 After creating the window, we set its style and background, and put a
13675 pointer to the widget in the user data field of the GdkWindow. This
13676 last step allows GTK to dispatch events for this window to the correct
13681 gtk_dial_realize (GtkWidget *widget)
13684 GdkWindowAttr attributes;
13685 gint attributes_mask;
13687 g_return_if_fail (widget != NULL);
13688 g_return_if_fail (GTK_IS_DIAL (widget));
13690 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
13691 dial = GTK_DIAL (widget);
13693 attributes.x = widget->allocation.x;
13694 attributes.y = widget->allocation.y;
13695 attributes.width = widget->allocation.width;
13696 attributes.height = widget->allocation.height;
13697 attributes.wclass = GDK_INPUT_OUTPUT;
13698 attributes.window_type = GDK_WINDOW_CHILD;
13699 attributes.event_mask = gtk_widget_get_events (widget) |
13700 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
13701 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
13702 GDK_POINTER_MOTION_HINT_MASK;
13703 attributes.visual = gtk_widget_get_visual (widget);
13704 attributes.colormap = gtk_widget_get_colormap (widget);
13706 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
13707 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
13709 widget->style = gtk_style_attach (widget->style, widget->window);
13711 gdk_window_set_user_data (widget->window, widget);
13713 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
13717 <sect2> Size negotiation
13720 Before the first time that the window containing a widget is
13721 displayed, and whenever the layout of the window changes, GTK asks
13722 each child widget for its desired size. This request is handled by the
13723 function <tt/gtk_dial_size_request()/. Since our widget isn't a
13724 container widget, and has no real constraints on its size, we just
13725 return a reasonable default value.
13729 gtk_dial_size_request (GtkWidget *widget,
13730 GtkRequisition *requisition)
13732 requisition->width = DIAL_DEFAULT_SIZE;
13733 requisition->height = DIAL_DEFAULT_SIZE;
13738 After all the widgets have requested an ideal size, the layout of the
13739 window is computed and each child widget is notified of its actual
13740 size. Usually, this will be at least as large as the requested size,
13741 but if for instance the user has resized the window, it may
13742 occasionally be smaller than the requested size. The size notification
13743 is handled by the function <tt/gtk_dial_size_allocate()/. Notice that
13744 as well as computing the sizes of some component pieces for future
13745 use, this routine also does the grunt work of moving the widget's X
13746 window into the new position and size.
13750 gtk_dial_size_allocate (GtkWidget *widget,
13751 GtkAllocation *allocation)
13755 g_return_if_fail (widget != NULL);
13756 g_return_if_fail (GTK_IS_DIAL (widget));
13757 g_return_if_fail (allocation != NULL);
13759 widget->allocation = *allocation;
13760 if (GTK_WIDGET_REALIZED (widget))
13762 dial = GTK_DIAL (widget);
13764 gdk_window_move_resize (widget->window,
13765 allocation->x, allocation->y,
13766 allocation->width, allocation->height);
13768 dial->radius = MAX(allocation->width,allocation->height) * 0.45;
13769 dial->pointer_width = dial->radius / 5;
13774 <!-- ----------------------------------------------------------------- -->
13775 <sect2> <tt/gtk_dial_expose()/
13778 As mentioned above, all the drawing of this widget is done in the
13779 handler for expose events. There's not much to remark on here except
13780 the use of the function <tt/gtk_draw_polygon/ to draw the pointer with
13781 three dimensional shading according to the colors stored in the
13786 gtk_dial_expose (GtkWidget *widget,
13787 GdkEventExpose *event)
13790 GdkPoint points[3];
13797 g_return_val_if_fail (widget != NULL, FALSE);
13798 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13799 g_return_val_if_fail (event != NULL, FALSE);
13801 if (event->count > 0)
13804 dial = GTK_DIAL (widget);
13806 gdk_window_clear_area (widget->window,
13808 widget->allocation.width,
13809 widget->allocation.height);
13811 xc = widget->allocation.width/2;
13812 yc = widget->allocation.height/2;
13816 for (i=0; i<25; i++)
13818 theta = (i*M_PI/18. - M_PI/6.);
13822 tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
13824 gdk_draw_line (widget->window,
13825 widget->style->fg_gc[widget->state],
13826 xc + c*(dial->radius - tick_length),
13827 yc - s*(dial->radius - tick_length),
13828 xc + c*dial->radius,
13829 yc - s*dial->radius);
13834 s = sin(dial->angle);
13835 c = cos(dial->angle);
13838 points[0].x = xc + s*dial->pointer_width/2;
13839 points[0].y = yc + c*dial->pointer_width/2;
13840 points[1].x = xc + c*dial->radius;
13841 points[1].y = yc - s*dial->radius;
13842 points[2].x = xc - s*dial->pointer_width/2;
13843 points[2].y = yc - c*dial->pointer_width/2;
13845 gtk_draw_polygon (widget->style,
13856 <!-- ----------------------------------------------------------------- -->
13857 <sect2> Event handling
13859 The rest of the widget's code handles various types of events, and
13860 isn't too different from what would be found in many GTK
13861 applications. Two types of events can occur - either the user can
13862 click on the widget with the mouse and drag to move the pointer, or
13863 the value of the Adjustment object can change due to some external
13866 When the user clicks on the widget, we check to see if the click was
13867 appropriately near the pointer, and if so, store the button that the
13868 user clicked with in the <tt/button/ field of the widget
13869 structure, and grab all mouse events with a call to
13870 <tt/gtk_grab_add()/. Subsequent motion of the mouse causes the
13871 value of the control to be recomputed (by the function
13872 <tt/gtk_dial_update_mouse/). Depending on the policy that has been
13873 set, "value_changed" events are either generated instantly
13874 (<tt/GTK_UPDATE_CONTINUOUS/), after a delay in a timer added with
13875 <tt/gtk_timeout_add()/ (<tt/GTK_UPDATE_DELAYED/), or only when the
13876 button is released (<tt/GTK_UPDATE_DISCONTINUOUS/).
13880 gtk_dial_button_press (GtkWidget *widget,
13881 GdkEventButton *event)
13887 double d_perpendicular;
13889 g_return_val_if_fail (widget != NULL, FALSE);
13890 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13891 g_return_val_if_fail (event != NULL, FALSE);
13893 dial = GTK_DIAL (widget);
13895 /* Determine if button press was within pointer region - we
13896 do this by computing the parallel and perpendicular distance of
13897 the point where the mouse was pressed from the line passing through
13900 dx = event->x - widget->allocation.width / 2;
13901 dy = widget->allocation.height / 2 - event->y;
13903 s = sin(dial->angle);
13904 c = cos(dial->angle);
13906 d_parallel = s*dy + c*dx;
13907 d_perpendicular = fabs(s*dx - c*dy);
13909 if (!dial->button &&
13910 (d_perpendicular < dial->pointer_width/2) &&
13911 (d_parallel > - dial->pointer_width))
13913 gtk_grab_add (widget);
13915 dial->button = event->button;
13917 gtk_dial_update_mouse (dial, event->x, event->y);
13924 gtk_dial_button_release (GtkWidget *widget,
13925 GdkEventButton *event)
13929 g_return_val_if_fail (widget != NULL, FALSE);
13930 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13931 g_return_val_if_fail (event != NULL, FALSE);
13933 dial = GTK_DIAL (widget);
13935 if (dial->button == event->button)
13937 gtk_grab_remove (widget);
13941 if (dial->policy == GTK_UPDATE_DELAYED)
13942 gtk_timeout_remove (dial->timer);
13944 if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
13945 (dial->old_value != dial->adjustment->value))
13946 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13953 gtk_dial_motion_notify (GtkWidget *widget,
13954 GdkEventMotion *event)
13957 GdkModifierType mods;
13960 g_return_val_if_fail (widget != NULL, FALSE);
13961 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13962 g_return_val_if_fail (event != NULL, FALSE);
13964 dial = GTK_DIAL (widget);
13966 if (dial->button != 0)
13971 if (event->is_hint || (event->window != widget->window))
13972 gdk_window_get_pointer (widget->window, &x, &y, &mods);
13974 switch (dial->button)
13977 mask = GDK_BUTTON1_MASK;
13980 mask = GDK_BUTTON2_MASK;
13983 mask = GDK_BUTTON3_MASK;
13991 gtk_dial_update_mouse (dial, x,y);
13998 gtk_dial_timer (GtkDial *dial)
14000 g_return_val_if_fail (dial != NULL, FALSE);
14001 g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
14003 if (dial->policy == GTK_UPDATE_DELAYED)
14004 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
14010 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
14015 g_return_if_fail (dial != NULL);
14016 g_return_if_fail (GTK_IS_DIAL (dial));
14018 xc = GTK_WIDGET(dial)->allocation.width / 2;
14019 yc = GTK_WIDGET(dial)->allocation.height / 2;
14021 old_value = dial->adjustment->value;
14022 dial->angle = atan2(yc-y, x-xc);
14024 if (dial->angle < -M_PI/2.)
14025 dial->angle += 2*M_PI;
14027 if (dial->angle < -M_PI/6)
14028 dial->angle = -M_PI/6;
14030 if (dial->angle > 7.*M_PI/6.)
14031 dial->angle = 7.*M_PI/6.;
14033 dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
14034 (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
14036 if (dial->adjustment->value != old_value)
14038 if (dial->policy == GTK_UPDATE_CONTINUOUS)
14040 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
14044 gtk_widget_draw (GTK_WIDGET(dial), NULL);
14046 if (dial->policy == GTK_UPDATE_DELAYED)
14049 gtk_timeout_remove (dial->timer);
14051 dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
14052 (GtkFunction) gtk_dial_timer,
14060 Changes to the Adjustment by external means are communicated to our
14061 widget by the "changed" and "value_changed" signals. The handlers
14062 for these functions call <tt/gtk_dial_update()/ to validate the
14063 arguments, compute the new pointer angle, and redraw the widget (by
14064 calling <tt/gtk_widget_draw()/).
14068 gtk_dial_update (GtkDial *dial)
14072 g_return_if_fail (dial != NULL);
14073 g_return_if_fail (GTK_IS_DIAL (dial));
14075 new_value = dial->adjustment->value;
14077 if (new_value < dial->adjustment->lower)
14078 new_value = dial->adjustment->lower;
14080 if (new_value > dial->adjustment->upper)
14081 new_value = dial->adjustment->upper;
14083 if (new_value != dial->adjustment->value)
14085 dial->adjustment->value = new_value;
14086 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
14089 dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
14090 (dial->adjustment->upper - dial->adjustment->lower);
14092 gtk_widget_draw (GTK_WIDGET(dial), NULL);
14096 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
14101 g_return_if_fail (adjustment != NULL);
14102 g_return_if_fail (data != NULL);
14104 dial = GTK_DIAL (data);
14106 if ((dial->old_value != adjustment->value) ||
14107 (dial->old_lower != adjustment->lower) ||
14108 (dial->old_upper != adjustment->upper))
14110 gtk_dial_update (dial);
14112 dial->old_value = adjustment->value;
14113 dial->old_lower = adjustment->lower;
14114 dial->old_upper = adjustment->upper;
14119 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
14124 g_return_if_fail (adjustment != NULL);
14125 g_return_if_fail (data != NULL);
14127 dial = GTK_DIAL (data);
14129 if (dial->old_value != adjustment->value)
14131 gtk_dial_update (dial);
14133 dial->old_value = adjustment->value;
14138 <!-- ----------------------------------------------------------------- -->
14139 <sect2> Possible Enhancements
14141 The Dial widget as we've described it so far runs about 670 lines of
14142 code. Although that might sound like a fair bit, we've really
14143 accomplished quite a bit with that much code, especially since much of
14144 that length is headers and boilerplate. However, there are quite a few
14145 more enhancements that could be made to this widget:
14148 <item> If you try this widget out, you'll find that there is some
14149 flashing as the pointer is dragged around. This is because the entire
14150 widget is erased every time the pointer is moved before being
14151 redrawn. Often, the best way to handle this problem is to draw to an
14152 offscreen pixmap, then copy the final results onto the screen in one
14153 step. (The ProgressBar widget draws itself in this fashion.)
14155 <item> The user should be able to use the up and down arrow keys to
14156 increase and decrease the value.
14158 <item> It would be nice if the widget had buttons to increase and
14159 decrease the value in small or large steps. Although it would be
14160 possible to use embedded Button widgets for this, we would also like
14161 the buttons to auto-repeat when held down, as the arrows on a
14162 scrollbar do. Most of the code to implement this type of behavior can
14163 be found in the Range widget.
14165 <item> The Dial widget could be made into a container widget with a
14166 single child widget positioned at the bottom between the buttons
14167 mentioned above. The user could then add their choice of a label or
14168 entry widget to display the current value of the dial.
14172 <!-- ----------------------------------------------------------------- -->
14173 <sect1> Learning More
14176 Only a small part of the many details involved in creating widgets
14177 could be described above. If you want to write your own widgets, the
14178 best source of examples is the GTK source itself. Ask yourself some
14179 questions about the widget you want to write: IS it a Container
14180 widget? Does it have its own window? Is it a modification of an
14181 existing widget? Then find a similar widget, and start making changes.
14184 <!-- ***************************************************************** -->
14185 <sect>Scribble, A Simple Example Drawing Program
14186 <!-- ***************************************************************** -->
14188 <!-- ----------------------------------------------------------------- -->
14191 In this section, we will build a simple drawing program. In the
14192 process, we will examine how to handle mouse events, how to draw in a
14193 window, and how to do drawing better by using a backing pixmap. After
14194 creating the simple drawing program, we will extend it by adding
14195 support for XInput devices, such as drawing tablets. GTK provides
14196 support routines which makes getting extended information, such as
14197 pressure and tilt, from such devices quite easy.
14199 <!-- ----------------------------------------------------------------- -->
14200 <sect1> Event Handling
14202 The GTK signals we have already discussed are for high-level actions,
14203 such as a menu item being selected. However, sometimes it is useful to
14204 learn about lower-level occurrences, such as the mouse being moved, or
14205 a key being pressed. There are also GTK signals corresponding to these
14206 low-level <em>events</em>. The handlers for these signals have an
14207 extra parameter which is a pointer to a structure containing
14208 information about the event. For instance, motion event handlers are
14209 passed a pointer to a GdkEventMotion structure which looks (in part)
14213 struct _GdkEventMotion
14226 <tt/type/ will be set to the event type, in this case
14227 <tt/GDK_MOTION_NOTIFY/, window is the window in which the event
14228 occurred. <tt/x/ and <tt/y/ give the coordinates of the event.
14229 <tt/state/ specifies the modifier state when the event
14230 occurred (that is, it specifies which modifier keys and mouse buttons
14231 were pressed). It is the bitwise OR of some of the following:
14249 As for other signals, to determine what happens when an event occurs
14250 we call <tt>gtk_signal_connect()</tt>. But we also need let GTK
14251 know which events we want to be notified about. To do this, we call
14255 void gtk_widget_set_events (GtkWidget *widget,
14259 The second field specifies the events we are interested in. It
14260 is the bitwise OR of constants that specify different types
14261 of events. For future reference the event types are:
14265 GDK_POINTER_MOTION_MASK
14266 GDK_POINTER_MOTION_HINT_MASK
14267 GDK_BUTTON_MOTION_MASK
14268 GDK_BUTTON1_MOTION_MASK
14269 GDK_BUTTON2_MOTION_MASK
14270 GDK_BUTTON3_MOTION_MASK
14271 GDK_BUTTON_PRESS_MASK
14272 GDK_BUTTON_RELEASE_MASK
14274 GDK_KEY_RELEASE_MASK
14275 GDK_ENTER_NOTIFY_MASK
14276 GDK_LEAVE_NOTIFY_MASK
14277 GDK_FOCUS_CHANGE_MASK
14279 GDK_PROPERTY_CHANGE_MASK
14280 GDK_PROXIMITY_IN_MASK
14281 GDK_PROXIMITY_OUT_MASK
14284 There are a few subtle points that have to be observed when calling
14285 <tt/gtk_widget_set_events()/. First, it must be called before the X window
14286 for a GTK widget is created. In practical terms, this means you
14287 should call it immediately after creating the widget. Second, the
14288 widget must have an associated X window. For efficiency, many widget
14289 types do not have their own window, but draw in their parent's window.
14312 To capture events for these widgets, you need to use an EventBox
14313 widget. See the section on the <ref id="sec_EventBox"
14314 name="EventBox"> widget for details.
14316 For our drawing program, we want to know when the mouse button is
14317 pressed and when the mouse is moved, so we specify
14318 <tt/GDK_POINTER_MOTION_MASK/ and <tt/GDK_BUTTON_PRESS_MASK/. We also
14319 want to know when we need to redraw our window, so we specify
14320 <tt/GDK_EXPOSURE_MASK/. Although we want to be notified via a
14321 Configure event when our window size changes, we don't have to specify
14322 the corresponding <tt/GDK_STRUCTURE_MASK/ flag, because it is
14323 automatically specified for all windows.
14325 It turns out, however, that there is a problem with just specifying
14326 <tt/GDK_POINTER_MOTION_MASK/. This will cause the server to add a new
14327 motion event to the event queue every time the user moves the mouse.
14328 Imagine that it takes us 0.1 seconds to handle a motion event, but the
14329 X server queues a new motion event every 0.05 seconds. We will soon
14330 get way behind the users drawing. If the user draws for 5 seconds,
14331 it will take us another 5 seconds to catch up after they release
14332 the mouse button! What we would like is to only get one motion
14333 event for each event we process. The way to do this is to
14334 specify <tt/GDK_POINTER_MOTION_HINT_MASK/.
14336 When we specify <tt/GDK_POINTER_MOTION_HINT_MASK/, the server sends
14337 us a motion event the first time the pointer moves after entering
14338 our window, or after a button press or release event. Subsequent
14339 motion events will be suppressed until we explicitly ask for
14340 the position of the pointer using the function:
14343 GdkWindow* gdk_window_get_pointer (GdkWindow *window,
14346 GdkModifierType *mask);
14349 (There is another function, <tt>gtk_widget_get_pointer()</tt> which
14350 has a simpler interface, but turns out not to be very useful, since
14351 it only retrieves the position of the mouse, not whether the buttons
14354 The code to set the events for our window then looks like:
14357 gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
14358 (GtkSignalFunc) expose_event, NULL);
14359 gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
14360 (GtkSignalFunc) configure_event, NULL);
14361 gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
14362 (GtkSignalFunc) motion_notify_event, NULL);
14363 gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
14364 (GtkSignalFunc) button_press_event, NULL);
14366 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
14367 | GDK_LEAVE_NOTIFY_MASK
14368 | GDK_BUTTON_PRESS_MASK
14369 | GDK_POINTER_MOTION_MASK
14370 | GDK_POINTER_MOTION_HINT_MASK);
14373 We'll save the "expose_event" and "configure_event" handlers for
14374 later. The "motion_notify_event" and "button_press_event" handlers
14379 button_press_event (GtkWidget *widget, GdkEventButton *event)
14381 if (event->button == 1 && pixmap != NULL)
14382 draw_brush (widget, event->x, event->y);
14388 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
14391 GdkModifierType state;
14393 if (event->is_hint)
14394 gdk_window_get_pointer (event->window, &x, &y, &state);
14399 state = event->state;
14402 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
14403 draw_brush (widget, x, y);
14409 <!-- ----------------------------------------------------------------- -->
14410 <sect1> The DrawingArea Widget, And Drawing
14412 We now turn to the process of drawing on the screen. The
14413 widget we use for this is the DrawingArea widget. A drawing area
14414 widget is essentially an X window and nothing more. It is a blank
14415 canvas in which we can draw whatever we like. A drawing area
14416 is created using the call:
14419 GtkWidget* gtk_drawing_area_new (void);
14422 A default size for the widget can be specified by calling:
14425 void gtk_drawing_area_size (GtkDrawingArea *darea,
14430 This default size can be overridden, as is true for all widgets,
14431 by calling <tt>gtk_widget_set_usize()</tt>, and that, in turn, can
14432 be overridden if the user manually resizes the the window containing
14435 It should be noted that when we create a DrawingArea widget, we are
14436 <em>completely</em> responsible for drawing the contents. If our
14437 window is obscured then uncovered, we get an exposure event and must
14438 redraw what was previously hidden.
14440 Having to remember everything that was drawn on the screen so we
14441 can properly redraw it can, to say the least, be a nuisance. In
14442 addition, it can be visually distracting if portions of the
14443 window are cleared, then redrawn step by step. The solution to
14444 this problem is to use an offscreen <em>backing pixmap</em>.
14445 Instead of drawing directly to the screen, we draw to an image
14446 stored in server memory but not displayed, then when the image
14447 changes or new portions of the image are displayed, we copy the
14448 relevant portions onto the screen.
14450 To create an offscreen pixmap, we call the function:
14453 GdkPixmap* gdk_pixmap_new (GdkWindow *window,
14459 The <tt>window</tt> parameter specifies a GDK window that this pixmap
14460 takes some of its properties from. <tt>width</tt> and <tt>height</tt>
14461 specify the size of the pixmap. <tt>depth</tt> specifies the <em>color
14462 depth</em>, that is the number of bits per pixel, for the new window.
14463 If the depth is specified as <tt>-1</tt>, it will match the depth
14464 of <tt>window</tt>.
14466 We create the pixmap in our "configure_event" handler. This event
14467 is generated whenever the window changes size, including when it
14468 is originally created.
14471 /* Backing pixmap for drawing area */
14472 static GdkPixmap *pixmap = NULL;
14474 /* Create a new backing pixmap of the appropriate size */
14476 configure_event (GtkWidget *widget, GdkEventConfigure *event)
14479 gdk_pixmap_unref(pixmap);
14481 pixmap = gdk_pixmap_new(widget->window,
14482 widget->allocation.width,
14483 widget->allocation.height,
14485 gdk_draw_rectangle (pixmap,
14486 widget->style->white_gc,
14489 widget->allocation.width,
14490 widget->allocation.height);
14496 The call to <tt>gdk_draw_rectangle()</tt> clears the pixmap
14497 initially to white. We'll say more about that in a moment.
14499 Our exposure event handler then simply copies the relevant portion
14500 of the pixmap onto the screen (we determine the area we need
14501 to redraw by using the event->area field of the exposure event):
14504 /* Redraw the screen from the backing pixmap */
14506 expose_event (GtkWidget *widget, GdkEventExpose *event)
14508 gdk_draw_pixmap(widget->window,
14509 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
14511 event->area.x, event->area.y,
14512 event->area.x, event->area.y,
14513 event->area.width, event->area.height);
14519 We've now seen how to keep the screen up to date with our pixmap, but
14520 how do we actually draw interesting stuff on our pixmap? There are a
14521 large number of calls in GTK's GDK library for drawing on
14522 <em>drawables</em>. A drawable is simply something that can be drawn
14523 upon. It can be a window, a pixmap, or a bitmap (a black and white
14524 image). We've already seen two such calls above,
14525 <tt>gdk_draw_rectangle()</tt> and <tt>gdk_draw_pixmap()</tt>. The
14530 gdk_draw_rectangle ()
14532 gdk_draw_polygon ()
14539 gdk_draw_segments ()
14542 See the reference documentation or the header file
14543 <tt><gdk/gdk.h></tt> for further details on these functions.
14544 These functions all share the same first two arguments. The first
14545 argument is the drawable to draw upon, the second argument is a
14546 <em>graphics context</em> (GC).
14548 A graphics context encapsulates information about things such as
14549 foreground and background color and line width. GDK has a full set of
14550 functions for creating and modifying graphics contexts, but to keep
14551 things simple we'll just use predefined graphics contexts. Each widget
14552 has an associated style. (Which can be modified in a gtkrc file, see
14553 the section GTK's rc file.) This, among other things, stores a number
14554 of graphics contexts. Some examples of accessing these graphics
14558 widget->style->white_gc
14559 widget->style->black_gc
14560 widget->style->fg_gc[GTK_STATE_NORMAL]
14561 widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
14564 The fields <tt>fg_gc</tt>, <tt>bg_gc</tt>, <tt>dark_gc</tt>, and
14565 <tt>light_gc</tt> are indexed by a parameter of type
14566 <tt>GtkStateType</tt> which can take on the values:
14571 GTK_STATE_PRELIGHT,
14572 GTK_STATE_SELECTED,
14573 GTK_STATE_INSENSITIVE
14576 For instance, for <tt/GTK_STATE_SELECTED/ the default foreground
14577 color is white and the default background color, dark blue.
14579 Our function <tt>draw_brush()</tt>, which does the actual drawing
14580 on the screen, is then:
14583 /* Draw a rectangle on the screen */
14585 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
14587 GdkRectangle update_rect;
14589 update_rect.x = x - 5;
14590 update_rect.y = y - 5;
14591 update_rect.width = 10;
14592 update_rect.height = 10;
14593 gdk_draw_rectangle (pixmap,
14594 widget->style->black_gc,
14596 update_rect.x, update_rect.y,
14597 update_rect.width, update_rect.height);
14598 gtk_widget_draw (widget, &update_rect);
14602 After we draw the rectangle representing the brush onto the pixmap,
14603 we call the function:
14606 void gtk_widget_draw (GtkWidget *widget,
14607 GdkRectangle *area);
14610 which notifies X that the area given by the <tt>area</tt> parameter
14611 needs to be updated. X will eventually generate an expose event
14612 (possibly combining the areas passed in several calls to
14613 <tt>gtk_widget_draw()</tt>) which will cause our expose event handler
14614 to copy the relevant portions to the screen.
14616 We have now covered the entire drawing program except for a few
14617 mundane details like creating the main window.
14619 <!-- ----------------------------------------------------------------- -->
14620 <sect1> Adding XInput support
14622 It is now possible to buy quite inexpensive input devices such
14623 as drawing tablets, which allow drawing with a much greater
14624 ease of artistic expression than does a mouse. The simplest way
14625 to use such devices is simply as a replacement for the mouse,
14626 but that misses out many of the advantages of these devices,
14630 <item> Pressure sensitivity
14631 <item> Tilt reporting
14632 <item> Sub-pixel positioning
14633 <item> Multiple inputs (for example, a stylus with a point and eraser)
14636 For information about the XInput extension, see the <htmlurl
14637 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
14638 name="XInput-HOWTO">.
14640 If we examine the full definition of, for example, the GdkEventMotion
14641 structure, we see that it has fields to support extended device
14645 struct _GdkEventMotion
14657 GdkInputSource source;
14662 <tt/pressure/ gives the pressure as a floating point number between
14663 0 and 1. <tt/xtilt/ and <tt/ytilt/ can take on values between
14664 -1 and 1, corresponding to the degree of tilt in each direction.
14665 <tt/source/ and <tt/deviceid/ specify the device for which the
14666 event occurred in two different ways. <tt/source/ gives some simple
14667 information about the type of device. It can take the enumeration
14677 <tt/deviceid/ specifies a unique numeric ID for the device. This can
14678 be used to find out further information about the device using the
14679 <tt/gdk_input_list_devices()/ call (see below). The special value
14680 <tt/GDK_CORE_POINTER/ is used for the core pointer device. (Usually
14683 <sect2> Enabling extended device information
14685 To let GTK know about our interest in the extended device information,
14686 we merely have to add a single line to our program:
14689 gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
14692 By giving the value <tt/GDK_EXTENSION_EVENTS_CURSOR/ we say that
14693 we are interested in extension events, but only if we don't have
14694 to draw our own cursor. See the section <ref
14695 id="sec_Further_Sophistications" name="Further Sophistications"> below
14696 for more information about drawing the cursor. We could also
14697 give the values <tt/GDK_EXTENSION_EVENTS_ALL/ if we were willing
14698 to draw our own cursor, or <tt/GDK_EXTENSION_EVENTS_NONE/ to revert
14699 back to the default condition.
14701 This is not completely the end of the story however. By default,
14702 no extension devices are enabled. We need a mechanism to allow
14703 users to enable and configure their extension devices. GTK provides
14704 the InputDialog widget to automate this process. The following
14705 procedure manages an InputDialog widget. It creates the dialog if
14706 it isn't present, and raises it to the top otherwise.
14710 input_dialog_destroy (GtkWidget *w, gpointer data)
14712 *((GtkWidget **)data) = NULL;
14716 create_input_dialog ()
14718 static GtkWidget *inputd = NULL;
14722 inputd = gtk_input_dialog_new();
14724 gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
14725 (GtkSignalFunc)input_dialog_destroy, &inputd);
14726 gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
14728 (GtkSignalFunc)gtk_widget_hide,
14729 GTK_OBJECT(inputd));
14730 gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
14732 gtk_widget_show (inputd);
14736 if (!GTK_WIDGET_MAPPED(inputd))
14737 gtk_widget_show(inputd);
14739 gdk_window_raise(inputd->window);
14744 (You might want to take note of the way we handle this dialog. By
14745 connecting to the "destroy" signal, we make sure that we don't keep a
14746 pointer to dialog around after it is destroyed - that could lead to a
14749 The InputDialog has two buttons "Close" and "Save", which by default
14750 have no actions assigned to them. In the above function we make
14751 "Close" hide the dialog, hide the "Save" button, since we don't
14752 implement saving of XInput options in this program.
14754 <sect2> Using extended device information
14756 Once we've enabled the device, we can just use the extended
14757 device information in the extra fields of the event structures.
14758 In fact, it is always safe to use this information since these
14759 fields will have reasonable default values even when extended
14760 events are not enabled.
14762 Once change we do have to make is to call
14763 <tt/gdk_input_window_get_pointer()/ instead of
14764 <tt/gdk_window_get_pointer/. This is necessary because
14765 <tt/gdk_window_get_pointer/ doesn't return the extended device
14769 void gdk_input_window_get_pointer( GdkWindow *window,
14776 GdkModifierType *mask);
14779 When calling this function, we need to specify the device ID as
14780 well as the window. Usually, we'll get the device ID from the
14781 <tt/deviceid/ field of an event structure. Again, this function
14782 will return reasonable values when extension events are not
14783 enabled. (In this case, <tt/event->deviceid/ will have the value
14784 <tt/GDK_CORE_POINTER/).
14786 So the basic structure of our button-press and motion event handlers
14787 doesn't change much - we just need to add code to deal with the
14788 extended information.
14792 button_press_event (GtkWidget *widget, GdkEventButton *event)
14794 print_button_press (event->deviceid);
14796 if (event->button == 1 && pixmap != NULL)
14797 draw_brush (widget, event->source, event->x, event->y, event->pressure);
14803 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
14807 GdkModifierType state;
14809 if (event->is_hint)
14810 gdk_input_window_get_pointer (event->window, event->deviceid,
14811 &x, &y, &pressure, NULL, NULL, &state);
14816 pressure = event->pressure;
14817 state = event->state;
14820 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
14821 draw_brush (widget, event->source, x, y, pressure);
14827 We also need to do something with the new information. Our new
14828 <tt/draw_brush()/ function draws with a different color for
14829 each <tt/event->source/ and changes the brush size depending
14833 /* Draw a rectangle on the screen, size depending on pressure,
14834 and color on the type of device */
14836 draw_brush (GtkWidget *widget, GdkInputSource source,
14837 gdouble x, gdouble y, gdouble pressure)
14840 GdkRectangle update_rect;
14844 case GDK_SOURCE_MOUSE:
14845 gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
14847 case GDK_SOURCE_PEN:
14848 gc = widget->style->black_gc;
14850 case GDK_SOURCE_ERASER:
14851 gc = widget->style->white_gc;
14854 gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
14857 update_rect.x = x - 10 * pressure;
14858 update_rect.y = y - 10 * pressure;
14859 update_rect.width = 20 * pressure;
14860 update_rect.height = 20 * pressure;
14861 gdk_draw_rectangle (pixmap, gc, TRUE,
14862 update_rect.x, update_rect.y,
14863 update_rect.width, update_rect.height);
14864 gtk_widget_draw (widget, &update_rect);
14868 <sect2> Finding out more about a device
14870 As an example of how to find out more about a device, our program
14871 will print the name of the device that generates each button
14872 press. To find out the name of a device, we call the function:
14875 GList *gdk_input_list_devices (void);
14878 which returns a GList (a linked list type from the GLib library)
14879 of GdkDeviceInfo structures. The GdkDeviceInfo structure is defined
14883 struct _GdkDeviceInfo
14887 GdkInputSource source;
14893 GdkDeviceKey *keys;
14897 Most of these fields are configuration information that you can ignore
14898 unless you are implementing XInput configuration saving. The fieldwe
14899 are interested in here is <tt/name/ which is simply the name that X
14900 assigns to the device. The other field that isn't configuration
14901 information is <tt/has_cursor/. If <tt/has_cursor/ is false, then we
14902 we need to draw our own cursor. But since we've specified
14903 <tt/GDK_EXTENSION_EVENTS_CURSOR/, we don't have to worry about this.
14905 Our <tt/print_button_press()/ function simply iterates through
14906 the returned list until it finds a match, then prints out
14907 the name of the device.
14911 print_button_press (guint32 deviceid)
14915 /* gdk_input_list_devices returns an internal list, so we shouldn't
14916 free it afterwards */
14917 tmp_list = gdk_input_list_devices();
14921 GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
14923 if (info->deviceid == deviceid)
14925 printf("Button press on device '%s'\n", info->name);
14929 tmp_list = tmp_list->next;
14934 That completes the changes to "XInputize" our program.
14936 <sect2> Further sophistications <label id="sec_Further_Sophistications">
14938 Although our program now supports XInput quite well, it lacks some
14939 features we would want in a full-featured application. First, the user
14940 probably doesn't want to have to configure their device each time they
14941 run the program, so we should allow them to save the device
14942 configuration. This is done by iterating through the return of
14943 <tt/gdk_input_list_devices()/ and writing out the configuration to a
14946 To restore the state next time the program is run, GDK provides
14947 functions to change device configuration:
14950 gdk_input_set_extension_events()
14951 gdk_input_set_source()
14952 gdk_input_set_mode()
14953 gdk_input_set_axes()
14954 gdk_input_set_key()
14957 (The list returned from <tt/gdk_input_list_devices()/ should not be
14958 modified directly.) An example of doing this can be found in the
14959 drawing program gsumi. (Available from <htmlurl
14960 url="http://www.msc.cornell.edu/~otaylor/gsumi/"
14961 name="http://www.msc.cornell.edu/~otaylor/gsumi/">) Eventually, it
14962 would be nice to have a standard way of doing this for all
14963 applications. This probably belongs at a slightly higher level than
14964 GTK, perhaps in the GNOME library.
14966 Another major omission that we have mentioned above is the lack of
14967 cursor drawing. Platforms other than XFree86 currently do not allow
14968 simultaneously using a device as both the core pointer and directly by
14969 an application. See the <url
14970 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
14971 name="XInput-HOWTO"> for more information about this. This means that
14972 applications that want to support the widest audience need to draw
14975 An application that draws its own cursor needs to do two things:
14976 determine if the current device needs a cursor drawn or not, and
14977 determine if the current device is in proximity. (If the current
14978 device is a drawing tablet, it's a nice touch to make the cursor
14979 disappear when the stylus is lifted from the tablet. When the
14980 device is touching the stylus, that is called "in proximity.")
14981 The first is done by searching the device list, as we did
14982 to find out the device name. The second is achieved by selecting
14983 "proximity_out" events. An example of drawing one's own cursor is
14984 found in the "testinput" program found in the GTK distribution.
14986 <!-- ***************************************************************** -->
14987 <sect>Tips For Writing GTK Applications
14988 <!-- ***************************************************************** -->
14990 This section is simply a gathering of wisdom, general style guidelines
14991 and hints to creating good GTK applications. Currently this section
14992 is very short, but I hope it will get longer in future editions of
14995 Use GNU autoconf and automake! They are your friends :) Automake
14996 examines C files, determines how they depend on each other, and
14997 generates a Makefile so the files can be compiled in the correct
14998 order. Autoconf permits automatic configuration of software
14999 installation, handling a large number of system quirks to increase
15000 portability. I am planning to make a quick intro on them here.
15002 When writing C code, use only C comments (beginning with "/*" and
15003 ending with "*/"), and don't use C++-style comments ("//"). Although
15004 many C compilers understand C++ comments, others don't, and the ANSI C
15005 standard does not require that C++-style comments be processed as
15008 <!-- ***************************************************************** -->
15009 <sect>Contributing <label id="sec_Contributing">
15010 <!-- ***************************************************************** -->
15012 This document, like so much other great software out there, was
15013 created for free by volunteers. If you are at all knowledgeable about
15014 any aspect of GTK that does not already have documentation, please
15015 consider contributing to this document.
15017 If you do decide to contribute, please mail your text to Tony Gale,
15018 <tt><htmlurl url="mailto:gale@gtk.org"
15019 name="gale@gtk.org"></tt>. Also, be aware that the entirety of this
15020 document is free, and any addition by you provide must also be
15021 free. That is, people may use any portion of your examples in their
15022 programs, and copies of this document may be distributed at will, etc.
15026 <!-- ***************************************************************** -->
15028 <!-- ***************************************************************** -->
15030 We would like to thank the following for their contributions to this text.
15033 <item>Bawer Dagdeviren, <tt><htmlurl url="mailto:chamele0n@geocities.com"
15034 name="chamele0n@geocities.com"></tt> for the menus tutorial.
15036 <item>Raph Levien, <tt><htmlurl url="mailto:raph@acm.org"
15037 name="raph@acm.org"></tt>
15038 for hello world ala GTK, widget packing, and general all around wisdom.
15039 He's also generously donated a home for this tutorial.
15041 <item>Peter Mattis, <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
15042 name="petm@xcf.berkeley.edu"></tt> for the simplest GTK program..
15043 and the ability to make it :)
15045 <item>Werner Koch <tt><htmlurl url="mailto:werner.koch@guug.de"
15046 name="werner.koch@guug.de"></tt> for converting the original plain text to
15047 SGML, and the widget class hierarchy.
15049 <item>Mark Crichton <tt><htmlurl
15050 url="mailto:crichton@expert.cc.purdue.edu"
15051 name="crichton@expert.cc.purdue.edu"></tt> for the menu factory code,
15052 and the table packing tutorial.
15054 <item>Owen Taylor <tt><htmlurl url="mailto:owt1@cornell.edu"
15055 name="owt1@cornell.edu"></tt> for the EventBox widget section (and the
15056 patch to the distro). He's also responsible for the selections code
15057 and tutorial, as well as the sections on writing your own GTK widgets,
15058 and the example application. Thanks a lot Owen for all you help!
15060 <item>Mark VanderBoom <tt><htmlurl url="mailto:mvboom42@calvin.edu"
15061 name="mvboom42@calvin.edu"></tt> for his wonderful work on the
15062 Notebook, Progress Bar, Dialogs, and File selection widgets. Thanks a
15063 lot Mark! You've been a great help.
15065 <item>Tim Janik <tt><htmlurl url="mailto:timj@gtk.org"
15066 name="timj@gtk.org"></tt> for his great job on the Lists
15067 Widget. His excellent work on automatically extracting the widget tree
15068 and signal information from GTK. Thanks Tim :)
15070 <item>Rajat Datta <tt><htmlurl url="mailto:rajat@ix.netcom.com"
15071 name="rajat@ix.netcom.com"</tt> for the excellent job on the Pixmap
15074 <item>Michael K. Johnson <tt><htmlurl url="mailto:johnsonm@redhat.com"
15075 name="johnsonm@redhat.com"></tt> for info and code for popup menus.
15077 <item>David Huggins-Daines <tt><htmlurl
15078 url="mailto:bn711@freenet.carleton.ca"
15079 name="bn711@freenet.carleton.ca"></tt> for the Range Widgets and Tree
15082 <item>Stefan Mars <tt><htmlurl url="mailto:mars@lysator.liu.se"
15083 name="mars@lysator.liu.se"></tt> for the CList section.
15085 <item>David A. Wheeler <tt><htmlurl url="mailto:dwheeler@ida.org"
15086 name="dwheeler@ida.org"></tt> for portions of the text on GLib
15087 and various tutorial fixups and improvements.
15088 The GLib text was in turn based on material developed by Damon Chaplin
15089 <tt><htmlurl url="mailto:DAChaplin@msn.com" name="DAChaplin@msn.com"></tt>
15091 <item>David King for style checking the entire document.
15094 And to all of you who commented on and helped refine this document.
15098 <!-- ***************************************************************** -->
15099 <sect> Tutorial Copyright and Permissions Notice
15100 <!-- ***************************************************************** -->
15103 The GTK Tutorial is Copyright (C) 1997 Ian Main.
15105 Copyright (C) 1998-1999 Tony Gale.
15107 Permission is granted to make and distribute verbatim copies of this
15108 manual provided the copyright notice and this permission notice are
15109 preserved on all copies.
15111 Permission is granted to copy and distribute modified versions of
15112 this document under the conditions for verbatim copying, provided that
15113 this copyright notice is included exactly as in the original,
15114 and that the entire resulting derived work is distributed under
15115 the terms of a permission notice identical to this one.
15116 <P>Permission is granted to copy and distribute translations of this
15117 document into another language, under the above conditions for modified
15120 If you are intending to incorporate this document into a published
15121 work, please contact the maintainer, and we will make an effort
15122 to ensure that you have the most up to date information available.
15124 There is no guarantee that this document lives up to its intended
15125 purpose. This is simply provided as a free resource. As such,
15126 the authors and maintainers of the information provided within can
15127 not make any guarantee that the information is even accurate.
15129 <!-- ***************************************************************** -->
15131 <!-- ***************************************************************** -->
15133 <!-- ***************************************************************** -->
15134 <sect> GTK Signals <label id="sec_GTK_Signals">
15135 <!-- ***************************************************************** -->
15137 As GTK is an object oriented widget set, it has a hierarchy of
15138 inheritance. This inheritance mechanism applies for
15139 signals. Therefore, you should refer to the widget hierarchy tree when
15140 using the signals listed in this section.
15142 <!-- ----------------------------------------------------------------- -->
15144 <!-- ----------------------------------------------------------------- -->
15147 void GtkObject::destroy (GtkObject *,
15151 <!-- ----------------------------------------------------------------- -->
15153 <!-- ----------------------------------------------------------------- -->
15157 void GtkWidget::show (GtkWidget *,
15159 void GtkWidget::hide (GtkWidget *,
15161 void GtkWidget::map (GtkWidget *,
15163 void GtkWidget::unmap (GtkWidget *,
15165 void GtkWidget::realize (GtkWidget *,
15167 void GtkWidget::unrealize (GtkWidget *,
15169 void GtkWidget::draw (GtkWidget *,
15172 void GtkWidget::draw-focus (GtkWidget *,
15174 void GtkWidget::draw-default (GtkWidget *,
15176 void GtkWidget::size-request (GtkWidget *,
15179 void GtkWidget::size-allocate (GtkWidget *,
15182 void GtkWidget::state-changed (GtkWidget *,
15185 void GtkWidget::parent-set (GtkWidget *,
15188 void GtkWidget::style-set (GtkWidget *,
15191 void GtkWidget::add-accelerator (GtkWidget *,
15198 void GtkWidget::remove-accelerator (GtkWidget *,
15203 gboolean GtkWidget::event (GtkWidget *,
15206 gboolean GtkWidget::button-press-event (GtkWidget *,
15209 gboolean GtkWidget::button-release-event (GtkWidget *,
15212 gboolean GtkWidget::motion-notify-event (GtkWidget *,
15215 gboolean GtkWidget::delete-event (GtkWidget *,
15218 gboolean GtkWidget::destroy-event (GtkWidget *,
15221 gboolean GtkWidget::expose-event (GtkWidget *,
15224 gboolean GtkWidget::key-press-event (GtkWidget *,
15227 gboolean GtkWidget::key-release-event (GtkWidget *,
15230 gboolean GtkWidget::enter-notify-event (GtkWidget *,
15233 gboolean GtkWidget::leave-notify-event (GtkWidget *,
15236 gboolean GtkWidget::configure-event (GtkWidget *,
15239 gboolean GtkWidget::focus-in-event (GtkWidget *,
15242 gboolean GtkWidget::focus-out-event (GtkWidget *,
15245 gboolean GtkWidget::map-event (GtkWidget *,
15248 gboolean GtkWidget::unmap-event (GtkWidget *,
15251 gboolean GtkWidget::property-notify-event (GtkWidget *,
15254 gboolean GtkWidget::selection-clear-event (GtkWidget *,
15257 gboolean GtkWidget::selection-request-event (GtkWidget *,
15260 gboolean GtkWidget::selection-notify-event (GtkWidget *,
15263 void GtkWidget::selection-get (GtkWidget *,
15264 GtkSelectionData *,
15267 void GtkWidget::selection-received (GtkWidget *,
15268 GtkSelectionData *,
15271 gboolean GtkWidget::proximity-in-event (GtkWidget *,
15274 gboolean GtkWidget::proximity-out-event (GtkWidget *,
15277 void GtkWidget::drag-begin (GtkWidget *,
15280 void GtkWidget::drag-end (GtkWidget *,
15283 void GtkWidget::drag-data-delete (GtkWidget *,
15286 void GtkWidget::drag-leave (GtkWidget *,
15290 gboolean GtkWidget::drag-motion (GtkWidget *,
15296 gboolean GtkWidget::drag-drop (GtkWidget *,
15302 void GtkWidget::drag-data-get (GtkWidget *,
15304 GtkSelectionData *,
15308 void GtkWidget::drag-data-received (GtkWidget *,
15312 GtkSelectionData *,
15316 gboolean GtkWidget::client-event (GtkWidget *,
15319 gboolean GtkWidget::no-expose-event (GtkWidget *,
15322 gboolean GtkWidget::visibility-notify-event (GtkWidget *,
15325 void GtkWidget::debug-msg (GtkWidget *,
15330 <!-- ----------------------------------------------------------------- -->
15332 <!-- ----------------------------------------------------------------- -->
15335 void GtkData::disconnect (GtkData *,
15339 <!-- ----------------------------------------------------------------- -->
15340 <sect1>GtkContainer
15341 <!-- ----------------------------------------------------------------- -->
15344 void GtkContainer::add (GtkContainer *,
15347 void GtkContainer::remove (GtkContainer *,
15350 void GtkContainer::check-resize (GtkContainer *,
15352 GtkDirectionType GtkContainer::focus (GtkContainer *,
15355 void GtkContainer::set-focus-child (GtkContainer *,
15360 <!-- ----------------------------------------------------------------- -->
15362 <!-- ----------------------------------------------------------------- -->
15365 void GtkCalendar::month-changed (GtkCalendar *,
15367 void GtkCalendar::day-selected (GtkCalendar *,
15369 void GtkCalendar::day-selected-double-click (GtkCalendar *,
15371 void GtkCalendar::prev-month (GtkCalendar *,
15373 void GtkCalendar::next-month (GtkCalendar *,
15375 void GtkCalendar::prev-year (GtkCalendar *,
15377 void GtkCalendar::next-year (GtkCalendar *,
15381 <!-- ----------------------------------------------------------------- -->
15383 <!-- ----------------------------------------------------------------- -->
15386 void GtkEditable::changed (GtkEditable *,
15388 void GtkEditable::insert-text (GtkEditable *,
15393 void GtkEditable::delete-text (GtkEditable *,
15397 void GtkEditable::activate (GtkEditable *,
15399 void GtkEditable::set-editable (GtkEditable *,
15402 void GtkEditable::move-cursor (GtkEditable *,
15406 void GtkEditable::move-word (GtkEditable *,
15409 void GtkEditable::move-page (GtkEditable *,
15413 void GtkEditable::move-to-row (GtkEditable *,
15416 void GtkEditable::move-to-column (GtkEditable *,
15419 void GtkEditable::kill-char (GtkEditable *,
15422 void GtkEditable::kill-word (GtkEditable *,
15425 void GtkEditable::kill-line (GtkEditable *,
15428 void GtkEditable::cut-clipboard (GtkEditable *,
15430 void GtkEditable::copy-clipboard (GtkEditable *,
15432 void GtkEditable::paste-clipboard (GtkEditable *,
15436 <!-- ----------------------------------------------------------------- -->
15437 <sect1>GtkTipsQuery
15438 <!-- ----------------------------------------------------------------- -->
15441 void GtkTipsQuery::start-query (GtkTipsQuery *,
15443 void GtkTipsQuery::stop-query (GtkTipsQuery *,
15445 void GtkTipsQuery::widget-entered (GtkTipsQuery *,
15450 gboolean GtkTipsQuery::widget-selected (GtkTipsQuery *,
15458 <!-- ----------------------------------------------------------------- -->
15460 <!-- ----------------------------------------------------------------- -->
15463 void GtkCList::select-row (GtkCList *,
15468 void GtkCList::unselect-row (GtkCList *,
15473 void GtkCList::row-move (GtkCList *,
15477 void GtkCList::click-column (GtkCList *,
15480 void GtkCList::resize-column (GtkCList *,
15484 void GtkCList::toggle-focus-row (GtkCList *,
15486 void GtkCList::select-all (GtkCList *,
15488 void GtkCList::unselect-all (GtkCList *,
15490 void GtkCList::undo-selection (GtkCList *,
15492 void GtkCList::start-selection (GtkCList *,
15494 void GtkCList::end-selection (GtkCList *,
15496 void GtkCList::toggle-add-mode (GtkCList *,
15498 void GtkCList::extend-selection (GtkCList *,
15503 void GtkCList::scroll-vertical (GtkCList *,
15507 void GtkCList::scroll-horizontal (GtkCList *,
15511 void GtkCList::abort-column-resize (GtkCList *,
15515 <!-- ----------------------------------------------------------------- -->
15517 <!-- ----------------------------------------------------------------- -->
15520 void GtkNotebook::switch-page (GtkNotebook *,
15527 <!-- ----------------------------------------------------------------- -->
15529 <!-- ----------------------------------------------------------------- -->
15532 void GtkList::selection-changed (GtkList *,
15534 void GtkList::select-child (GtkList *,
15537 void GtkList::unselect-child (GtkList *,
15542 <!-- ----------------------------------------------------------------- -->
15543 <sect1>GtkMenuShell
15544 <!-- ----------------------------------------------------------------- -->
15547 void GtkMenuShell::deactivate (GtkMenuShell *,
15549 void GtkMenuShell::selection-done (GtkMenuShell *,
15551 void GtkMenuShell::move-current (GtkMenuShell *,
15552 GtkMenuDirectionType,
15554 void GtkMenuShell::activate-current (GtkMenuShell *,
15557 void GtkMenuShell::cancel (GtkMenuShell *,
15561 <!-- ----------------------------------------------------------------- -->
15563 <!-- ----------------------------------------------------------------- -->
15566 void GtkToolbar::orientation-changed (GtkToolbar *,
15569 void GtkToolbar::style-changed (GtkToolbar *,
15574 <!-- ----------------------------------------------------------------- -->
15576 <!-- ----------------------------------------------------------------- -->
15579 void GtkTree::selection-changed (GtkTree *,
15581 void GtkTree::select-child (GtkTree *,
15584 void GtkTree::unselect-child (GtkTree *,
15589 <!-- ----------------------------------------------------------------- -->
15591 <!-- ----------------------------------------------------------------- -->
15594 void GtkButton::pressed (GtkButton *,
15596 void GtkButton::released (GtkButton *,
15598 void GtkButton::clicked (GtkButton *,
15600 void GtkButton::enter (GtkButton *,
15602 void GtkButton::leave (GtkButton *,
15606 <!-- ----------------------------------------------------------------- -->
15608 <!-- ----------------------------------------------------------------- -->
15611 void GtkItem::select (GtkItem *,
15613 void GtkItem::deselect (GtkItem *,
15615 void GtkItem::toggle (GtkItem *,
15619 <!-- ----------------------------------------------------------------- -->
15621 <!-- ----------------------------------------------------------------- -->
15624 void GtkWindow::set-focus (GtkWindow *,
15629 <!-- ----------------------------------------------------------------- -->
15630 <sect1>GtkHandleBox
15631 <!-- ----------------------------------------------------------------- -->
15634 void GtkHandleBox::child-attached (GtkHandleBox *,
15637 void GtkHandleBox::child-detached (GtkHandleBox *,
15642 <!-- ----------------------------------------------------------------- -->
15643 <sect1>GtkToggleButton
15644 <!-- ----------------------------------------------------------------- -->
15647 void GtkToggleButton::toggled (GtkToggleButton *,
15652 <!-- ----------------------------------------------------------------- -->
15654 <!-- ----------------------------------------------------------------- -->
15657 void GtkMenuItem::activate (GtkMenuItem *,
15659 void GtkMenuItem::activate-item (GtkMenuItem *,
15663 <!-- ----------------------------------------------------------------- -->
15665 <!-- ----------------------------------------------------------------- -->
15668 void GtkListItem::toggle-focus-row (GtkListItem *,
15670 void GtkListItem::select-all (GtkListItem *,
15672 void GtkListItem::unselect-all (GtkListItem *,
15674 void GtkListItem::undo-selection (GtkListItem *,
15676 void GtkListItem::start-selection (GtkListItem *,
15678 void GtkListItem::end-selection (GtkListItem *,
15680 void GtkListItem::toggle-add-mode (GtkListItem *,
15682 void GtkListItem::extend-selection (GtkListItem *,
15687 void GtkListItem::scroll-vertical (GtkListItem *,
15691 void GtkListItem::scroll-horizontal (GtkListItem *,
15697 <!-- ----------------------------------------------------------------- -->
15699 <!-- ----------------------------------------------------------------- -->
15702 void GtkTreeItem::collapse (GtkTreeItem *,
15704 void GtkTreeItem::expand (GtkTreeItem *,
15708 <!-- ----------------------------------------------------------------- -->
15709 <sect1>GtkCheckMenuItem
15710 <!-- ----------------------------------------------------------------- -->
15713 void GtkCheckMenuItem::toggled (GtkCheckMenuItem *,
15717 <!-- ----------------------------------------------------------------- -->
15718 <sect1>GtkInputDialog
15719 <!-- ----------------------------------------------------------------- -->
15722 void GtkInputDialog::enable-device (GtkInputDialog *,
15725 void GtkInputDialog::disable-device (GtkInputDialog *,
15730 <!-- ----------------------------------------------------------------- -->
15731 <sect1>GtkColorSelection
15732 <!-- ----------------------------------------------------------------- -->
15735 void GtkColorSelection::color-changed (GtkColorSelection *,
15739 <!-- ----------------------------------------------------------------- -->
15740 <sect1>GtkStatusBar
15741 <!-- ----------------------------------------------------------------- -->
15744 void GtkStatusbar::text-pushed (GtkStatusbar *,
15748 void GtkStatusbar::text-popped (GtkStatusbar *,
15754 <!-- ----------------------------------------------------------------- -->
15756 <!-- ----------------------------------------------------------------- -->
15759 void GtkCTree::tree-select-row (GtkCTree *,
15763 void GtkCTree::tree-unselect-row (GtkCTree *,
15767 void GtkCTree::tree-expand (GtkCTree *,
15770 void GtkCTree::tree-collapse (GtkCTree *,
15773 void GtkCTree::tree-move (GtkCTree *,
15778 void GtkCTree::change-focus-row-expansion (GtkCTree *,
15779 GtkCTreeExpansionType,
15783 <!-- ----------------------------------------------------------------- -->
15785 <!-- ----------------------------------------------------------------- -->
15788 void GtkCurve::curve-type-changed (GtkCurve *,
15792 <!-- ----------------------------------------------------------------- -->
15793 <sect1>GtkAdjustment
15794 <!-- ----------------------------------------------------------------- -->
15797 void GtkAdjustment::changed (GtkAdjustment *,
15799 void GtkAdjustment::value-changed (GtkAdjustment *,
15803 <!-- ***************************************************************** -->
15804 <sect> GDK Event Types<label id="sec_GDK_Event_Types">
15805 <!-- ***************************************************************** -->
15807 The following data types are passed into event handlers by GTK+. For
15808 each data type listed, the signals that use this data type are listed.
15813 <item>drag_end_event
15816 <item> GdkEventType
15821 <item>destroy_event
15824 <item>no_expose_event
15827 <item> GdkEventExpose
15832 <item> GdkEventNoExpose
15834 <item> GdkEventVisibility
15836 <item> GdkEventMotion
15838 <item>motion_notify_event
15841 <item> GdkEventButton
15843 <item>button_press_event
15844 <item>button_release_event
15849 <item>key_press_event
15850 <item>key_release_event
15853 <item> GdkEventCrossing
15855 <item>enter_notify_event
15856 <item>leave_notify_event
15859 <item> GdkEventFocus
15861 <item>focus_in_event
15862 <item>focus_out_event
15865 <item> GdkEventConfigure
15867 <item>configure_event
15870 <item> GdkEventProperty
15872 <item>property_notify_event
15875 <item> GdkEventSelection
15877 <item>selection_clear_event
15878 <item>selection_request_event
15879 <item>selection_notify_event
15882 <item> GdkEventProximity
15884 <item>proximity_in_event
15885 <item>proximity_out_event
15888 <item> GdkEventDragBegin
15890 <item>drag_begin_event
15893 <item> GdkEventDragRequest
15895 <item>drag_request_event
15898 <item> GdkEventDropEnter
15900 <item>drop_enter_event
15903 <item> GdkEventDropLeave
15905 <item>drop_leave_event
15908 <item> GdkEventDropDataAvailable
15910 <item>drop_data_available_event
15913 <item> GdkEventClient
15918 <item> GdkEventOther
15924 The data type <tt/GdkEventType/ is a special data type that is used by
15925 all the other data types as an indicator of the data type being passed
15926 to the signal handler. As you will see below, each of the event data
15927 structures has a member of this type. It is defined as an enumeration
15937 GDK_MOTION_NOTIFY = 3,
15938 GDK_BUTTON_PRESS = 4,
15939 GDK_2BUTTON_PRESS = 5,
15940 GDK_3BUTTON_PRESS = 6,
15941 GDK_BUTTON_RELEASE = 7,
15943 GDK_KEY_RELEASE = 9,
15944 GDK_ENTER_NOTIFY = 10,
15945 GDK_LEAVE_NOTIFY = 11,
15946 GDK_FOCUS_CHANGE = 12,
15947 GDK_CONFIGURE = 13,
15950 GDK_PROPERTY_NOTIFY = 16,
15951 GDK_SELECTION_CLEAR = 17,
15952 GDK_SELECTION_REQUEST = 18,
15953 GDK_SELECTION_NOTIFY = 19,
15954 GDK_PROXIMITY_IN = 20,
15955 GDK_PROXIMITY_OUT = 21,
15956 GDK_DRAG_BEGIN = 22,
15957 GDK_DRAG_REQUEST = 23,
15958 GDK_DROP_ENTER = 24,
15959 GDK_DROP_LEAVE = 25,
15960 GDK_DROP_DATA_AVAIL = 26,
15961 GDK_CLIENT_EVENT = 27,
15962 GDK_VISIBILITY_NOTIFY = 28,
15963 GDK_NO_EXPOSE = 29,
15964 GDK_OTHER_EVENT = 9999 /* Deprecated, use filters instead */
15968 The other event type that is different from the others is
15969 <tt/GdkEvent/ itself. This is a union of all the other
15970 data types, which allows it to be cast to a specific
15971 event data type within a signal handler.
15973 <!-- Just a big list for now, needs expanding upon - TRG -->
15974 So, the event data types are defined as follows:
15977 struct _GdkEventAny
15984 struct _GdkEventExpose
15990 gint count; /* If non-zero, how many more events follow. */
15993 struct _GdkEventNoExpose
15998 /* XXX: does anyone need the X major_code or minor_code fields? */
16001 struct _GdkEventVisibility
16006 GdkVisibilityState state;
16009 struct _GdkEventMotion
16022 GdkInputSource source;
16024 gdouble x_root, y_root;
16027 struct _GdkEventButton
16040 GdkInputSource source;
16042 gdouble x_root, y_root;
16045 struct _GdkEventKey
16057 struct _GdkEventCrossing
16062 GdkWindow *subwindow;
16063 GdkNotifyType detail;
16066 struct _GdkEventFocus
16074 struct _GdkEventConfigure
16084 struct _GdkEventProperty
16094 struct _GdkEventSelection
16106 /* This event type will be used pretty rarely. It only is important
16107 for XInput aware programs that are drawing their own cursor */
16109 struct _GdkEventProximity
16115 GdkInputSource source;
16119 struct _GdkEventDragRequest
16127 guint protocol_version:4;
16129 guint willaccept:1;
16130 guint delete_data:1; /* Do *not* delete if link is sent, only
16137 guint8 isdrop; /* This gdk event can be generated by a couple of
16138 X events - this lets the app know whether the
16139 drop really occurred or we just set the data */
16141 GdkPoint drop_coords;
16146 struct _GdkEventDragBegin
16153 guint protocol_version:4;
16160 struct _GdkEventDropEnter
16168 guint protocol_version:4;
16170 guint extended_typelist:1;
16177 struct _GdkEventDropLeave
16185 guint protocol_version:4;
16192 struct _GdkEventDropDataAvailable
16200 guint protocol_version:4;
16206 gchar *data_type; /* MIME type */
16207 gulong data_numbytes;
16213 struct _GdkEventClient
16218 GdkAtom message_type;
16219 gushort data_format;
16227 struct _GdkEventOther
16236 <!-- ***************************************************************** -->
16237 <sect> Code Examples
16238 <!-- ***************************************************************** -->
16240 Below are the code examples that are used in the above text
16241 which are not included in complete form elsewhere.
16243 <!-- ----------------------------------------------------------------- -->
16245 <!-- ----------------------------------------------------------------- -->
16249 /* example-start tictactoe tictactoe.h */
16251 /* GTK - The GTK+ Toolkit
16252 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
16254 * This library is free software; you can redistribute it and/or
16255 * modify it under the terms of the GNU Library General Public
16256 * License as published by the Free Software Foundation; either
16257 * version 2 of the License, or (at your option) any later version.
16259 * This library is distributed in the hope that it will be useful,
16260 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16261 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16262 * Library General Public License for more details.
16264 * You should have received a copy of the GNU Library General Public
16265 * License along with this library; if not, write to the
16266 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16267 * Boston, MA 02111-1307, USA.
16269 #ifndef __TICTACTOE_H__
16270 #define __TICTACTOE_H__
16273 #include <gdk/gdk.h>
16274 #include <gtk/gtkvbox.h>
16279 #endif /* __cplusplus */
16281 #define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
16282 #define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
16283 #define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
16286 typedef struct _Tictactoe Tictactoe;
16287 typedef struct _TictactoeClass TictactoeClass;
16293 GtkWidget *buttons[3][3];
16296 struct _TictactoeClass
16298 GtkVBoxClass parent_class;
16300 void (* tictactoe) (Tictactoe *ttt);
16303 guint tictactoe_get_type (void);
16304 GtkWidget* tictactoe_new (void);
16305 void tictactoe_clear (Tictactoe *ttt);
16309 #endif /* __cplusplus */
16311 #endif /* __TICTACTOE_H__ */
16316 <!-- ----------------------------------------------------------------- -->
16320 /* example-start tictactoe tictactoe.c */
16322 /* GTK - The GTK+ Toolkit
16323 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
16325 * This library is free software; you can redistribute it and/or
16326 * modify it under the terms of the GNU Library General Public
16327 * License as published by the Free Software Foundation; either
16328 * version 2 of the License, or (at your option) any later version.
16330 * This library is distributed in the hope that it will be useful,
16331 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16332 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16333 * Library General Public License for more details.
16335 * You should have received a copy of the GNU Library General Public
16336 * License along with this library; if not, write to the
16337 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16338 * Boston, MA 02111-1307, USA.
16340 #include "gtk/gtksignal.h"
16341 #include "gtk/gtktable.h"
16342 #include "gtk/gtktogglebutton.h"
16343 #include "tictactoe.h"
16350 static void tictactoe_class_init (TictactoeClass *klass);
16351 static void tictactoe_init (Tictactoe *ttt);
16352 static void tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt);
16354 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
16357 tictactoe_get_type ()
16359 static guint ttt_type = 0;
16363 GtkTypeInfo ttt_info =
16366 sizeof (Tictactoe),
16367 sizeof (TictactoeClass),
16368 (GtkClassInitFunc) tictactoe_class_init,
16369 (GtkObjectInitFunc) tictactoe_init,
16370 (GtkArgSetFunc) NULL,
16371 (GtkArgGetFunc) NULL
16374 ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
16381 tictactoe_class_init (TictactoeClass *class)
16383 GtkObjectClass *object_class;
16385 object_class = (GtkObjectClass*) class;
16387 tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
16389 object_class->type,
16390 GTK_SIGNAL_OFFSET (TictactoeClass,
16392 gtk_signal_default_marshaller,
16396 gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
16398 class->tictactoe = NULL;
16402 tictactoe_init (Tictactoe *ttt)
16407 table = gtk_table_new (3, 3, TRUE);
16408 gtk_container_add (GTK_CONTAINER(ttt), table);
16409 gtk_widget_show (table);
16414 ttt->buttons[i][j] = gtk_toggle_button_new ();
16415 gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
16417 gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
16418 GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
16419 gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
16420 gtk_widget_show (ttt->buttons[i][j]);
16427 return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
16431 tictactoe_clear (Tictactoe *ttt)
16438 gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
16439 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
16441 gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
16446 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
16450 static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
16451 { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
16452 { 0, 1, 2 }, { 0, 1, 2 } };
16453 static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
16454 { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
16455 { 0, 1, 2 }, { 2, 1, 0 } };
16457 int success, found;
16459 for (k=0; k<8; k++)
16466 success = success &&
16467 GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
16469 ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
16472 if (success && found)
16474 gtk_signal_emit (GTK_OBJECT (ttt),
16475 tictactoe_signals[TICTACTOE_SIGNAL]);
16484 <!-- ----------------------------------------------------------------- -->
16488 /* example-start tictactoe ttt_test.c */
16490 #include <gtk/gtk.h>
16491 #include "tictactoe.h"
16493 void win( GtkWidget *widget,
16496 g_print ("Yay!\n");
16497 tictactoe_clear (TICTACTOE (widget));
16500 int main( int argc,
16506 gtk_init (&argc, &argv);
16508 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
16510 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
16512 gtk_signal_connect (GTK_OBJECT (window), "destroy",
16513 GTK_SIGNAL_FUNC (gtk_exit), NULL);
16515 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
16517 ttt = tictactoe_new ();
16519 gtk_container_add (GTK_CONTAINER (window), ttt);
16520 gtk_widget_show (ttt);
16522 gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
16523 GTK_SIGNAL_FUNC (win), NULL);
16525 gtk_widget_show (window);
16535 <!-- ----------------------------------------------------------------- -->
16538 <!-- ----------------------------------------------------------------- -->
16542 /* example-start gtkdial gtkdial.h */
16544 /* GTK - The GTK+ Toolkit
16545 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
16547 * This library is free software; you can redistribute it and/or
16548 * modify it under the terms of the GNU Library General Public
16549 * License as published by the Free Software Foundation; either
16550 * version 2 of the License, or (at your option) any later version.
16552 * This library is distributed in the hope that it will be useful,
16553 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16554 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16555 * Library General Public License for more details.
16557 * You should have received a copy of the GNU Library General Public
16558 * License along with this library; if not, write to the
16559 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16560 * Boston, MA 02111-1307, USA.
16562 #ifndef __GTK_DIAL_H__
16563 #define __GTK_DIAL_H__
16566 #include <gdk/gdk.h>
16567 #include <gtk/gtkadjustment.h>
16568 #include <gtk/gtkwidget.h>
16573 #endif /* __cplusplus */
16576 #define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
16577 #define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
16578 #define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
16581 typedef struct _GtkDial GtkDial;
16582 typedef struct _GtkDialClass GtkDialClass;
16588 /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
16591 /* Button currently pressed or 0 if none */
16594 /* Dimensions of dial components */
16596 gint pointer_width;
16598 /* ID of update timer, or 0 if none */
16601 /* Current angle */
16605 /* Old values from adjustment stored so we know when something changes */
16610 /* The adjustment object that stores the data for this dial */
16611 GtkAdjustment *adjustment;
16614 struct _GtkDialClass
16616 GtkWidgetClass parent_class;
16620 GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
16621 guint gtk_dial_get_type (void);
16622 GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
16623 void gtk_dial_set_update_policy (GtkDial *dial,
16624 GtkUpdateType policy);
16626 void gtk_dial_set_adjustment (GtkDial *dial,
16627 GtkAdjustment *adjustment);
16630 #endif /* __cplusplus */
16633 #endif /* __GTK_DIAL_H__ */
16637 <!-- ----------------------------------------------------------------- -->
16641 /* example-start gtkdial gtkdial.c */
16643 /* GTK - The GTK+ Toolkit
16644 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
16646 * This library is free software; you can redistribute it and/or
16647 * modify it under the terms of the GNU Library General Public
16648 * License as published by the Free Software Foundation; either
16649 * version 2 of the License, or (at your option) any later version.
16651 * This library is distributed in the hope that it will be useful,
16652 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16653 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16654 * Library General Public License for more details.
16656 * You should have received a copy of the GNU Library General Public
16657 * License along with this library; if not, write to the
16658 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16659 * Boston, MA 02111-1307, USA.
16663 #include <gtk/gtkmain.h>
16664 #include <gtk/gtksignal.h>
16666 #include "gtkdial.h"
16668 #define SCROLL_DELAY_LENGTH 300
16669 #define DIAL_DEFAULT_SIZE 100
16671 /* Forward declarations */
16673 static void gtk_dial_class_init (GtkDialClass *klass);
16674 static void gtk_dial_init (GtkDial *dial);
16675 static void gtk_dial_destroy (GtkObject *object);
16676 static void gtk_dial_realize (GtkWidget *widget);
16677 static void gtk_dial_size_request (GtkWidget *widget,
16678 GtkRequisition *requisition);
16679 static void gtk_dial_size_allocate (GtkWidget *widget,
16680 GtkAllocation *allocation);
16681 static gint gtk_dial_expose (GtkWidget *widget,
16682 GdkEventExpose *event);
16683 static gint gtk_dial_button_press (GtkWidget *widget,
16684 GdkEventButton *event);
16685 static gint gtk_dial_button_release (GtkWidget *widget,
16686 GdkEventButton *event);
16687 static gint gtk_dial_motion_notify (GtkWidget *widget,
16688 GdkEventMotion *event);
16689 static gint gtk_dial_timer (GtkDial *dial);
16691 static void gtk_dial_update_mouse (GtkDial *dial, gint x, gint y);
16692 static void gtk_dial_update (GtkDial *dial);
16693 static void gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
16695 static void gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
16700 static GtkWidgetClass *parent_class = NULL;
16703 gtk_dial_get_type ()
16705 static guint dial_type = 0;
16709 GtkTypeInfo dial_info =
16713 sizeof (GtkDialClass),
16714 (GtkClassInitFunc) gtk_dial_class_init,
16715 (GtkObjectInitFunc) gtk_dial_init,
16716 (GtkArgSetFunc) NULL,
16717 (GtkArgGetFunc) NULL,
16720 dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info);
16727 gtk_dial_class_init (GtkDialClass *class)
16729 GtkObjectClass *object_class;
16730 GtkWidgetClass *widget_class;
16732 object_class = (GtkObjectClass*) class;
16733 widget_class = (GtkWidgetClass*) class;
16735 parent_class = gtk_type_class (gtk_widget_get_type ());
16737 object_class->destroy = gtk_dial_destroy;
16739 widget_class->realize = gtk_dial_realize;
16740 widget_class->expose_event = gtk_dial_expose;
16741 widget_class->size_request = gtk_dial_size_request;
16742 widget_class->size_allocate = gtk_dial_size_allocate;
16743 widget_class->button_press_event = gtk_dial_button_press;
16744 widget_class->button_release_event = gtk_dial_button_release;
16745 widget_class->motion_notify_event = gtk_dial_motion_notify;
16749 gtk_dial_init (GtkDial *dial)
16752 dial->policy = GTK_UPDATE_CONTINUOUS;
16755 dial->pointer_width = 0;
16757 dial->old_value = 0.0;
16758 dial->old_lower = 0.0;
16759 dial->old_upper = 0.0;
16760 dial->adjustment = NULL;
16764 gtk_dial_new (GtkAdjustment *adjustment)
16768 dial = gtk_type_new (gtk_dial_get_type ());
16771 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
16773 gtk_dial_set_adjustment (dial, adjustment);
16775 return GTK_WIDGET (dial);
16779 gtk_dial_destroy (GtkObject *object)
16783 g_return_if_fail (object != NULL);
16784 g_return_if_fail (GTK_IS_DIAL (object));
16786 dial = GTK_DIAL (object);
16788 if (dial->adjustment)
16789 gtk_object_unref (GTK_OBJECT (dial->adjustment));
16791 if (GTK_OBJECT_CLASS (parent_class)->destroy)
16792 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
16796 gtk_dial_get_adjustment (GtkDial *dial)
16798 g_return_val_if_fail (dial != NULL, NULL);
16799 g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
16801 return dial->adjustment;
16805 gtk_dial_set_update_policy (GtkDial *dial,
16806 GtkUpdateType policy)
16808 g_return_if_fail (dial != NULL);
16809 g_return_if_fail (GTK_IS_DIAL (dial));
16811 dial->policy = policy;
16815 gtk_dial_set_adjustment (GtkDial *dial,
16816 GtkAdjustment *adjustment)
16818 g_return_if_fail (dial != NULL);
16819 g_return_if_fail (GTK_IS_DIAL (dial));
16821 if (dial->adjustment)
16823 gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
16824 gtk_object_unref (GTK_OBJECT (dial->adjustment));
16827 dial->adjustment = adjustment;
16828 gtk_object_ref (GTK_OBJECT (dial->adjustment));
16830 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
16831 (GtkSignalFunc) gtk_dial_adjustment_changed,
16833 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
16834 (GtkSignalFunc) gtk_dial_adjustment_value_changed,
16837 dial->old_value = adjustment->value;
16838 dial->old_lower = adjustment->lower;
16839 dial->old_upper = adjustment->upper;
16841 gtk_dial_update (dial);
16845 gtk_dial_realize (GtkWidget *widget)
16848 GdkWindowAttr attributes;
16849 gint attributes_mask;
16851 g_return_if_fail (widget != NULL);
16852 g_return_if_fail (GTK_IS_DIAL (widget));
16854 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
16855 dial = GTK_DIAL (widget);
16857 attributes.x = widget->allocation.x;
16858 attributes.y = widget->allocation.y;
16859 attributes.width = widget->allocation.width;
16860 attributes.height = widget->allocation.height;
16861 attributes.wclass = GDK_INPUT_OUTPUT;
16862 attributes.window_type = GDK_WINDOW_CHILD;
16863 attributes.event_mask = gtk_widget_get_events (widget) |
16864 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
16865 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
16866 GDK_POINTER_MOTION_HINT_MASK;
16867 attributes.visual = gtk_widget_get_visual (widget);
16868 attributes.colormap = gtk_widget_get_colormap (widget);
16870 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
16871 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
16873 widget->style = gtk_style_attach (widget->style, widget->window);
16875 gdk_window_set_user_data (widget->window, widget);
16877 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
16881 gtk_dial_size_request (GtkWidget *widget,
16882 GtkRequisition *requisition)
16884 requisition->width = DIAL_DEFAULT_SIZE;
16885 requisition->height = DIAL_DEFAULT_SIZE;
16889 gtk_dial_size_allocate (GtkWidget *widget,
16890 GtkAllocation *allocation)
16894 g_return_if_fail (widget != NULL);
16895 g_return_if_fail (GTK_IS_DIAL (widget));
16896 g_return_if_fail (allocation != NULL);
16898 widget->allocation = *allocation;
16899 dial = GTK_DIAL (widget);
16901 if (GTK_WIDGET_REALIZED (widget))
16904 gdk_window_move_resize (widget->window,
16905 allocation->x, allocation->y,
16906 allocation->width, allocation->height);
16909 dial->radius = MIN(allocation->width,allocation->height) * 0.45;
16910 dial->pointer_width = dial->radius / 5;
16914 gtk_dial_expose (GtkWidget *widget,
16915 GdkEventExpose *event)
16918 GdkPoint points[6];
16920 gdouble theta, last, increment;
16921 GtkStyle *blankstyle;
16927 g_return_val_if_fail (widget != NULL, FALSE);
16928 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16929 g_return_val_if_fail (event != NULL, FALSE);
16931 if (event->count > 0)
16934 dial = GTK_DIAL (widget);
16936 /* gdk_window_clear_area (widget->window,
16938 widget->allocation.width,
16939 widget->allocation.height);
16941 xc = widget->allocation.width/2;
16942 yc = widget->allocation.height/2;
16944 upper = dial->adjustment->upper;
16945 lower = dial->adjustment->lower;
16947 /* Erase old pointer */
16949 s = sin(dial->last_angle);
16950 c = cos(dial->last_angle);
16951 dial->last_angle = dial->angle;
16953 points[0].x = xc + s*dial->pointer_width/2;
16954 points[0].y = yc + c*dial->pointer_width/2;
16955 points[1].x = xc + c*dial->radius;
16956 points[1].y = yc - s*dial->radius;
16957 points[2].x = xc - s*dial->pointer_width/2;
16958 points[2].y = yc - c*dial->pointer_width/2;
16959 points[3].x = xc - c*dial->radius/10;
16960 points[3].y = yc + s*dial->radius/10;
16961 points[4].x = points[0].x;
16962 points[4].y = points[0].y;
16964 blankstyle = gtk_style_new ();
16965 blankstyle->bg_gc[GTK_STATE_NORMAL] =
16966 widget->style->bg_gc[GTK_STATE_NORMAL];
16967 blankstyle->dark_gc[GTK_STATE_NORMAL] =
16968 widget->style->bg_gc[GTK_STATE_NORMAL];
16969 blankstyle->light_gc[GTK_STATE_NORMAL] =
16970 widget->style->bg_gc[GTK_STATE_NORMAL];
16971 blankstyle->black_gc =
16972 widget->style->bg_gc[GTK_STATE_NORMAL];
16974 gtk_draw_polygon (blankstyle,
16981 gtk_style_unref(blankstyle);
16986 if ((upper - lower) == 0)
16989 increment = (100*M_PI)/(dial->radius*dial->radius);
16991 inc = (upper - lower);
16993 while (inc < 100) inc *=10;
16994 while (inc >= 1000) inc /=10;
16997 for (i=0; i<=inc; i++)
16999 theta = ((gfloat)i*M_PI/(18*inc/24.) - M_PI/6.);
17001 if ((theta - last) < (increment))
17008 tick_length = (i%(inc/10) == 0) ? dial->pointer_width : dial->pointer_width/2;
17010 gdk_draw_line (widget->window,
17011 widget->style->fg_gc[widget->state],
17012 xc + c*(dial->radius - tick_length),
17013 yc - s*(dial->radius - tick_length),
17014 xc + c*dial->radius,
17015 yc - s*dial->radius);
17020 s = sin(dial->angle);
17021 c = cos(dial->angle);
17022 dial->last_angle = dial->angle;
17024 points[0].x = xc + s*dial->pointer_width/2;
17025 points[0].y = yc + c*dial->pointer_width/2;
17026 points[1].x = xc + c*dial->radius;
17027 points[1].y = yc - s*dial->radius;
17028 points[2].x = xc - s*dial->pointer_width/2;
17029 points[2].y = yc - c*dial->pointer_width/2;
17030 points[3].x = xc - c*dial->radius/10;
17031 points[3].y = yc + s*dial->radius/10;
17032 points[4].x = points[0].x;
17033 points[4].y = points[0].y;
17036 gtk_draw_polygon (widget->style,
17047 gtk_dial_button_press (GtkWidget *widget,
17048 GdkEventButton *event)
17054 double d_perpendicular;
17056 g_return_val_if_fail (widget != NULL, FALSE);
17057 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
17058 g_return_val_if_fail (event != NULL, FALSE);
17060 dial = GTK_DIAL (widget);
17062 /* Determine if button press was within pointer region - we
17063 do this by computing the parallel and perpendicular distance of
17064 the point where the mouse was pressed from the line passing through
17067 dx = event->x - widget->allocation.width / 2;
17068 dy = widget->allocation.height / 2 - event->y;
17070 s = sin(dial->angle);
17071 c = cos(dial->angle);
17073 d_parallel = s*dy + c*dx;
17074 d_perpendicular = fabs(s*dx - c*dy);
17076 if (!dial->button &&
17077 (d_perpendicular < dial->pointer_width/2) &&
17078 (d_parallel > - dial->pointer_width))
17080 gtk_grab_add (widget);
17082 dial->button = event->button;
17084 gtk_dial_update_mouse (dial, event->x, event->y);
17091 gtk_dial_button_release (GtkWidget *widget,
17092 GdkEventButton *event)
17096 g_return_val_if_fail (widget != NULL, FALSE);
17097 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
17098 g_return_val_if_fail (event != NULL, FALSE);
17100 dial = GTK_DIAL (widget);
17102 if (dial->button == event->button)
17104 gtk_grab_remove (widget);
17108 if (dial->policy == GTK_UPDATE_DELAYED)
17109 gtk_timeout_remove (dial->timer);
17111 if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
17112 (dial->old_value != dial->adjustment->value))
17113 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
17120 gtk_dial_motion_notify (GtkWidget *widget,
17121 GdkEventMotion *event)
17124 GdkModifierType mods;
17127 g_return_val_if_fail (widget != NULL, FALSE);
17128 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
17129 g_return_val_if_fail (event != NULL, FALSE);
17131 dial = GTK_DIAL (widget);
17133 if (dial->button != 0)
17138 if (event->is_hint || (event->window != widget->window))
17139 gdk_window_get_pointer (widget->window, &x, &y, &mods);
17141 switch (dial->button)
17144 mask = GDK_BUTTON1_MASK;
17147 mask = GDK_BUTTON2_MASK;
17150 mask = GDK_BUTTON3_MASK;
17157 if (mods & mask)
17158 gtk_dial_update_mouse (dial, x,y);
17165 gtk_dial_timer (GtkDial *dial)
17167 g_return_val_if_fail (dial != NULL, FALSE);
17168 g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
17170 if (dial->policy == GTK_UPDATE_DELAYED)
17171 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
17177 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
17182 g_return_if_fail (dial != NULL);
17183 g_return_if_fail (GTK_IS_DIAL (dial));
17185 xc = GTK_WIDGET(dial)->allocation.width / 2;
17186 yc = GTK_WIDGET(dial)->allocation.height / 2;
17188 old_value = dial->adjustment->value;
17189 dial->angle = atan2(yc-y, x-xc);
17191 if (dial->angle < -M_PI/2.)
17192 dial->angle += 2*M_PI;
17194 if (dial->angle < -M_PI/6)
17195 dial->angle = -M_PI/6;
17197 if (dial->angle > 7.*M_PI/6.)
17198 dial->angle = 7.*M_PI/6.;
17200 dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
17201 (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
17203 if (dial->adjustment->value != old_value)
17205 if (dial->policy == GTK_UPDATE_CONTINUOUS)
17207 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
17211 gtk_widget_draw (GTK_WIDGET(dial), NULL);
17213 if (dial->policy == GTK_UPDATE_DELAYED)
17216 gtk_timeout_remove (dial->timer);
17218 dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
17219 (GtkFunction) gtk_dial_timer,
17227 gtk_dial_update (GtkDial *dial)
17231 g_return_if_fail (dial != NULL);
17232 g_return_if_fail (GTK_IS_DIAL (dial));
17234 new_value = dial->adjustment->value;
17236 if (new_value < dial->adjustment->lower)
17237 new_value = dial->adjustment->lower;
17239 if (new_value > dial->adjustment->upper)
17240 new_value = dial->adjustment->upper;
17242 if (new_value != dial->adjustment->value)
17244 dial->adjustment->value = new_value;
17245 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
17248 dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
17249 (dial->adjustment->upper - dial->adjustment->lower);
17251 gtk_widget_draw (GTK_WIDGET(dial), NULL);
17255 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
17260 g_return_if_fail (adjustment != NULL);
17261 g_return_if_fail (data != NULL);
17263 dial = GTK_DIAL (data);
17265 if ((dial->old_value != adjustment->value) ||
17266 (dial->old_lower != adjustment->lower) ||
17267 (dial->old_upper != adjustment->upper))
17269 gtk_dial_update (dial);
17271 dial->old_value = adjustment->value;
17272 dial->old_lower = adjustment->lower;
17273 dial->old_upper = adjustment->upper;
17278 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
17283 g_return_if_fail (adjustment != NULL);
17284 g_return_if_fail (data != NULL);
17286 dial = GTK_DIAL (data);
17288 if (dial->old_value != adjustment->value)
17290 gtk_dial_update (dial);
17292 dial->old_value = adjustment->value;
17299 <!-- ----------------------------------------------------------------- -->
17300 <sect2> dial_test.c
17304 #include <gtk/gtk.h>
17305 #include "gtkdial.h"
17307 void value_changed( GtkAdjustment *adjustment,
17312 sprintf(buffer,"%4.2f",adjustment->value);
17313 gtk_label_set (GTK_LABEL (label), buffer);
17316 int main( int argc,
17320 GtkAdjustment *adjustment;
17326 gtk_init (&argc, &argv);
17328 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
17330 gtk_window_set_title (GTK_WINDOW (window), "Dial");
17332 gtk_signal_connect (GTK_OBJECT (window), "destroy",
17333 GTK_SIGNAL_FUNC (gtk_exit), NULL);
17335 gtk_container_border_width (GTK_CONTAINER (window), 10);
17337 vbox = gtk_vbox_new (FALSE, 5);
17338 gtk_container_add (GTK_CONTAINER (window), vbox);
17339 gtk_widget_show(vbox);
17341 frame = gtk_frame_new (NULL);
17342 gtk_frame_set_shadow_type (GTK_FRAME(frame), GTK_SHADOW_IN);
17343 gtk_container_add (GTK_CONTAINER (vbox), frame);
17344 gtk_widget_show (frame);
17346 adjustment = GTK_ADJUSTMENT(gtk_adjustment_new (0, 0, 100, 0.01, 0.1, 0));
17348 dial = gtk_dial_new(adjustment);
17349 gtk_dial_set_update_policy (GTK_DIAL(dial), GTK_UPDATE_DELAYED);
17350 /* gtk_widget_set_usize (dial, 100, 100); */
17352 gtk_container_add (GTK_CONTAINER (frame), dial);
17353 gtk_widget_show (dial);
17355 label = gtk_label_new("0.00");
17356 gtk_box_pack_end (GTK_BOX(vbox), label, 0, 0, 0);
17357 gtk_widget_show (label);
17359 gtk_signal_connect (GTK_OBJECT(adjustment), "value_changed",
17360 GTK_SIGNAL_FUNC (value_changed), label);
17362 gtk_widget_show (window);
17371 <!-- ----------------------------------------------------------------- -->
17374 <!-- ----------------------------------------------------------------- -->
17375 <sect2> scribble-simple.c
17378 /* example-start scribble-simple scribble-simple.c */
17380 /* GTK - The GTK+ Toolkit
17381 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
17383 * This library is free software; you can redistribute it and/or
17384 * modify it under the terms of the GNU Library General Public
17385 * License as published by the Free Software Foundation; either
17386 * version 2 of the License, or (at your option) any later version.
17388 * This library is distributed in the hope that it will be useful,
17389 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17390 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17391 * Library General Public License for more details.
17393 * You should have received a copy of the GNU Library General Public
17394 * License along with this library; if not, write to the
17395 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17396 * Boston, MA 02111-1307, USA.
17399 #include <gtk/gtk.h>
17401 /* Backing pixmap for drawing area */
17402 static GdkPixmap *pixmap = NULL;
17404 /* Create a new backing pixmap of the appropriate size */
17405 static gint configure_event( GtkWidget *widget,
17406 GdkEventConfigure *event )
17409 gdk_pixmap_unref(pixmap);
17411 pixmap = gdk_pixmap_new(widget->window,
17412 widget->allocation.width,
17413 widget->allocation.height,
17415 gdk_draw_rectangle (pixmap,
17416 widget->style->white_gc,
17419 widget->allocation.width,
17420 widget->allocation.height);
17425 /* Redraw the screen from the backing pixmap */
17426 static gint expose_event( GtkWidget *widget,
17427 GdkEventExpose *event )
17429 gdk_draw_pixmap(widget->window,
17430 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
17432 event->area.x, event->area.y,
17433 event->area.x, event->area.y,
17434 event->area.width, event->area.height);
17439 /* Draw a rectangle on the screen */
17440 static void draw_brush( GtkWidget *widget,
17444 GdkRectangle update_rect;
17446 update_rect.x = x - 5;
17447 update_rect.y = y - 5;
17448 update_rect.width = 10;
17449 update_rect.height = 10;
17450 gdk_draw_rectangle (pixmap,
17451 widget->style->black_gc,
17453 update_rect.x, update_rect.y,
17454 update_rect.width, update_rect.height);
17455 gtk_widget_draw (widget, &update_rect);
17458 static gint button_press_event( GtkWidget *widget,
17459 GdkEventButton *event )
17461 if (event->button == 1 && pixmap != NULL)
17462 draw_brush (widget, event->x, event->y);
17467 static gint motion_notify_event( GtkWidget *widget,
17468 GdkEventMotion *event )
17471 GdkModifierType state;
17473 if (event->is_hint)
17474 gdk_window_get_pointer (event->window, &x, &y, &state);
17479 state = event->state;
17482 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
17483 draw_brush (widget, x, y);
17493 int main( int argc,
17497 GtkWidget *drawing_area;
17502 gtk_init (&argc, &argv);
17504 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
17505 gtk_widget_set_name (window, "Test Input");
17507 vbox = gtk_vbox_new (FALSE, 0);
17508 gtk_container_add (GTK_CONTAINER (window), vbox);
17509 gtk_widget_show (vbox);
17511 gtk_signal_connect (GTK_OBJECT (window), "destroy",
17512 GTK_SIGNAL_FUNC (quit), NULL);
17514 /* Create the drawing area */
17516 drawing_area = gtk_drawing_area_new ();
17517 gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200);
17518 gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
17520 gtk_widget_show (drawing_area);
17522 /* Signals used to handle backing pixmap */
17524 gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
17525 (GtkSignalFunc) expose_event, NULL);
17526 gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
17527 (GtkSignalFunc) configure_event, NULL);
17529 /* Event signals */
17531 gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
17532 (GtkSignalFunc) motion_notify_event, NULL);
17533 gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
17534 (GtkSignalFunc) button_press_event, NULL);
17536 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
17537 | GDK_LEAVE_NOTIFY_MASK
17538 | GDK_BUTTON_PRESS_MASK
17539 | GDK_POINTER_MOTION_MASK
17540 | GDK_POINTER_MOTION_HINT_MASK);
17542 /* .. And a quit button */
17543 button = gtk_button_new_with_label ("Quit");
17544 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
17546 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
17547 GTK_SIGNAL_FUNC (gtk_widget_destroy),
17548 GTK_OBJECT (window));
17549 gtk_widget_show (button);
17551 gtk_widget_show (window);
17560 <!-- ----------------------------------------------------------------- -->
17561 <sect2> scribble-xinput.c
17564 /* example-start scribble-xinput scribble-xinput.c */
17566 /* GTK - The GTK+ Toolkit
17567 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
17569 * This library is free software; you can redistribute it and/or
17570 * modify it under the terms of the GNU Library General Public
17571 * License as published by the Free Software Foundation; either
17572 * version 2 of the License, or (at your option) any later version.
17574 * This library is distributed in the hope that it will be useful,
17575 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17576 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17577 * Library General Public License for more details.
17579 * You should have received a copy of the GNU Library General Public
17580 * License along with this library; if not, write to the
17581 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17582 * Boston, MA 02111-1307, USA.
17585 #include <gtk/gtk.h>
17587 /* Backing pixmap for drawing area */
17588 static GdkPixmap *pixmap = NULL;
17590 /* Create a new backing pixmap of the appropriate size */
17592 configure_event (GtkWidget *widget, GdkEventConfigure *event)
17595 gdk_pixmap_unref(pixmap);
17597 pixmap = gdk_pixmap_new(widget->window,
17598 widget->allocation.width,
17599 widget->allocation.height,
17601 gdk_draw_rectangle (pixmap,
17602 widget->style->white_gc,
17605 widget->allocation.width,
17606 widget->allocation.height);
17611 /* Redraw the screen from the backing pixmap */
17613 expose_event (GtkWidget *widget, GdkEventExpose *event)
17615 gdk_draw_pixmap(widget->window,
17616 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
17618 event->area.x, event->area.y,
17619 event->area.x, event->area.y,
17620 event->area.width, event->area.height);
17625 /* Draw a rectangle on the screen, size depending on pressure,
17626 and color on the type of device */
17628 draw_brush (GtkWidget *widget, GdkInputSource source,
17629 gdouble x, gdouble y, gdouble pressure)
17632 GdkRectangle update_rect;
17636 case GDK_SOURCE_MOUSE:
17637 gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
17639 case GDK_SOURCE_PEN:
17640 gc = widget->style->black_gc;
17642 case GDK_SOURCE_ERASER:
17643 gc = widget->style->white_gc;
17646 gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
17649 update_rect.x = x - 10 * pressure;
17650 update_rect.y = y - 10 * pressure;
17651 update_rect.width = 20 * pressure;
17652 update_rect.height = 20 * pressure;
17653 gdk_draw_rectangle (pixmap, gc, TRUE,
17654 update_rect.x, update_rect.y,
17655 update_rect.width, update_rect.height);
17656 gtk_widget_draw (widget, &update_rect);
17660 print_button_press (guint32 deviceid)
17664 /* gdk_input_list_devices returns an internal list, so we shouldn't
17665 free it afterwards */
17666 tmp_list = gdk_input_list_devices();
17670 GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
17672 if (info->deviceid == deviceid)
17674 g_print("Button press on device '%s'\n", info->name);
17678 tmp_list = tmp_list->next;
17683 button_press_event (GtkWidget *widget, GdkEventButton *event)
17685 print_button_press (event->deviceid);
17687 if (event->button == 1 && pixmap != NULL)
17688 draw_brush (widget, event->source, event->x, event->y, event->pressure);
17694 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
17698 GdkModifierType state;
17700 if (event->is_hint)
17701 gdk_input_window_get_pointer (event->window, event->deviceid,
17702 &x, &y, &pressure,
17703 NULL, NULL, &state);
17708 pressure = event->pressure;
17709 state = event->state;
17712 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
17713 draw_brush (widget, event->source, x, y, pressure);
17719 input_dialog_destroy (GtkWidget *w, gpointer data)
17721 *((GtkWidget **)data) = NULL;
17725 create_input_dialog ()
17727 static GtkWidget *inputd = NULL;
17731 inputd = gtk_input_dialog_new();
17733 gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
17734 (GtkSignalFunc)input_dialog_destroy, &inputd);
17735 gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
17737 (GtkSignalFunc)gtk_widget_hide,
17738 GTK_OBJECT(inputd));
17739 gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
17741 gtk_widget_show (inputd);
17745 if (!GTK_WIDGET_MAPPED(inputd))
17746 gtk_widget_show(inputd);
17748 gdk_window_raise(inputd->window);
17759 main (int argc, char *argv[])
17762 GtkWidget *drawing_area;
17767 gtk_init (&argc, &argv);
17769 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
17770 gtk_widget_set_name (window, "Test Input");
17772 vbox = gtk_vbox_new (FALSE, 0);
17773 gtk_container_add (GTK_CONTAINER (window), vbox);
17774 gtk_widget_show (vbox);
17776 gtk_signal_connect (GTK_OBJECT (window), "destroy",
17777 GTK_SIGNAL_FUNC (quit), NULL);
17779 /* Create the drawing area */
17781 drawing_area = gtk_drawing_area_new ();
17782 gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200);
17783 gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
17785 gtk_widget_show (drawing_area);
17787 /* Signals used to handle backing pixmap */
17789 gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
17790 (GtkSignalFunc) expose_event, NULL);
17791 gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
17792 (GtkSignalFunc) configure_event, NULL);
17794 /* Event signals */
17796 gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
17797 (GtkSignalFunc) motion_notify_event, NULL);
17798 gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
17799 (GtkSignalFunc) button_press_event, NULL);
17801 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
17802 | GDK_LEAVE_NOTIFY_MASK
17803 | GDK_BUTTON_PRESS_MASK
17804 | GDK_POINTER_MOTION_MASK
17805 | GDK_POINTER_MOTION_HINT_MASK);
17807 /* The following call enables tracking and processing of extension
17808 events for the drawing area */
17809 gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
17811 /* .. And some buttons */
17812 button = gtk_button_new_with_label ("Input Dialog");
17813 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
17815 gtk_signal_connect (GTK_OBJECT (button), "clicked",
17816 GTK_SIGNAL_FUNC (create_input_dialog), NULL);
17817 gtk_widget_show (button);
17819 button = gtk_button_new_with_label ("Quit");
17820 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
17822 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
17823 GTK_SIGNAL_FUNC (gtk_widget_destroy),
17824 GTK_OBJECT (window));
17825 gtk_widget_show (button);
17827 gtk_widget_show (window);
17836 <!-- ***************************************************************** -->
17838 <!-- ***************************************************************** -->
17840 NOTE: The List widget has been superseded by the CList widget. It is
17841 detailed here just for completeness.
17843 The List widget is designed to act as a vertical container for
17844 widgets that should be of the type ListItem.
17846 A List widget has its own window to receive events and its own
17847 background color which is usually white. As it is directly derived
17848 from a Container it can be treated as such by using the
17849 GTK_CONTAINER(List) macro, see the Container widget for more on
17850 this. One should already be familiar with the usage of a GList and
17851 its related functions g_list_*() to be able to use the List widget
17854 There is one field inside the structure definition of the List
17855 widget that will be of greater interest to us, this is:
17862 guint selection_mode;
17867 The selection field of a List points to a linked list of all items
17868 that are currently selected, or NULL if the selection is empty. So to
17869 learn about the current selection we read the GTK_LIST()->selection
17870 field, but do not modify it since the internal fields are maintained
17871 by the gtk_list_*() functions.
17873 The selection_mode of the List determines the selection facilities
17874 of a List and therefore the contents of the GTK_LIST()->selection
17875 field. The selection_mode may be one of the following:
17878 <item> <tt/GTK_SELECTION_SINGLE/ - The selection is either NULL
17879 or contains a GList pointer
17880 for a single selected item.
17882 <item> <tt/GTK_SELECTION_BROWSE/ - The selection is NULL if the list
17883 contains no widgets or insensitive
17884 ones only, otherwise it contains
17885 a GList pointer for one GList
17886 structure, and therefore exactly
17889 <item> <tt/GTK_SELECTION_MULTIPLE/ - The selection is NULL if no list
17890 items are selected or a GList pointer
17891 for the first selected item. That
17892 in turn points to a GList structure
17893 for the second selected item and so
17896 <item> <tt/GTK_SELECTION_EXTENDED/ - The selection is always NULL.
17899 The default is <tt/GTK_SELECTION_MULTIPLE/.
17901 <!-- ----------------------------------------------------------------- -->
17905 void selection_changed( GtkList *list );
17908 This signal will be invoked whenever the selection field of a List
17909 has changed. This happens when a child of thekList got selected or
17913 void select_child( GtkList *list,
17917 This signal is invoked when a child of the List is about to get
17918 selected. This happens mainly on calls to gtk_list_select_item(),
17919 gtk_list_select_child(), button presses and sometimes indirectly
17920 triggered on some else occasions where children get added to or
17921 removed from the List.
17924 void unselect_child( GtkList *list,
17925 GtkWidget *child );
17928 This signal is invoked when a child of the List is about to get
17929 deselected. This happens mainly on calls to gtk_list_unselect_item(),
17930 gtk_list_unselect_child(), button presses and sometimes indirectly
17931 triggered on some else occasions where children get added to or
17932 removed from the List.
17934 <!-- ----------------------------------------------------------------- -->
17938 guint gtk_list_get_type( void );
17941 Returns the "GtkList" type identifier.
17944 GtkWidget *gtk_list_new( void );
17947 Create a new List object. The new widget is returned as a pointer
17948 to a GtkWidget object. NULL is returned on failure.
17951 void gtk_list_insert_items( GtkList *list,
17956 Insert list items into the list, starting at <tt/position/.
17957 <tt/items/ is a doubly linked list where each nodes data pointer is
17958 expected to point to a newly created ListItem. The GList nodes of
17959 <tt/items/ are taken over by the list.
17962 void gtk_list_append_items( GtkList *list,
17966 Insert list items just like gtk_list_insert_items() at the end of the
17967 list. The GList nodes of <tt/items/ are taken over by the list.
17970 void gtk_list_prepend_items( GtkList *list,
17974 Insert list items just like gtk_list_insert_items() at the very
17975 beginning of the list. The GList nodes of <tt/items/ are taken over by
17979 void gtk_list_remove_items( GtkList *list,
17983 Remove list items from the list. <tt/items/ is a doubly linked list
17984 where each nodes data pointer is expected to point to a direct child
17985 of list. It is the callers responsibility to make a call to
17986 g_list_free(items) afterwards. Also the caller has to destroy the list
17990 void gtk_list_clear_items( GtkList *list,
17995 Remove and destroy list items from the list. A widget is affected if
17996 its current position within the list is in the range specified by
17997 <tt/start/ and <tt/end/.
18000 void gtk_list_select_item( GtkList *list,
18004 Invoke the select_child signal for a list item specified through its
18005 current position within the list.
18008 void gtk_list_unselect_item( GtkList *list,
18012 Invoke the unselect_child signal for a list item specified through its
18013 current position within the list.
18016 void gtk_list_select_child( GtkList *list,
18020 Invoke the select_child signal for the specified child.
18023 void gtk_list_unselect_child( GtkList *list,
18027 Invoke the unselect_child signal for the specified child.
18030 gint gtk_list_child_position( GtkList *list,
18034 Return the position of <tt/child/ within the list. "-1" is returned on
18038 void gtk_list_set_selection_mode( GtkList *list,
18039 GtkSelectionMode mode );
18042 Set the selection mode MODE which can be of GTK_SELECTION_SINGLE,
18043 GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE or
18044 GTK_SELECTION_EXTENDED.
18047 GtkList *GTK_LIST( gpointer obj );
18050 Cast a generic pointer to "GtkList *".
18053 GtkListClass *GTK_LIST_CLASS( gpointer class);
18056 Cast a generic pointer to "GtkListClass *".
18059 gint GTK_IS_LIST( gpointer obj);
18062 Determine if a generic pointer refers to a "GtkList" object.
18064 <!-- ----------------------------------------------------------------- -->
18067 Following is an example program that will print out the changes of the
18068 selection of a List, and lets you "arrest" list items into a prison
18069 by selecting them with the rightmost mouse button.
18072 /* example-start list list.c */
18074 /* Include the GTK header files
18075 * Include stdio.h, we need that for the printf() function
18077 #include <gtk/gtk.h>
18080 /* This is our data identification string to store
18081 * data in list items
18083 const gchar *list_item_data_key="list_item_data";
18086 /* prototypes for signal handler that we are going to connect
18087 * to the List widget
18089 static void sigh_print_selection( GtkWidget *gtklist,
18090 gpointer func_data);
18092 static void sigh_button_event( GtkWidget *gtklist,
18093 GdkEventButton *event,
18094 GtkWidget *frame );
18097 /* Main function to set up the user interface */
18099 gint main( int argc,
18102 GtkWidget *separator;
18105 GtkWidget *scrolled_window;
18107 GtkWidget *gtklist;
18109 GtkWidget *list_item;
18115 /* Initialize GTK (and subsequently GDK) */
18117 gtk_init(&argc, &argv);
18120 /* Create a window to put all the widgets in
18121 * connect gtk_main_quit() to the "destroy" event of
18122 * the window to handle window manager close-window-events
18124 window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
18125 gtk_window_set_title(GTK_WINDOW(window), "GtkList Example");
18126 gtk_signal_connect(GTK_OBJECT(window),
18128 GTK_SIGNAL_FUNC(gtk_main_quit),
18132 /* Inside the window we need a box to arrange the widgets
18134 vbox=gtk_vbox_new(FALSE, 5);
18135 gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
18136 gtk_container_add(GTK_CONTAINER(window), vbox);
18137 gtk_widget_show(vbox);
18139 /* This is the scrolled window to put the List widget inside */
18140 scrolled_window=gtk_scrolled_window_new(NULL, NULL);
18141 gtk_widget_set_usize(scrolled_window, 250, 150);
18142 gtk_container_add(GTK_CONTAINER(vbox), scrolled_window);
18143 gtk_widget_show(scrolled_window);
18145 /* Create thekList widget.
18146 * Connect the sigh_print_selection() signal handler
18147 * function to the "selection_changed" signal of the List
18148 * to print out the selected items each time the selection
18150 gtklist=gtk_list_new();
18151 gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(scrolled_window),
18153 gtk_widget_show(gtklist);
18154 gtk_signal_connect(GTK_OBJECT(gtklist),
18155 "selection_changed",
18156 GTK_SIGNAL_FUNC(sigh_print_selection),
18159 /* We create a "Prison" to put a list item in ;) */
18160 frame=gtk_frame_new("Prison");
18161 gtk_widget_set_usize(frame, 200, 50);
18162 gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
18163 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
18164 gtk_container_add(GTK_CONTAINER(vbox), frame);
18165 gtk_widget_show(frame);
18167 /* Connect the sigh_button_event() signal handler to the List
18168 * which will handle the "arresting" of list items
18170 gtk_signal_connect(GTK_OBJECT(gtklist),
18171 "button_release_event",
18172 GTK_SIGNAL_FUNC(sigh_button_event),
18175 /* Create a separator */
18176 separator=gtk_hseparator_new();
18177 gtk_container_add(GTK_CONTAINER(vbox), separator);
18178 gtk_widget_show(separator);
18180 /* Finally create a button and connect its "clicked" signal
18181 * to the destruction of the window */
18182 button=gtk_button_new_with_label("Close");
18183 gtk_container_add(GTK_CONTAINER(vbox), button);
18184 gtk_widget_show(button);
18185 gtk_signal_connect_object(GTK_OBJECT(button),
18187 GTK_SIGNAL_FUNC(gtk_widget_destroy),
18188 GTK_OBJECT(window));
18191 /* Now we create 5 list items, each having its own
18192 * label and add them to the List using gtk_container_add()
18193 * Also we query the text string from the label and
18194 * associate it with the list_item_data_key for each list item
18196 for (i=0; i<5; i++) {
18200 sprintf(buffer, "ListItemContainer with Label #%d", i);
18201 label=gtk_label_new(buffer);
18202 list_item=gtk_list_item_new();
18203 gtk_container_add(GTK_CONTAINER(list_item), label);
18204 gtk_widget_show(label);
18205 gtk_container_add(GTK_CONTAINER(gtklist), list_item);
18206 gtk_widget_show(list_item);
18207 gtk_label_get(GTK_LABEL(label), &string);
18208 gtk_object_set_data(GTK_OBJECT(list_item),
18209 list_item_data_key,
18212 /* Here, we are creating another 5 labels, this time
18213 * we use gtk_list_item_new_with_label() for the creation
18214 * we can't query the text string from the label because
18215 * we don't have the labels pointer and therefore
18216 * we just associate the list_item_data_key of each
18217 * list item with the same text string.
18218 * For adding of the list items we put them all into a doubly
18219 * linked list (GList), and then add them by a single call to
18220 * gtk_list_append_items().
18221 * Because we use g_list_prepend() to put the items into the
18222 * doubly linked list, their order will be descending (instead
18223 * of ascending when using g_list_append())
18226 for (; i<10; i++) {
18227 sprintf(buffer, "List Item with Label %d", i);
18228 list_item=gtk_list_item_new_with_label(buffer);
18229 dlist=g_list_prepend(dlist, list_item);
18230 gtk_widget_show(list_item);
18231 gtk_object_set_data(GTK_OBJECT(list_item),
18232 list_item_data_key,
18233 "ListItem with integrated Label");
18235 gtk_list_append_items(GTK_LIST(gtklist), dlist);
18237 /* Finally we want to see the window, don't we? ;) */
18238 gtk_widget_show(window);
18240 /* Fire up the main event loop of gtk */
18243 /* We get here after gtk_main_quit() has been called which
18244 * happens if the main window gets destroyed
18249 /* This is the signal handler that got connected to button
18250 * press/release events of the List
18252 void sigh_button_event( GtkWidget *gtklist,
18253 GdkEventButton *event,
18256 /* We only do something if the third (rightmost mouse button
18259 if (event->type==GDK_BUTTON_RELEASE &&
18260 event->button==3) {
18261 GList *dlist, *free_list;
18262 GtkWidget *new_prisoner;
18264 /* Fetch the currently selected list item which
18265 * will be our next prisoner ;)
18267 dlist=GTK_LIST(gtklist)->selection;
18269 new_prisoner=GTK_WIDGET(dlist->data);
18273 /* Look for already imprisoned list items, we
18274 * will put them back into the list.
18275 * Remember to free the doubly linked list that
18276 * gtk_container_children() returns
18278 dlist=gtk_container_children(GTK_CONTAINER(frame));
18281 GtkWidget *list_item;
18283 list_item=dlist->data;
18285 gtk_widget_reparent(list_item, gtklist);
18289 g_list_free(free_list);
18291 /* If we have a new prisoner, remove him from the
18292 * List and put him into the frame "Prison".
18293 * We need to unselect the item first.
18295 if (new_prisoner) {
18296 GList static_dlist;
18298 static_dlist.data=new_prisoner;
18299 static_dlist.next=NULL;
18300 static_dlist.prev=NULL;
18302 gtk_list_unselect_child(GTK_LIST(gtklist),
18304 gtk_widget_reparent(new_prisoner, frame);
18309 /* This is the signal handler that gets called if List
18310 * emits the "selection_changed" signal
18312 void sigh_print_selection( GtkWidget *gtklist,
18313 gpointer func_data )
18317 /* Fetch the doubly linked list of selected items
18318 * of the List, remember to treat this as read-only!
18320 dlist=GTK_LIST(gtklist)->selection;
18322 /* If there are no selected items there is nothing more
18323 * to do than just telling the user so
18326 g_print("Selection cleared\n");
18329 /* Ok, we got a selection and so we print it
18331 g_print("The selection is a ");
18333 /* Get the list item from the doubly linked list
18334 * and then query the data associated with list_item_data_key.
18335 * We then just print it */
18337 GtkObject *list_item;
18338 gchar *item_data_string;
18340 list_item=GTK_OBJECT(dlist->data);
18341 item_data_string=gtk_object_get_data(list_item,
18342 list_item_data_key);
18343 g_print("%s ", item_data_string);
18352 <!-- ----------------------------------------------------------------- -->
18353 <sect1> List Item Widget
18355 The ListItem widget is designed to act as a container holding up to
18356 one child, providing functions for selection/deselection just like the
18357 List widget requires them for its children.
18359 A ListItem has its own window to receive events and has its own
18360 background color which is usually white.
18362 As it is directly derived from an Item it can be treated as such by
18363 using the GTK_ITEM(ListItem) macro, see the Item widget for more on
18364 this. Usually a ListItem just holds a label to identify, e.g., a
18365 filename within a List -- therefore the convenience function
18366 gtk_list_item_new_with_label() is provided. The same effect can be
18367 achieved by creating a Label on its own, setting its alignment to
18368 xalign=0 and yalign=0.5 with a subsequent container addition to the
18371 As one is not forced to add a GtkLabel to a GtkListItem, you could
18372 also add a GtkVBox or a GtkArrow etc. to the GtkListItem.
18374 <!-- ----------------------------------------------------------------- -->
18377 AkListItem does not create new signals on its own, but inherits
18378 the signals of a Item.
18380 <!-- ----------------------------------------------------------------- -->
18384 guint gtk_list_item_get_type( void );
18387 Returns the "GtkListItem" type identifier.
18390 GtkWidget *gtk_list_item_new( void );
18393 Create a new ListItem object. The new widget is returned as a
18394 pointer to a GtkWidget object. NULL is returned on failure.
18397 GtkWidget *gtk_list_item_new_with_label( gchar *label );
18400 Create a new ListItem object, having a single GtkLabel as the sole
18401 child. The new widget is returned as a pointer to a GtkWidget
18402 object. NULL is returned on failure.
18405 void gtk_list_item_select( GtkListItem *list_item );
18408 This function is basically a wrapper around a call to gtk_item_select
18409 (GTK_ITEM (list_item)) which will emit the select signal. *Note
18410 GtkItem::, for more info.
18413 void gtk_list_item_deselect( GtkListItem *list_item );
18416 This function is basically a wrapper around a call to
18417 gtk_item_deselect (GTK_ITEM (list_item)) which will emit the deselect
18418 signal. *Note GtkItem::, for more info.
18421 GtkListItem *GTK_LIST_ITEM( gpointer obj );
18424 Cast a generic pointer to "GtkListItem *".
18427 GtkListItemClass *GTK_LIST_ITEM_CLASS( gpointer class );
18430 Cast a generic pointer to GtkListItemClass*. *Note Standard Macros::,
18434 gint GTK_IS_LIST_ITEM( gpointer obj );
18437 Determine if a generic pointer refers to a `GtkListItem' object.
18438 *Note Standard Macros::, for more info.
18440 <!-- ----------------------------------------------------------------- -->
18443 Please see the List example on this, which covers the usage of a