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.1 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>December 13th, 1998
16 <!-- ***************************************************************** -->
18 <!-- ***************************************************************** -->
20 GTK (GIMP Toolkit) was originally developed as a toolkit for the GIMP
21 (General Image Manipulation Program). GTK is built on top of GDK
22 (GIMP Drawing Kit) which is basically a wrapper around the Xlib
23 functions. It's called the GIMP toolkit because it was originally
24 written for developing the GIMP, but has now been used in several free
25 software projects. The authors are:
27 <item> Peter Mattis <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
28 name="petm@xcf.berkeley.edu"></tt>
29 <item> Spencer Kimball <tt><htmlurl url="mailto:spencer@xcf.berkeley.edu"
30 name="spencer@xcf.berkeley.edu"></tt>
31 <item> Josh MacDonald <tt><htmlurl url="mailto:jmacd@xcf.berkeley.edu"
32 name="jmacd@xcf.berkeley.edu"></tt>
35 GTK is essentially an object oriented application programmers
36 interface (API). Although written completely in C, it is implemented
37 using the idea of classes and callback functions (pointers to
40 There is also a third component called glib which contains a few
41 replacements for some standard calls, as well as some additional
42 functions for handling linked lists etc. The replacement functions are
43 used to increase GTK's portability, as some of the functions
44 implemented here are not available or are nonstandard on other unixes
45 such as g_strerror(). Some also contain enhancements to the libc
46 versions, such as g_malloc that has enhanced debugging utilities.
48 This tutorial is an attempt to document as much as possible of GTK, it
49 is by no means complete. This tutorial assumes a good understanding of
50 C, and how to create C programs. It would be a great benefit for the
51 reader to have previous X programming experience, but it shouldn't be
52 necessary. If you are learning GTK as your first widget set, please
53 comment on how you found this tutorial, and what you had trouble
54 with. Note that there is also a C++ API for GTK (GTK--) in the works,
55 so if you prefer to use C++, you should look into this
56 instead. There's also an Objective C wrapper, and Guile bindings
57 available, but I don't follow these.
59 This document is a 'work in progress'. Please look for updates on
60 http://www.gtk.org/ <htmlurl url="http://www.gtk.org/"
61 name="http://www.gtk.org/">.
63 I would very much like to hear of any problems you have learning GTK
64 from this document, and would appreciate input as to how it may be
65 improved. Please see the section on <ref id="sec_Contributing"
66 name="Contributing"> for further information.
68 <!-- ***************************************************************** -->
70 <!-- ***************************************************************** -->
73 The first thing to do of course, is download the GTK source and
74 install it. You can always get the latest version from ftp.gtk.org in
75 /pub/gtk. You can also view other sources of GTK information on
76 http://www.gtk.org/ <htmlurl url="http://www.gtk.org/"
77 name="http://www.gtk.org/">. GTK uses GNU autoconf for configuration.
78 Once untar'd, type ./configure --help to see a list of options.
80 Th GTK source distribution also contains the complete source to all of
81 the examples used in this tutorial, along with Makefiles to aid
84 To begin our introduction to GTK, we'll start with the simplest
85 program possible. This program will create a 200x200 pixel window and
86 has no way of exiting except to be killed using the shell.
89 /* example-start base base.c */
98 gtk_init (&argc, &argv);
100 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
101 gtk_widget_show (window);
110 You can compile the above program with gcc using:
112 gcc base.c -o base `gtk-config --cflags --libs`
115 The meaning of the unusual compilation options is explained below.
117 All programs will of course include gtk/gtk.h which declares the
118 variables, functions, structures etc. that will be used in your GTK
124 gtk_init (&argc, &argv);
127 calls the function gtk_init(gint *argc, gchar ***argv) which will be
128 called in all GTK applications. This sets up a few things for us such
129 as the default visual and color map and then proceeds to call
130 gdk_init(gint *argc, gchar ***argv). This function initializes the
131 library for use, sets up default signal handlers, and checks the
132 arguments passed to your application on the command line, looking for
133 one of the following:
136 <item> <tt/--gtk-module/
137 <item> <tt/--g-fatal-warnings/
138 <item> <tt/--gtk-debug/
139 <item> <tt/--gtk-no-debug/
140 <item> <tt/--gdk-debug/
141 <item> <tt/--gdk-no-debug/
142 <item> <tt/--display/
144 <item> <tt/--no-xshm/
149 It removes these from the argument list, leaving anything it does not
150 recognize for your application to parse or ignore. This creates a set
151 of standard arguments accepted by all GTK applications.
153 The next two lines of code create and display a window.
156 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
157 gtk_widget_show (window);
160 The GTK_WINDOW_TOPLEVEL argument specifies that we want the window to
161 undergo window manager decoration and placement. Rather than create a
162 window of 0x0 size, a window without children is set to 200x200 by
163 default so you can still manipulate it.
165 The gtk_widget_show() function lets GTK know that we are done setting
166 the attributes of this widget, and that it can display it.
168 The last line enters the GTK main processing loop.
174 gtk_main() is another call you will see in every GTK application.
175 When control reaches this point, GTK will sleep waiting for X events
176 (such as button or key presses), timeouts, or file IO notifications to
177 occur. In our simple example however, events are ignored.
179 <!-- ----------------------------------------------------------------- -->
180 <sect1>Hello World in GTK
182 Now for a program with a widget (a button). It's the classic
183 hello world a la GTK.
186 /* example-start helloworld helloworld.c */
190 /* This is a callback function. The data arguments are ignored
191 * in this example. More on callbacks below. */
192 void hello( GtkWidget *widget,
195 g_print ("Hello World\n");
198 gint delete_event( GtkWidget *widget,
202 /* If you return FALSE in the "delete_event" signal handler,
203 * GTK will emit the "destroy" signal. Returning TRUE means
204 * you don't want the window to be destroyed.
205 * This is useful for popping up 'are you sure you want to quit?'
208 g_print ("delete event occurred\n");
210 /* Change TRUE to FALSE and the main window will be destroyed with
211 * a "delete_event". */
216 /* Another callback */
217 void destroy( GtkWidget *widget,
226 /* GtkWidget is the storage type for widgets */
230 /* This is called in all GTK applications. Arguments are parsed
231 * from the command line and are returned to the application. */
232 gtk_init(&argc, &argv);
234 /* create a new window */
235 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
237 /* When the window is given the "delete_event" signal (this is given
238 * by the window manager, usually by the 'close' option, or on the
239 * titlebar), we ask it to call the delete_event () function
240 * as defined above. The data passed to the callback
241 * function is NULL and is ignored in the callback function. */
242 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
243 GTK_SIGNAL_FUNC (delete_event), NULL);
245 /* Here we connect the "destroy" event to a signal handler.
246 * This event occurs when we call gtk_widget_destroy() on the window,
247 * or if we return 'FALSE' in the "delete_event" callback. */
248 gtk_signal_connect (GTK_OBJECT (window), "destroy",
249 GTK_SIGNAL_FUNC (destroy), NULL);
251 /* Sets the border width of the window. */
252 gtk_container_border_width (GTK_CONTAINER (window), 10);
254 /* Creates a new button with the label "Hello World". */
255 button = gtk_button_new_with_label ("Hello World");
257 /* When the button receives the "clicked" signal, it will call the
258 * function hello() passing it NULL as its argument. The hello()
259 * function is defined above. */
260 gtk_signal_connect (GTK_OBJECT (button), "clicked",
261 GTK_SIGNAL_FUNC (hello), NULL);
263 /* This will cause the window to be destroyed by calling
264 * gtk_widget_destroy(window) when "clicked". Again, the destroy
265 * signal could come from here, or the window manager. */
266 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
267 GTK_SIGNAL_FUNC (gtk_widget_destroy),
268 GTK_OBJECT (window));
270 /* This packs the button into the window (a gtk container). */
271 gtk_container_add (GTK_CONTAINER (window), button);
273 /* The final step is to display this newly created widget. */
274 gtk_widget_show (button);
277 gtk_widget_show (window);
279 /* All GTK applications must have a gtk_main(). Control ends here
280 * and waits for an event to occur (like a key press or
289 <!-- ----------------------------------------------------------------- -->
290 <sect1>Compiling Hello World
295 gcc -Wall -g helloworld.c -o helloworld `gtk-config --cflags` \
299 This uses the program <tt>gtk-config</>, which comes with gtk. This
300 program 'knows' what compiler switches are needed to compile programs
301 that use gtk. <tt>gtk-config --cflags</> will output a list of include
302 directories for the compiler to look in, and <tt>gtk-config --libs</>
303 will output the list of libraries for the compiler to link with and
304 the directories to find them in. In the aboce example they could have
305 been combined into a single instance, such as
306 `gtk-config --cflags --libs`.
308 Note that the type of single quote used in the compile command above
311 The libraries that are usually linked in are:
313 <item>The GTK library (-lgtk), the widget library, based on top of GDK.
314 <item>The GDK library (-lgdk), the Xlib wrapper.
315 <item>The gmodule library (-lgmodule), which is used to load run time
317 <item>The glib library (-lglib), containing miscellaneous functions, only
318 g_print() is used in this particular example. GTK is built on top
319 of glib so you will always require this library. See the section on
320 <ref id="sec_glib" name="glib"> for details.
321 <item>The Xlib library (-lX11) which is used by GDK.
322 <item>The Xext library (-lXext). This contains code for shared memory
323 pixmaps and other X extensions.
324 <item>The math library (-lm). This is used by GTK for various purposes.
327 <!-- ----------------------------------------------------------------- -->
328 <sect1>Theory of Signals and Callbacks
330 Before we look in detail at <em>helloworld</em>, we'll discuss signals
331 and callbacks. GTK is an event driven toolkit, which means it will
332 sleep in gtk_main until an event occurs and control is passed to the
333 appropriate function.
335 This passing of control is done using the idea of "signals". When an
336 event occurs, such as the press of a mouse button, the appropriate
337 signal will be "emitted" by the widget that was pressed. This is how
338 GTK does most of its useful work. There are a set of signals that all
339 widgets inherit, such as "destroy", and there are signals that are
340 widget specific, such as "toggled" on a toggle button.
342 To make a button perform an action, we set up a signal handler to
343 catch these signals and call the appropriate function. This is done by
344 using a function such as:
347 gint gtk_signal_connect( GtkObject *object,
350 gpointer func_data );
353 Where the first argument is the widget which will be emitting the
354 signal, and the second, the name of the signal you wish to catch. The
355 third is the function you wish to be called when it is caught, and the
356 fourth, the data you wish to have passed to this function.
358 The function specified in the third argument is called a "callback
359 function", and should generally be of the form:
362 void callback_func( GtkWidget *widget,
363 gpointer callback_data );
366 Where the first argument will be a pointer to the widget that emitted
367 the signal, and the second, a pointer to the data given as the last
368 argument to the gtk_signal_connect() function as shown above.
370 Note that the above form for a signal callback function declaration is
371 only a general guide, as some widget specific signals generate
372 different calling parameters. For example, the GtkCList "select_row"
373 signal provides both row and column parameters.
375 Another call used in the <em>helloworld</em> example, is:
378 gint gtk_signal_connect_object( GtkObject *object,
381 GtkObject *slot_object );
384 gtk_signal_connect_object() is the same as gtk_signal_connect() except
385 that the callback function only uses one argument, a pointer to a GTK
386 object. So when using this function to connect signals, the callback
387 should be of the form:
390 void callback_func( GtkObject *object );
393 Where the object is usually a widget. We usually don't setup callbacks
394 for gtk_signal_connect_object however. They are usually used to call a
395 GTK function that accepts a single widget or object as an argument, as
396 is the case in our <em>helloworld</em> example.
398 The purpose of having two functions to connect signals is simply to
399 allow the callbacks to have a different number of arguments. Many
400 functions in the GTK library accept only a single GtkWidget pointer as
401 an argument, so you want to use the gtk_signal_connect_object() for
402 these, whereas for your functions, you may need to have additional
403 data supplied to the callbacks.
405 <!-- ----------------------------------------------------------------- -->
408 In addition to the signal mechanism described above, there are a set
409 of <em>events</em> that reflect the X event mechanism. Callbacks may
410 also be attached to these events. These events are:
414 <item> button_press_event
415 <item> button_release_event
416 <item> motion_notify_event
420 <item> key_press_event
421 <item> key_release_event
422 <item> enter_notify_event
423 <item> leave_notify_event
424 <item> configure_event
425 <item> focus_in_event
426 <item> focus_out_event
429 <item> property_notify_event
430 <item> selection_clear_event
431 <item> selection_request_event
432 <item> selection_notify_event
433 <item> proximity_in_event
434 <item> proximity_out_event
435 <item> drag_begin_event
436 <item> drag_request_event
437 <item> drag_end_event
438 <item> drop_enter_event
439 <item> drop_leave_event
440 <item> drop_data_available_event
444 In order to connect a callback function to one of these events, you
445 use the function gtk_signal_connect, as described above, using one of
446 the above event names as the <tt/name/ parameter. The callback
447 function for events has a slightly different form than that for
451 void callback_func( GtkWidget *widget,
453 gpointer callback_data );
456 GdkEvent is a C <tt/union/ structure whose type will depend upon which
457 of the above events has occurred. In order for us to tell which event
458 has been issued each of the possible alternatives has a <tt/type/
459 parameter which reflects the event being issued. The other components
460 of the event structure will depend upon the type of the
461 event. Possible values for the type are:
483 GDK_SELECTION_REQUEST
493 GDK_VISIBILITY_NOTIFY
495 GDK_OTHER_EVENT /* Deprecated, use filters instead */
498 So, to connect a callback function to one of these events we would use
502 gtk_signal_connect( GTK_OBJECT(button), "button_press_event",
503 GTK_SIGNAL_FUNC(button_press_callback),
507 This assumes that <tt/button/ is a GtkButton widget. Now, when the
508 mouse is over the button and a mouse button is pressed, the function
509 <tt/button_press_callback/ will be called. This function may be
513 static gint button_press_event (GtkWidget *widget,
514 GdkEventButton *event,
518 Note that we can declare the second argument as type
519 <tt/GdkEventButton/ as we know what type of event will occur for this
520 function to be called.
522 The value returned from this function indicates whether the event
523 should be propagated further by the GTK event handling
524 mechanism. Returning TRUE indicates that the event has been handled,
525 and that it should not propagate further. Returning FALSE continues
526 the normal event handling. See the section on
527 <ref id="sec_Adv_Events_and_Signals"
528 name="Advanced Event and Signal Handling"> for more details on this
531 For details on the GdkEvent data types, see the appendix entitled
532 <ref id="sec_GDK_Event_Types" name="GDK Event Types">.
534 <!-- ----------------------------------------------------------------- -->
535 <sect1>Stepping Through Hello World
537 Now that we know the theory behind this, lets clarify by walking through
538 the example <em>helloworld</em> program.
540 Here is the callback function that will be called when the button is
541 "clicked". We ignore both the widget and the data in this example, but
542 it is not hard to do things with them. The next example will use the
543 data argument to tell us which button was pressed.
546 void hello( GtkWidget *widget,
549 g_print ("Hello World\n");
553 The next callback is a bit special. The "delete_event" occurs when the
554 window manager sends this event to the application. We have a choice
555 here as to what to do about these events. We can ignore them, make
556 some sort of response, or simply quit the application.
558 The value you return in this callback lets GTK know what action to
559 take. By returning TRUE, we let it know that we don't want to have
560 the "destroy" signal emitted, keeping our application running. By
561 returning FALSE, we ask that "destroy" is emitted, which in turn will
562 call our "destroy" signal handler.
565 gint delete_event( GtkWidget *widget,
569 g_print ("delete event occurred\n");
575 Here is another callback function which causes the program to quit by
576 calling gtk_main_quit(). This function tells GTK that it is to exit
577 from gtk_main when control is returned to it.
580 void destroy( GtkWidget *widget,
587 I assume you know about the main() function... yes, as with other
588 applications, all GTK applications will also have one of these.
596 This next part, declares a pointer to a structure of type
597 GtkWidget. These are used below to create a window and a button.
604 Here is our gtk_init again. As before, this initializes the toolkit,
605 and parses the arguments found on the command line. Any argument it
606 recognizes from the command line, it removes from the list, and
607 modifies argc and argv to make it look like they never existed,
608 allowing your application to parse the remaining arguments.
611 gtk_init (&argc, &argv);
614 Create a new window. This is fairly straight forward. Memory is
615 allocated for the GtkWidget *window structure so it now points to a
616 valid structure. It sets up a new window, but it is not displayed
617 until we call gtk_widget_show(window) near the end of our program.
620 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
623 Here is an example of connecting a signal handler to an object, in
624 this case, the window. Here, the "destroy" signal is caught. This is
625 emitted when we use the window manager to kill the window (and we
626 return TRUE in the "delete_event" handler), or when we use the
627 gtk_widget_destroy() call passing in the window widget as the object
628 to destroy. By setting this up, we handle both cases with a single
629 call. Here, it just calls the destroy() function defined above with a
630 NULL argument, which quits GTK for us.
632 The GTK_OBJECT and GTK_SIGNAL_FUNC are macros that perform type
633 casting and checking for us, as well as aid the readability of the
637 gtk_signal_connect (GTK_OBJECT (window), "destroy",
638 GTK_SIGNAL_FUNC (destroy), NULL);
641 This next function is used to set an attribute of a container object.
642 This just sets the window so it has a blank area along the inside of
643 it 10 pixels wide where no widgets will go. There are other similar
644 functions which we will look at in the section on
645 <ref id="sec_setting_widget_attributes" name="Setting Widget Attributes">
647 And again, GTK_CONTAINER is a macro to perform type casting.
650 gtk_container_border_width (GTK_CONTAINER (window), 10);
653 This call creates a new button. It allocates space for a new GtkWidget
654 structure in memory, initializes it, and makes the button pointer
655 point to it. It will have the label "Hello World" on it when
659 button = gtk_button_new_with_label ("Hello World");
662 Here, we take this button, and make it do something useful. We attach
663 a signal handler to it so when it emits the "clicked" signal, our
664 hello() function is called. The data is ignored, so we simply pass in
665 NULL to the hello() callback function. Obviously, the "clicked" signal
666 is emitted when we click the button with our mouse pointer.
669 gtk_signal_connect (GTK_OBJECT (button), "clicked",
670 GTK_SIGNAL_FUNC (hello), NULL);
673 We are also going to use this button to exit our program. This will
674 illustrate how the "destroy" signal may come from either the window
675 manager, or our program. When the button is "clicked", same as above,
676 it calls the first hello() callback function, and then this one in the
677 order they are set up. You may have as many callback functions as you
678 need, and all will be executed in the order you connected
679 them. Because the gtk_widget_destroy() function accepts only a
680 GtkWidget *widget as an argument, we use the
681 gtk_signal_connect_object() function here instead of straight
682 gtk_signal_connect().
685 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
686 GTK_SIGNAL_FUNC (gtk_widget_destroy),
687 GTK_OBJECT (window));
690 This is a packing call, which will be explained in depth later on. But
691 it is fairly easy to understand. It simply tells GTK that the button
692 is to be placed in the window where it will be displayed. Note that a
693 GTK container can only contain one widget. There are other widgets,
694 that are described later, which are designed to layout multiple
695 widgets in various ways.
698 gtk_container_add (GTK_CONTAINER (window), button);
701 Now we have everything set up the way we want it to be. With all the
702 signal handlers in place, and the button placed in the window where it
703 should be, we ask GTK to "show" the widgets on the screen. The window
704 widget is shown last so the whole window will pop up at once rather
705 than seeing the window pop up, and then the button form inside of
706 it. Although with such a simple example, you'd never notice.
709 gtk_widget_show (button);
711 gtk_widget_show (window);
714 And of course, we call gtk_main() which waits for events to come from
715 the X server and will call on the widgets to emit signals when these
722 And the final return. Control returns here after gtk_quit() is called.
728 Now, when we click the mouse button on a GTK button, the widget emits
729 a "clicked" signal. In order for us to use this information, our
730 program sets up a signal handler to catch that signal, which
731 dispatches the function of our choice. In our example, when the button
732 we created is "clicked", the hello() function is called with a NULL
733 argument, and then the next handler for this signal is called. This
734 calls the gtk_widget_destroy() function, passing it the window widget
735 as its argument, destroying the window widget. This causes the window
736 to emit the "destroy" signal, which is caught, and calls our destroy()
737 callback function, which simply exits GTK.
739 Another course of events, is to use the window manager to kill the
740 window. This will cause the "delete_event" to be emitted. This will
741 call our "delete_event" handler. If we return TRUE here, the window
742 will be left as is and nothing will happen. Returning FALSE will cause
743 GTK to emit the "destroy" signal which of course, calls the "destroy"
744 callback, exiting GTK.
746 Note that these signals are not the same as the Unix system signals,
747 and are not implemented using them, although the terminology is almost
750 <!-- ***************************************************************** -->
752 <!-- ***************************************************************** -->
754 <!-- ----------------------------------------------------------------- -->
757 There are a few things you probably noticed in the previous examples
758 that need explaining. The gint, gchar etc. that you see are typedefs
759 to int and char respectively. This is done to get around that nasty
760 dependency on the size of simple data types when doing calculations.
762 A good example is "gint32" which will be typedef'd to a 32 bit integer
763 for any given platform, whether it be the 64 bit alpha, or the 32 bit
764 i386. The typedefs are very straight forward and intuitive. They are
765 all defined in glib/glib.h (which gets included from gtk.h).
767 You'll also notice the ability to use GtkWidget when the function
768 calls for a GtkObject. GTK is an object oriented design, and a widget
771 <!-- ----------------------------------------------------------------- -->
772 <sect1>More on Signal Handlers
774 Lets take another look at the gtk_signal_connect declaration.
777 gint gtk_signal_connect( GtkObject *object,
780 gpointer func_data );
783 Notice the gint return value? This is a tag that identifies your
784 callback function. As stated above, you may have as many callbacks per
785 signal and per object as you need, and each will be executed in turn,
786 in the order they were attached.
788 This tag allows you to remove this callback from the list by using:
791 void gtk_signal_disconnect( GtkObject *object,
795 So, by passing in the widget you wish to remove the handler from, and
796 the tag returned by one of the signal_connect functions, you can
797 disconnect a signal handler.
799 Another function to remove all the signal handers from an object is:
802 void gtk_signal_handlers_destroy( GtkObject *object );
805 This call is fairly self explanatory. It simply removes all the
806 current signal handlers from the object passed in as the first
809 <!-- ----------------------------------------------------------------- -->
810 <sect1>An Upgraded Hello World
812 Let's take a look at a slightly improved <em>helloworld</em> with
813 better examples of callbacks. This will also introduce us to our next
814 topic, packing widgets.
817 /* example-start helloworld2 helloworld2.c */
821 /* Our new improved callback. The data passed to this function
822 * is printed to stdout. */
823 void callback( GtkWidget *widget,
826 g_print ("Hello again - %s was pressed\n", (char *) data);
829 /* another callback */
830 void delete_event( GtkWidget *widget,
840 /* GtkWidget is the storage type for widgets */
845 /* This is called in all GTK applications. Arguments are parsed
846 * from the command line and are returned to the application. */
847 gtk_init (&argc, &argv);
849 /* Create a new window */
850 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
852 /* This is a new call, this just sets the title of our
853 * new window to "Hello Buttons!" */
854 gtk_window_set_title (GTK_WINDOW (window), "Hello Buttons!");
856 /* Here we just set a handler for delete_event that immediately
858 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
859 GTK_SIGNAL_FUNC (delete_event), NULL);
861 /* Sets the border width of the window. */
862 gtk_container_border_width (GTK_CONTAINER (window), 10);
864 /* We create a box to pack widgets into. This is described in detail
865 * in the "packing" section. The box is not really visible, it
866 * is just used as a tool to arrange widgets. */
867 box1 = gtk_hbox_new(FALSE, 0);
869 /* Put the box into the main window. */
870 gtk_container_add (GTK_CONTAINER (window), box1);
872 /* Creates a new button with the label "Button 1". */
873 button = gtk_button_new_with_label ("Button 1");
875 /* Now when the button is clicked, we call the "callback" function
876 * with a pointer to "button 1" as its argument */
877 gtk_signal_connect (GTK_OBJECT (button), "clicked",
878 GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");
880 /* Instead of gtk_container_add, we pack this button into the invisible
881 * box, which has been packed into the window. */
882 gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
884 /* Always remember this step, this tells GTK that our preparation for
885 * this button is complete, and it can now be displayed. */
886 gtk_widget_show(button);
888 /* Do these same steps again to create a second button */
889 button = gtk_button_new_with_label ("Button 2");
891 /* Call the same callback function with a different argument,
892 * passing a pointer to "button 2" instead. */
893 gtk_signal_connect (GTK_OBJECT (button), "clicked",
894 GTK_SIGNAL_FUNC (callback), (gpointer) "button 2");
896 gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
898 /* The order in which we show the buttons is not really important, but I
899 * recommend showing the window last, so it all pops up at once. */
900 gtk_widget_show(button);
902 gtk_widget_show(box1);
904 gtk_widget_show (window);
906 /* Rest in gtk_main and wait for the fun to begin! */
914 Compile this program using the same linking arguments as our first
915 example. You'll notice this time there is no easy way to exit the
916 program, you have to use your window manager or command line to kill
917 it. A good exercise for the reader would be to insert a third "Quit"
918 button that will exit the program. You may also wish to play with the
919 options to gtk_box_pack_start() while reading the next section. Try
920 resizing the window, and observe the behavior.
922 Just as a side note, there is another useful define for
923 gtk_window_new() - GTK_WINDOW_DIALOG. This interacts with the window
924 manager a little differently and should be used for transient windows.
926 <!-- ***************************************************************** -->
927 <sect>Packing Widgets
928 <!-- ***************************************************************** -->
930 When creating an application, you'll want to put more than one widget
931 inside a window. Our first <em>helloworld</em> example only used one
932 widget so we could simply use a gtk_container_add call to "pack" the
933 widget into the window. But when you want to put more than one widget
934 into a window, how do you control where that widget is positioned?
935 This is where packing comes in.
937 <!-- ----------------------------------------------------------------- -->
938 <sect1>Theory of Packing Boxes
940 Most packing is done by creating boxes as in the example above. These
941 are invisible widget containers that we can pack our widgets into
942 which come in two forms, a horizontal box, and a vertical box. When
943 packing widgets into a horizontal box, the objects are inserted
944 horizontally from left to right or right to left depending on the call
945 used. In a vertical box, widgets are packed from top to bottom or vice
946 versa. You may use any combination of boxes inside or beside other
947 boxes to create the desired effect.
949 To create a new horizontal box, we use a call to gtk_hbox_new(), and
950 for vertical boxes, gtk_vbox_new().The gtk_box_pack_start() and
951 gtk_box_pack_end() functions are used to place objects inside of these
952 containers. The gtk_box_pack_start() function will start at the top
953 and work its way down in a vbox, and pack left to right in an hbox.
954 gtk_box_pack_end() will do the opposite, packing from bottom to top in
955 a vbox, and right to left in an hbox. Using these functions allow us
956 to right justify or left justify our widgets and may be mixed in any
957 way to achieve the desired effect. We will use gtk_box_pack_start() in
958 most of our examples. An object may be another container or a
959 widget. In fact, many widgets are actually containers themselves,
960 including the button, but we usually only use a label inside a button.
962 By using these calls, GTK knows where you want to place your widgets
963 so it can do automatic resizing and other nifty things. There's also a
964 number of options as to how your widgets should be packed. As you can
965 imagine, this method gives us a quite a bit of flexibility when
966 placing and creating widgets.
968 <!-- ----------------------------------------------------------------- -->
969 <sect1>Details of Boxes
971 Because of this flexibility, packing boxes in GTK can be confusing at
972 first. There are a lot of options, and it's not immediately obvious how
973 they all fit together. In the end however, there are basically five
978 <IMG SRC="gtk_tut_packbox1.gif" VSPACE="15" HSPACE="10" WIDTH="528"
979 HEIGHT="235" ALT="Box Packing Example Image">
983 Each line contains one horizontal box (hbox) with several buttons. The
984 call to gtk_box_pack is shorthand for the call to pack each of the
985 buttons into the hbox. Each of the buttons is packed into the hbox the
986 same way (i.e. same arguments to the gtk_box_pack_start() function).
988 This is the declaration of the gtk_box_pack_start function.
991 void gtk_box_pack_start( GtkBox *box,
998 The first argument is the box you are packing the object into, the
999 second is the object. The objects will all be buttons for now, so
1000 we'll be packing buttons into boxes.
1002 The expand argument to gtk_box_pack_start() and gtk_box_pack_end()
1003 controls whether the widgets are laid out in the box to fill in all
1004 the extra space in the box so the box is expanded to fill the area
1005 alloted to it (TRUE). Or the box is shrunk to just fit the widgets
1006 (FALSE). Setting expand to FALSE will allow you to do right and left
1007 justification of your widgets. Otherwise, they will all expand to fit
1008 into the box, and the same effect could be achieved by using only one
1009 of gtk_box_pack_start or gtk_box_pack_end.
1011 The fill argument to the gtk_box_pack functions control whether the
1012 extra space is allocated to the objects themselves (TRUE), or as extra
1013 padding in the box around these objects (FALSE). It only has an effect
1014 if the expand argument is also TRUE.
1016 When creating a new box, the function looks like this:
1019 GtkWidget *gtk_hbox_new (gint homogeneous,
1023 The homogeneous argument to gtk_hbox_new (and the same for
1024 gtk_vbox_new) controls whether each object in the box has the same
1025 size (i.e. the same width in an hbox, or the same height in a
1026 vbox). If it is set, the expand argument to the gtk_box_pack routines
1027 is always turned on.
1029 What's the difference between spacing (set when the box is created)
1030 and padding (set when elements are packed)? Spacing is added between
1031 objects, and padding is added on either side of an object. The
1032 following figure should make it clearer:
1036 <IMG ALIGN="center" SRC="gtk_tut_packbox2.gif" WIDTH="509"
1037 HEIGHT="213" VSPACE="15" HSPACE="10"
1038 ALT="Box Packing Example Image">
1042 Here is the code used to create the above images. I've commented it
1043 fairly heavily so hopefully you won't have any problems following
1044 it. Compile it yourself and play with it.
1046 <!-- ----------------------------------------------------------------- -->
1047 <sect1>Packing Demonstration Program
1050 /* example-start packbox packbox.c */
1053 #include "gtk/gtk.h"
1055 void delete_event( GtkWidget *widget,
1062 /* Make a new hbox filled with button-labels. Arguments for the
1063 * variables we're interested are passed in to this function.
1064 * We do not show the box, but do show everything inside. */
1065 GtkWidget *make_box( gint homogeneous,
1075 /* Create a new hbox with the appropriate homogeneous
1076 * and spacing settings */
1077 box = gtk_hbox_new (homogeneous, spacing);
1079 /* Create a series of buttons with the appropriate settings */
1080 button = gtk_button_new_with_label ("gtk_box_pack");
1081 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1082 gtk_widget_show (button);
1084 button = gtk_button_new_with_label ("(box,");
1085 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1086 gtk_widget_show (button);
1088 button = gtk_button_new_with_label ("button,");
1089 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1090 gtk_widget_show (button);
1092 /* Create a button with the label depending on the value of
1095 button = gtk_button_new_with_label ("TRUE,");
1097 button = gtk_button_new_with_label ("FALSE,");
1099 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1100 gtk_widget_show (button);
1102 /* This is the same as the button creation for "expand"
1103 * above, but uses the shorthand form. */
1104 button = gtk_button_new_with_label (fill ? "TRUE," : "FALSE,");
1105 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1106 gtk_widget_show (button);
1108 sprintf (padstr, "%d);", padding);
1110 button = gtk_button_new_with_label (padstr);
1111 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1112 gtk_widget_show (button);
1124 GtkWidget *separator;
1129 /* Our init, don't forget this! :) */
1130 gtk_init (&argc, &argv);
1133 fprintf (stderr, "usage: packbox num, where num is 1, 2, or 3.\n");
1134 /* this just does cleanup in GTK, and exits with an exit status of 1. */
1138 which = atoi (argv[1]);
1140 /* Create our window */
1141 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1143 /* You should always remember to connect the destroy signal to the
1144 * main window. This is very important for proper intuitive
1146 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
1147 GTK_SIGNAL_FUNC (delete_event), NULL);
1148 gtk_container_border_width (GTK_CONTAINER (window), 10);
1150 /* We create a vertical box (vbox) to pack the horizontal boxes into.
1151 * This allows us to stack the horizontal boxes filled with buttons one
1152 * on top of the other in this vbox. */
1153 box1 = gtk_vbox_new (FALSE, 0);
1155 /* which example to show. These correspond to the pictures above. */
1158 /* create a new label. */
1159 label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1161 /* Align the label to the left side. We'll discuss this function and
1162 * others in the section on Widget Attributes. */
1163 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1165 /* Pack the label into the vertical box (vbox box1). Remember that
1166 * widgets added to a vbox will be packed one on top of the other in
1168 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1170 /* Show the label */
1171 gtk_widget_show (label);
1173 /* Call our make box function - homogeneous = FALSE, spacing = 0,
1174 * expand = FALSE, fill = FALSE, padding = 0 */
1175 box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1176 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1177 gtk_widget_show (box2);
1179 /* Call our make box function - homogeneous = FALSE, spacing = 0,
1180 * expand = FALSE, fill = FALSE, padding = 0 */
1181 box2 = make_box (FALSE, 0, TRUE, FALSE, 0);
1182 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1183 gtk_widget_show (box2);
1185 /* Args are: homogeneous, spacing, expand, fill, padding */
1186 box2 = make_box (FALSE, 0, TRUE, TRUE, 0);
1187 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1188 gtk_widget_show (box2);
1190 /* Creates a separator, we'll learn more about these later,
1191 * but they are quite simple. */
1192 separator = gtk_hseparator_new ();
1194 /* Cack the separator into the vbox. Remember each of these
1195 * widgets are being packed into a vbox, so they'll be stacked
1197 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1198 gtk_widget_show (separator);
1200 /* Create another new label, and show it. */
1201 label = gtk_label_new ("gtk_hbox_new (TRUE, 0);");
1202 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1203 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1204 gtk_widget_show (label);
1206 /* Args are: homogeneous, spacing, expand, fill, padding */
1207 box2 = make_box (TRUE, 0, TRUE, FALSE, 0);
1208 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1209 gtk_widget_show (box2);
1211 /* Args are: homogeneous, spacing, expand, fill, padding */
1212 box2 = make_box (TRUE, 0, TRUE, TRUE, 0);
1213 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1214 gtk_widget_show (box2);
1216 /* Another new separator. */
1217 separator = gtk_hseparator_new ();
1218 /* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */
1219 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1220 gtk_widget_show (separator);
1226 /* Create a new label, remember box1 is a vbox as created
1227 * near the beginning of main() */
1228 label = gtk_label_new ("gtk_hbox_new (FALSE, 10);");
1229 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1230 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1231 gtk_widget_show (label);
1233 /* Args are: homogeneous, spacing, expand, fill, padding */
1234 box2 = make_box (FALSE, 10, TRUE, FALSE, 0);
1235 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1236 gtk_widget_show (box2);
1238 /* Args are: homogeneous, spacing, expand, fill, padding */
1239 box2 = make_box (FALSE, 10, TRUE, TRUE, 0);
1240 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1241 gtk_widget_show (box2);
1243 separator = gtk_hseparator_new ();
1244 /* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */
1245 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1246 gtk_widget_show (separator);
1248 label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1249 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1250 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1251 gtk_widget_show (label);
1253 /* Args are: homogeneous, spacing, expand, fill, padding */
1254 box2 = make_box (FALSE, 0, TRUE, FALSE, 10);
1255 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1256 gtk_widget_show (box2);
1258 /* Args are: homogeneous, spacing, expand, fill, padding */
1259 box2 = make_box (FALSE, 0, TRUE, TRUE, 10);
1260 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1261 gtk_widget_show (box2);
1263 separator = gtk_hseparator_new ();
1264 /* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */
1265 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1266 gtk_widget_show (separator);
1271 /* This demonstrates the ability to use gtk_box_pack_end() to
1272 * right justify widgets. First, we create a new box as before. */
1273 box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1275 /* Create the label that will be put at the end. */
1276 label = gtk_label_new ("end");
1277 /* Pack it using gtk_box_pack_end(), so it is put on the right
1278 * side of the hbox created in the make_box() call. */
1279 gtk_box_pack_end (GTK_BOX (box2), label, FALSE, FALSE, 0);
1280 /* Show the label. */
1281 gtk_widget_show (label);
1283 /* Pack box2 into box1 (the vbox remember ? :) */
1284 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1285 gtk_widget_show (box2);
1287 /* A separator for the bottom. */
1288 separator = gtk_hseparator_new ();
1289 /* This explicitly sets the separator to 400 pixels wide by 5 pixels
1290 * high. This is so the hbox we created will also be 400 pixels wide,
1291 * and the "end" label will be separated from the other labels in the
1292 * hbox. Otherwise, all the widgets in the hbox would be packed as
1293 * close together as possible. */
1294 gtk_widget_set_usize (separator, 400, 5);
1295 /* pack the separator into the vbox (box1) created near the start
1297 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1298 gtk_widget_show (separator);
1301 /* Create another new hbox.. remember we can use as many as we need! */
1302 quitbox = gtk_hbox_new (FALSE, 0);
1304 /* Our quit button. */
1305 button = gtk_button_new_with_label ("Quit");
1307 /* Setup the signal to destroy the window. Remember that this will send
1308 * the "destroy" signal to the window which will be caught by our signal
1309 * handler as defined above. */
1310 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
1311 GTK_SIGNAL_FUNC (gtk_main_quit),
1312 GTK_OBJECT (window));
1313 /* Pack the button into the quitbox.
1314 * The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */
1315 gtk_box_pack_start (GTK_BOX (quitbox), button, TRUE, FALSE, 0);
1316 /* pack the quitbox into the vbox (box1) */
1317 gtk_box_pack_start (GTK_BOX (box1), quitbox, FALSE, FALSE, 0);
1319 /* Pack the vbox (box1) which now contains all our widgets, into the
1321 gtk_container_add (GTK_CONTAINER (window), box1);
1323 /* And show everything left */
1324 gtk_widget_show (button);
1325 gtk_widget_show (quitbox);
1327 gtk_widget_show (box1);
1328 /* Showing the window last so everything pops up at once. */
1329 gtk_widget_show (window);
1331 /* And of course, our main function. */
1334 /* Control returns here when gtk_main_quit() is called, but not when
1335 * gtk_exit is used. */
1342 <!-- ----------------------------------------------------------------- -->
1343 <sect1>Packing Using Tables
1345 Let's take a look at another way of packing - Tables. These can be
1346 extremely useful in certain situations.
1348 Using tables, we create a grid that we can place widgets in. The
1349 widgets may take up as many spaces as we specify.
1351 The first thing to look at of course, is the gtk_table_new function:
1354 GtkWidget *gtk_table_new( gint rows,
1359 The first argument is the number of rows to make in the table, while
1360 the second, obviously, is the number of columns.
1362 The homogeneous argument has to do with how the table's boxes are
1363 sized. If homogeneous is TRUE, the table boxes are resized to the size
1364 of the largest widget in the table. If homogeneous is FALSE, the size
1365 of a table boxes is dictated by the tallest widget in its same row,
1366 and the widest widget in its column.
1368 The rows and columns are laid out from 0 to n, where n was the number
1369 specified in the call to gtk_table_new. So, if you specify rows = 2
1370 and columns = 2, the layout would look something like this:
1374 0+----------+----------+
1376 1+----------+----------+
1378 2+----------+----------+
1381 Note that the coordinate system starts in the upper left hand corner.
1382 To place a widget into a box, use the following function:
1385 void gtk_table_attach( GtkTable *table,
1397 Where the first argument ("table") is the table you've created and the
1398 second ("child") the widget you wish to place in the table.
1400 The left and right attach arguments specify where to place the widget,
1401 and how many boxes to use. If you want a button in the lower right
1402 table entry of our 2x2 table, and want it to fill that entry ONLY,
1403 left_attach would be = 1, right_attach = 2, top_attach = 1,
1406 Now, if you wanted a widget to take up the whole top row of our 2x2
1407 table, you'd use left_attach = 0, right_attach = 2, top_attach = 0,
1410 The xoptions and yoptions are used to specify packing options and may
1411 be bitwise OR'ed together to allow multiple options.
1415 <item>GTK_FILL - If the table box is larger than the widget, and
1416 GTK_FILL is specified, the widget will expand to use all the room
1419 <item>GTK_SHRINK - If the table widget was allocated less space then
1420 was requested (usually by the user resizing the window), then the
1421 widgets would normally just be pushed off the bottom of the window and
1422 disappear. If GTK_SHRINK is specified, the widgets will shrink with
1425 <item>GTK_EXPAND - This will cause the table to expand to use up any
1426 remaining space in the window.
1429 Padding is just like in boxes, creating a clear area around the widget
1430 specified in pixels.
1432 gtk_table_attach() has a LOT of options. So, there's a shortcut:
1435 void gtk_table_attach_defaults( GtkTable *table,
1440 gint bottom_attach );
1443 The X and Y options default to GTK_FILL | GTK_EXPAND, and X and Y
1444 padding are set to 0. The rest of the arguments are identical to the
1447 We also have gtk_table_set_row_spacing() and
1448 gtk_table_set_col_spacing(). This places spacing between the rows at
1449 the specified row or column.
1452 void gtk_table_set_row_spacing( GtkTable *table,
1460 void gtk_table_set_col_spacing ( GtkTable *table,
1465 Note that for columns, the space goes to the right of the column, and
1466 for rows, the space goes below the row.
1468 You can also set a consistent spacing of all rows and/or columns with:
1471 void gtk_table_set_row_spacings( GtkTable *table,
1478 void gtk_table_set_col_spacings( GtkTable *table,
1482 Note that with these calls, the last row and last column do not get
1485 <!-- ----------------------------------------------------------------- -->
1486 <sect1>Table Packing Example
1488 Here we make a window with three buttons in a 2x2 table.
1489 The first two buttons will be placed in the upper row.
1490 A third, quit button, is placed in the lower row, spanning both columns.
1491 Which means it should look something like this:
1495 <IMG SRC="gtk_tut_table.gif" VSPACE="15" HSPACE="10"
1496 ALT="Table Packing Example Image" WIDTH="180" HEIGHT="120">
1500 Here's the source code:
1503 /* example-start table table.c */
1505 #include <gtk/gtk.h>
1508 * The data passed to this function is printed to stdout */
1509 void callback( GtkWidget *widget,
1512 g_print ("Hello again - %s was pressed\n", (char *) data);
1515 /* This callback quits the program */
1516 void delete_event( GtkWidget *widget,
1530 gtk_init (&argc, &argv);
1532 /* Create a new window */
1533 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1535 /* Set the window title */
1536 gtk_window_set_title (GTK_WINDOW (window), "Table");
1538 /* Set a handler for delete_event that immediately
1540 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
1541 GTK_SIGNAL_FUNC (delete_event), NULL);
1543 /* Sets the border width of the window. */
1544 gtk_container_border_width (GTK_CONTAINER (window), 20);
1546 /* Create a 2x2 table */
1547 table = gtk_table_new (2, 2, TRUE);
1549 /* Put the table in the main window */
1550 gtk_container_add (GTK_CONTAINER (window), table);
1552 /* Create first button */
1553 button = gtk_button_new_with_label ("button 1");
1555 /* When the button is clicked, we call the "callback" function
1556 * with a pointer to "button 1" as its argument */
1557 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1558 GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");
1561 /* Insert button 1 into the upper left quadrant of the table */
1562 gtk_table_attach_defaults (GTK_TABLE(table), button, 0, 1, 0, 1);
1564 gtk_widget_show (button);
1566 /* Create second button */
1568 button = gtk_button_new_with_label ("button 2");
1570 /* When the button is clicked, we call the "callback" function
1571 * with a pointer to "button 2" as its argument */
1572 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1573 GTK_SIGNAL_FUNC (callback), (gpointer) "button 2");
1574 /* Insert button 2 into the upper right quadrant of the table */
1575 gtk_table_attach_defaults (GTK_TABLE(table), button, 1, 2, 0, 1);
1577 gtk_widget_show (button);
1579 /* Create "Quit" button */
1580 button = gtk_button_new_with_label ("Quit");
1582 /* When the button is clicked, we call the "delete_event" function
1583 * and the program exits */
1584 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1585 GTK_SIGNAL_FUNC (delete_event), NULL);
1587 /* Insert the quit button into the both
1588 * lower quadrants of the table */
1589 gtk_table_attach_defaults (GTK_TABLE(table), button, 0, 2, 1, 2);
1591 gtk_widget_show (button);
1593 gtk_widget_show (table);
1594 gtk_widget_show (window);
1603 <!-- ***************************************************************** -->
1604 <sect>Widget Overview
1605 <!-- ***************************************************************** -->
1607 The general steps to creating a widget in GTK are:
1609 <item> gtk_*_new - one of various functions to create a new widget.
1610 These are all detailed in this section.
1612 <item> Connect all signals and events we wish to use to the
1613 appropriate handlers.
1615 <item> Set the attributes of the widget.
1617 <item> Pack the widget into a container using the appropriate call
1618 such as gtk_container_add() or gtk_box_pack_start().
1620 <item> gtk_widget_show() the widget.
1623 gtk_widget_show() lets GTK know that we are done setting the
1624 attributes of the widget, and it is ready to be displayed. You may
1625 also use gtk_widget_hide to make it disappear again. The order in
1626 which you show the widgets is not important, but I suggest showing the
1627 window last so the whole window pops up at once rather than seeing the
1628 individual widgets come up on the screen as they're formed. The
1629 children of a widget (a window is a widget too) will not be displayed
1630 until the window itself is shown using the gtk_widget_show() function.
1632 <!-- ----------------------------------------------------------------- -->
1635 You'll notice as you go on, that GTK uses a type casting system. This
1636 is always done using macros that both test the ability to cast the
1637 given item, and perform the cast. Some common ones you will see are:
1640 <item> GTK_WIDGET(widget)
1641 <item> GTK_OBJECT(object)
1642 <item> GTK_SIGNAL_FUNC(function)
1643 <item> GTK_CONTAINER(container)
1644 <item> GTK_WINDOW(window)
1648 These are all used to cast arguments in functions. You'll see them in the
1649 examples, and can usually tell when to use them simply by looking at the
1650 function's declaration.
1652 As you can see below in the class hierarchy, all GtkWidgets are
1653 derived from the GtkObject base class. This means you can use a widget
1654 in any place the function asks for an object - simply use the
1660 gtk_signal_connect( GTK_OBJECT(button), "clicked",
1661 GTK_SIGNAL_FUNC(callback_function), callback_data);
1664 This casts the button into an object, and provides a cast for the
1665 function pointer to the callback.
1667 Many widgets are also containers. If you look in the class hierarchy
1668 below, you'll notice that many widgets derive from the GtkContainer
1669 class. Any one of these widgets may be used with the GTK_CONTAINER
1670 macro to pass them to functions that ask for containers.
1672 Unfortunately, these macros are not extensively covered in the
1673 tutorial, but I recommend taking a look through the GTK header
1674 files. It can be very educational. In fact, it's not difficult to
1675 learn how a widget works just by looking at the function declarations.
1677 <!-- ----------------------------------------------------------------- -->
1678 <sect1>Widget Hierarchy
1680 For your reference, here is the class hierarchy tree used to implement widgets.
1687 | | | +GtkAccelLabel
1696 | | | | `GtkAspectFrame
1698 | | | | +GtkToggleButton
1699 | | | | | `GtkCheckButton
1700 | | | | | `GtkRadioButton
1701 | | | | `GtkOptionMenu
1703 | | | | +GtkMenuItem
1704 | | | | | +GtkCheckMenuItem
1705 | | | | | | `GtkRadioMenuItem
1706 | | | | | `GtkTearoffMenuItem
1707 | | | | +GtkListItem
1708 | | | | `GtkTreeItem
1710 | | | | +GtkColorSelectionDialog
1712 | | | | | `GtkInputDialog
1713 | | | | +GtkDrawWindow
1714 | | | | +GtkFileSelection
1715 | | | | +GtkFontSelectionDialog
1719 | | | +GtkScrolledWindow
1723 | | | | +GtkHButtonBox
1724 | | | | `GtkVButtonBox
1726 | | | | +GtkColorSelection
1727 | | | | `GtkGammaCurve
1735 | | | `GtkFontSelection
1754 | | | `GtkSpinButton
1778 <!-- ----------------------------------------------------------------- -->
1779 <sect1>Widgets Without Windows
1781 The following widgets do not have an associated window. If you want to
1782 capture events, you'll have to use the GtkEventBox. See the section on
1783 the <ref id="sec_EventBox" name="EventBox"> widget.
1805 We'll further our exploration of GTK by examining each widget in turn,
1806 creating a few simple functions to display them. Another good source
1807 is the testgtk.c program that comes with GTK. It can be found in
1810 <!-- ***************************************************************** -->
1811 <sect>The Button Widget
1812 <!-- ***************************************************************** -->
1814 <!-- ----------------------------------------------------------------- -->
1815 <sect1>Normal Buttons
1817 We've almost seen all there is to see of the button widget. It's
1818 pretty simple. There are however two ways to create a button. You can
1819 use the gtk_button_new_with_label() to create a button with a label,
1820 or use gtk_button_new() to create a blank button. It's then up to you
1821 to pack a label or pixmap into this new button. To do this, create a
1822 new box, and then pack your objects into this box using the usual
1823 gtk_box_pack_start, and then use gtk_container_add to pack the box
1826 Here's an example of using gtk_button_new to create a button with a
1827 picture and a label in it. I've broken up the code to create a box
1828 from the rest so you can use it in your programs. There are further
1829 examples of using pixmaps later in the tutorial.
1832 /* example-start buttons buttons.c */
1834 #include <gtk/gtk.h>
1836 /* Create a new hbox with an image and a label packed into it
1837 * and return the box. */
1839 GtkWidget *xpm_label_box( GtkWidget *parent,
1840 gchar *xpm_filename,
1845 GtkWidget *pixmapwid;
1850 /* Create box for xpm and label */
1851 box1 = gtk_hbox_new (FALSE, 0);
1852 gtk_container_border_width (GTK_CONTAINER (box1), 2);
1854 /* Get the style of the button to get the
1855 * background color. */
1856 style = gtk_widget_get_style(parent);
1858 /* Now on to the xpm stuff */
1859 pixmap = gdk_pixmap_create_from_xpm (parent->window, &mask,
1860 &style->bg[GTK_STATE_NORMAL],
1862 pixmapwid = gtk_pixmap_new (pixmap, mask);
1864 /* Create a label for the button */
1865 label = gtk_label_new (label_text);
1867 /* Pack the pixmap and label into the box */
1868 gtk_box_pack_start (GTK_BOX (box1),
1869 pixmapwid, FALSE, FALSE, 3);
1871 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 3);
1873 gtk_widget_show(pixmapwid);
1874 gtk_widget_show(label);
1879 /* Our usual callback function */
1880 void callback( GtkWidget *widget,
1883 g_print ("Hello again - %s was pressed\n", (char *) data);
1890 /* GtkWidget is the storage type for widgets */
1895 gtk_init (&argc, &argv);
1897 /* Create a new window */
1898 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1900 gtk_window_set_title (GTK_WINDOW (window), "Pixmap'd Buttons!");
1902 /* It's a good idea to do this for all windows. */
1903 gtk_signal_connect (GTK_OBJECT (window), "destroy",
1904 GTK_SIGNAL_FUNC (gtk_exit), NULL);
1906 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
1907 GTK_SIGNAL_FUNC (gtk_exit), NULL);
1910 /* Sets the border width of the window. */
1911 gtk_container_border_width (GTK_CONTAINER (window), 10);
1912 gtk_widget_realize(window);
1914 /* Create a new button */
1915 button = gtk_button_new ();
1917 /* Connect the "clicked" signal of the button to our callback */
1918 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1919 GTK_SIGNAL_FUNC (callback), (gpointer) "cool button");
1921 /* This calls our box creating function */
1922 box1 = xpm_label_box(window, "info.xpm", "cool button");
1924 /* Pack and show all our widgets */
1925 gtk_widget_show(box1);
1927 gtk_container_add (GTK_CONTAINER (button), box1);
1929 gtk_widget_show(button);
1931 gtk_container_add (GTK_CONTAINER (window), button);
1933 gtk_widget_show (window);
1935 /* Rest in gtk_main and wait for the fun to begin! */
1943 The xpm_label_box function could be used to pack xpm's and labels into
1944 any widget that can be a container.
1946 The Button widget has the following signals:
1956 <!-- ----------------------------------------------------------------- -->
1957 <sect1> Toggle Buttons
1959 Toggle buttons are derived from normal buttons and are very similar,
1960 except they will always be in one of two states, alternated by a
1961 click. They may be depressed, and when you click again, they will pop
1962 back up. Click again, and they will pop back down.
1964 Toggle buttons are the basis for check buttons and radio buttons, as
1965 such, many of the calls used for toggle buttons are inherited by radio
1966 and check buttons. I will point these out when we come to them.
1968 Creating a new toggle button:
1971 GtkWidget *gtk_toggle_button_new( void );
1973 GtkWidget *gtk_toggle_button_new_with_label( gchar *label );
1976 As you can imagine, these work identically to the normal button widget
1977 calls. The first creates a blank toggle button, and the second, a
1978 button with a label widget already packed into it.
1980 To retrieve the state of the toggle widget, including radio and check
1981 buttons, we use a GTK macro as shown in our example below. This tests
1982 the state of the toggle in a callback. The signal of interest emitted
1983 to us by toggle buttons (the toggle button, check button, and radio
1984 button widgets), is the "toggled" signal. To check the state of these
1985 buttons, set up a signal handler to catch the toggled signal, and use
1986 the macro to determine its state. The callback will look something
1990 void toggle_button_callback (GtkWidget *widget, gpointer data)
1992 if (GTK_TOGGLE_BUTTON (widget)->active)
1994 /* If control reaches here, the toggle button is down */
1998 /* If control reaches here, the toggle button is up */
2004 void gtk_toggle_button_set_state( GtkToggleButton *toggle_button,
2008 The above call can be used to set the state of the toggle button, and
2009 its children the radio and check buttons. Passing in your created
2010 button as the first argument, and a TRUE or FALSE for the second state
2011 argument to specify whether it should be down (depressed) or up
2012 (released). Default is up, or FALSE.
2014 Note that when you use the gtk_toggle_button_set_state() function, and
2015 the state is actually changed, it causes the "clicked" signal to be
2016 emitted from the button.
2019 void gtk_toggle_button_toggled (GtkToggleButton *toggle_button);
2022 This simply toggles the button, and emits the "toggled" signal.
2024 <!-- ----------------------------------------------------------------- -->
2025 <sect1> Check Buttons
2027 Check buttons inherent many properties and functions from the the
2028 toggle buttons above, but look a little different. Rather than being
2029 buttons with text inside them, they are small squares with the text to
2030 the right of them. These are often used for toggling options on and
2031 off in applications.
2033 The two creation functions are similar to those of the normal button.
2036 GtkWidget *gtk_check_button_new( void );
2038 GtkWidget *gtk_check_button_new_with_label ( gchar *label );
2041 The new_with_label function creates a check button with a label beside
2044 Checking the state of the check button is identical to that of the
2047 <!-- ----------------------------------------------------------------- -->
2048 <sect1> Radio Buttons <label id="sec_Radio_Buttons">
2050 Radio buttons are similar to check buttons except they are grouped so
2051 that only one may be selected/depressed at a time. This is good for
2052 places in your application where you need to select from a short list
2055 Creating a new radio button is done with one of these calls:
2058 GtkWidget *gtk_radio_button_new( GSList *group );
2060 GtkWidget *gtk_radio_button_new_with_label( GSList *group,
2064 You'll notice the extra argument to these calls. They require a group
2065 to perform their duty properly. The first call to
2066 gtk_radio_button_new_with_label or gtk_radio_button_new_with_label
2067 should pass NULL as the first argument. Then create a group using:
2070 GSList *gtk_radio_button_group( GtkRadioButton *radio_button );
2073 The important thing to remember is that gtk_radio_button_group must be
2074 called for each new button added to the group, with the previous
2075 button passed in as an argument. The result is then passed into the
2076 call to gtk_radio_button_new or gtk_radio_button_new_with_label. This
2077 allows a chain of buttons to be established. The example below should
2080 You can shorten this slightly by using the following syntax, which
2081 removes the need for a variable to hold the list of buttons. This form
2082 is used in the example to create the third button:
2085 button2 = gtk_radio_button_new_with_label(
2086 gtk_radio_button_group (GTK_RADIO_BUTTON (button1)),
2090 It is also a good idea to explicitly set which button should be the
2091 default depressed button with:
2094 void gtk_toggle_button_set_state( GtkToggleButton *toggle_button,
2098 This is described in the section on toggle buttons, and works in
2099 exactly the same way.
2101 The following example creates a radio button group with three buttons.
2104 /* example-start radiobuttons radiobuttons.c */
2106 #include <gtk/gtk.h>
2109 void close_application( GtkWidget *widget,
2119 GtkWidget *window = NULL;
2123 GtkWidget *separator;
2126 gtk_init(&argc,&argv);
2128 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2130 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
2131 GTK_SIGNAL_FUNC(close_application),
2134 gtk_window_set_title (GTK_WINDOW (window), "radio buttons");
2135 gtk_container_border_width (GTK_CONTAINER (window), 0);
2137 box1 = gtk_vbox_new (FALSE, 0);
2138 gtk_container_add (GTK_CONTAINER (window), box1);
2139 gtk_widget_show (box1);
2141 box2 = gtk_vbox_new (FALSE, 10);
2142 gtk_container_border_width (GTK_CONTAINER (box2), 10);
2143 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2144 gtk_widget_show (box2);
2146 button = gtk_radio_button_new_with_label (NULL, "button1");
2147 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2148 gtk_widget_show (button);
2150 group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
2151 button = gtk_radio_button_new_with_label(group, "button2");
2152 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
2153 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2154 gtk_widget_show (button);
2156 button = gtk_radio_button_new_with_label(
2157 gtk_radio_button_group (GTK_RADIO_BUTTON (button)),
2159 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2160 gtk_widget_show (button);
2162 separator = gtk_hseparator_new ();
2163 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
2164 gtk_widget_show (separator);
2166 box2 = gtk_vbox_new (FALSE, 10);
2167 gtk_container_border_width (GTK_CONTAINER (box2), 10);
2168 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
2169 gtk_widget_show (box2);
2171 button = gtk_button_new_with_label ("close");
2172 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2173 GTK_SIGNAL_FUNC(close_application),
2174 GTK_OBJECT (window));
2175 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2176 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
2177 gtk_widget_grab_default (button);
2178 gtk_widget_show (button);
2179 gtk_widget_show (window);
2188 <!-- TODO: check out gtk_radio_button_new_from_widget function - TRG -->
2190 <!-- ***************************************************************** -->
2191 <sect> Adjustments <label id="sec_Adjustment">
2192 <!-- ***************************************************************** -->
2194 GTK+ has various widgets that can be visually adjusted by the user
2195 using the mouse or the keyboard, such as the range widgets, described
2196 in the <ref id="sec_Range_Widgets" name="Range Widgets">
2197 section. There are also a few widgets that display some adjustable
2198 portion of a larger area of data, such as the text widget and the
2201 Obviously, an application needs to be able to react to changes the
2202 user makes in range widgets. One way to do this would be to have each
2203 widget emit its own type of signal when its adjustment changes, and
2204 either pass the new value to the signal handler, or require it to look
2205 inside the widget's data structure in order to ascertain the value.
2206 But you may also want to connect the adjustments of several widgets
2207 together, so that adjusting one adjusts the others. The most obvious
2208 example of this is connecting a scrollbar to a panning viewport or a
2209 scrolling text area. If each widget has its own way of setting or
2210 getting the adjustment value, then the programmer may have to write
2211 their own signal handlers to translate between the output of one
2212 widget's signal and the "input" of another's adjustment setting
2215 GTK+ solves this problem using the GtkAdjustment object, which is a
2216 way for widgets to store and pass adjustment information in an
2217 abstract and flexible form. The most obvious use of GtkAdjustment is
2218 to store the configuration parameters and values of range widgets,
2219 such as scrollbars and scale controls. However, since GtkAdjustments
2220 are derived from GtkObject, they have some special powers beyond those
2221 of normal data structures. Most importantly, they can emit signals,
2222 just like widgets, and these signals can be used not only to allow
2223 your program to react to user input on adjustable widgets, but also to
2224 propagate adjustment values transparently between adjustable widgets.
2226 <sect1> Creating an Adjustment
2228 You create an adjustment using:
2231 GtkObject *gtk_adjustment_new( gfloat value,
2234 gfloat step_increment,
2235 gfloat page_increment,
2239 The <tt/value/ argument is the initial value you want to give to the
2240 adjustment, usually corresponding to the topmost or leftmost position
2241 of an adjustable widget. The <tt/lower/ argument specifies the lowest
2242 value which the adjustment can hold. The <tt/step_increment/ argument
2243 specifies the "smaller" of the two increments by which the user can
2244 change the value, while the <tt/page_increment/ is the "larger" one.
2245 The <tt/page_size/ argument usually corresponds somehow to the visible
2246 area of a panning widget. The <tt/upper/ argument is used to represent
2247 the bottom most or right most coordinate in a panning widget's
2248 child. Therefore it is <em/not/ always the largest number that
2249 <tt/value/ can take, since the <tt/page_size/ of such widgets is
2252 <!-- ----------------------------------------------------------------- -->
2253 <sect1> Using Adjustments the Easy Way
2255 The adjustable widgets can be roughly divided into those which use and
2256 require specific units for these values and those which treat them as
2257 arbitrary numbers. The group which treats the values as arbitrary
2258 numbers includes the range widgets (scrollbars and scales, the
2259 progress bar widget, and the spin button widget). These widgets are
2260 all the widgets which are typically "adjusted" directly by the user
2261 with the mouse or keyboard. They will treat the <tt/lower/ and
2262 <tt/upper/ values of an adjustment as a range within which the user
2263 can manipulate the adjustment's <tt/value/. By default, they will only
2264 modify the <tt/value/ of an adjustment.
2266 The other group includes the text widget, the viewport widget, the
2267 compound list widget, and the scrolled window widget. All of these
2268 widgets use pixel values for their adjustments. These are also all
2269 widgets which are typically "adjusted" indirectly using scrollbars.
2270 While all widgets which use adjustments can either create their own
2271 adjustments or use ones you supply, you'll generally want to let this
2272 particular category of widgets create its own adjustments. Usually,
2273 they will eventually override all the values except the <tt/value/
2274 itself in whatever adjustments you give them, but the results are, in
2275 general, undefined (meaning, you'll have to read the source code to
2276 find out, and it may be different from widget to widget).
2278 Now, you're probably thinking, since text widgets and viewports insist
2279 on setting everything except the <tt/value/ of their adjustments,
2280 while scrollbars will <em/only/ touch the adjustment's <tt/value/, if
2281 you <em/share/ an adjustment object between a scrollbar and a text
2282 widget, manipulating the scrollbar will automagically adjust the text
2283 widget? Of course it will! Just like this:
2286 /* creates its own adjustments */
2287 text = gtk_text_new (NULL, NULL);
2288 /* uses the newly-created adjustment for the scrollbar as well */
2289 vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
2293 <!-- ----------------------------------------------------------------- -->
2294 <sect1> Adjustment Internals
2296 Ok, you say, that's nice, but what if I want to create my own handlers
2297 to respond when the user adjusts a range widget or a spin button, and
2298 how do I get at the value of the adjustment in these handlers? To
2299 answer these questions and more, let's start by taking a look at
2300 <tt>struct _GtkAdjustment</tt> itself:
2303 struct _GtkAdjustment
2310 gfloat step_increment;
2311 gfloat page_increment;
2316 The first thing you should know is that there aren't any handy-dandy
2317 macros or accessor functions for getting the <tt/value/ out of a
2318 GtkAdjustment, so you'll have to (horror of horrors) do it like a
2319 <em/real/ C programmer. Don't worry - the <tt>GTK_ADJUSTMENT
2320 (Object)</tt> macro does run-time type checking (as do all the GTK+
2321 type-casting macros, actually).
2323 Since, when you set the <tt/value/ of an adjustment, you generally
2324 want the change to be reflected by every widget that uses this
2325 adjustment, GTK+ provides this convenience function to do this:
2328 void gtk_adjustment_set_value( GtkAdjustment *adjustment,
2332 As mentioned earlier, GtkAdjustment is a subclass of GtkObject just
2333 like all the various widgets, and thus it is able to emit signals.
2334 This is, of course, why updates happen automagically when you share an
2335 adjustment object between a scrollbar and another adjustable widget;
2336 all adjustable widgets connect signal handlers to their adjustment's
2337 <tt/value_changed/ signal, as can your program. Here's the definition
2338 of this signal in <tt/struct _GtkAdjustmentClass/:
2341 void (* value_changed) (GtkAdjustment *adjustment);
2344 The various widgets that use the GtkAdjustment object will emit this
2345 signal on an adjustment whenever they change its value. This happens
2346 both when user input causes the slider to move on a range widget, as
2347 well as when the program explicitly changes the value with
2348 <tt/gtk_adjustment_set_value()/. So, for example, if you have a scale
2349 widget, and you want to change the rotation of a picture whenever its
2350 value changes, you would create a callback like this:
2353 void cb_rotate_picture (GtkAdjustment *adj, GtkWidget *picture)
2355 set_picture_rotation (picture, adj->value);
2359 and connect it to the scale widget's adjustment like this:
2362 gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
2363 GTK_SIGNAL_FUNC (cb_rotate_picture), picture);
2366 What about when a widget reconfigures the <tt/upper/ or <tt/lower/
2367 fields of its adjustment, such as when a user adds more text to a text
2368 widget? In this case, it emits the <tt/changed/ signal, which looks
2372 void (* changed) (GtkAdjustment *adjustment);
2375 Range widgets typically connect a handler to this signal, which
2376 changes their appearance to reflect the change - for example, the size
2377 of the slider in a scrollbar will grow or shrink in inverse proportion
2378 to the difference between the <tt/lower/ and <tt/upper/ values of its
2381 You probably won't ever need to attach a handler to this signal,
2382 unless you're writing a new type of range widget. However, if you
2383 change any of the values in a GtkAdjustment directly, you should emit
2384 this signal on it to reconfigure whatever widgets are using it, like
2388 gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");
2391 Now go forth and adjust!
2395 <!-- ***************************************************************** -->
2396 <sect> Range Widgets<label id="sec_Range_Widgets">
2397 <!-- ***************************************************************** -->
2400 The category of range widgets includes the ubiquitous scrollbar widget
2401 and the less common "scale" widget. Though these two types of widgets
2402 are generally used for different purposes, they are quite similar in
2403 function and implementation. All range widgets share a set of common
2404 graphic elements, each of which has its own X window and receives
2405 events. They all contain a "trough" and a "slider" (what is sometimes
2406 called a "thumbwheel" in other GUI environments). Dragging the slider
2407 with the pointer moves it back and forth within the trough, while
2408 clicking in the trough advances the slider towards the location of the
2409 click, either completely, or by a designated amount, depending on
2410 which mouse button is used.
2412 As mentioned in <ref id="sec_Adjustment" name="Adjustments"> above,
2413 all range widgets are associated with an adjustment object, from which
2414 they calculate the length of the slider and it's position within the
2415 trough. When the user manipulates the slider, the range widget will
2416 change the value of the adjustment.
2418 <!-- ----------------------------------------------------------------- -->
2419 <sect1> Scrollbar Widgets
2421 These are your standard, run-of-the-mill scrollbars. These should be
2422 used only for scrolling some other widget, such as a list, a text box,
2423 or a viewport (and it's generally easier to use the scrolled window
2424 widget in most cases). For other purposes, you should use scale
2425 widgets, as they are friendlier and more featureful.
2427 There are separate types for horizontal and vertical scrollbars.
2428 There really isn't much to say about these. You create them with the
2429 following functions, defined in <tt><gtk/gtkhscrollbar.h></tt>
2430 and <tt><gtk/gtkvscrollbar.h></tt>:
2433 GtkWidget *gtk_hscrollbar_new( GtkAdjustment *adjustment );
2435 GtkWidget *gtk_vscrollbar_new( GtkAdjustment *adjustment );
2438 and that's about it (if you don't believe me, look in the header
2439 files!). The <tt/adjustment/ argument can either be a pointer to an
2440 existing GtkAdjustment, or NULL, in which case one will be created for
2441 you. Specifying NULL might actually be useful in this case, if you
2442 wish to pass the newly-created adjustment to the constructor function
2443 of some other widget which will configure it for you, such as a text
2447 <!-- ----------------------------------------------------------------- -->
2448 <sect1> Scale Widgets
2450 Scale widgets are used to allow the user to visually select and
2451 manipulate a value within a specific range. You might want to use a
2452 scale widget, for example, to adjust the magnification level on a
2453 zoomed preview of a picture, or to control the brightness of a colour,
2454 or to specify the number of minutes of inactivity before a screensaver
2455 takes over the screen.
2457 <!-- ----------------------------------------------------------------- -->
2458 <sect2>Creating a Scale Widget
2460 As with scrollbars, there are separate widget types for horizontal and
2461 vertical scale widgets. (Most programmers seem to favour horizontal
2462 scale widgets). Since they work essentially the same way, there's no
2463 need to treat them separately here. The following functions, defined
2464 in <tt><gtk/gtkvscale.h></tt> and
2465 <tt><gtk/gtkhscale.h></tt>, create vertical and horizontal scale
2466 widgets, respectively:
2470 GtkWidget *gtk_vscale_new( GtkAdjustment *adjustment );
2472 GtkWidget *gtk_hscale_new( GtkAdjustment *adjustment );
2476 The <tt/adjustment/ argument can either be an adjustment which has
2477 already been created with <tt/gtk_adjustment_new()/, or <tt/NULL/, in
2478 which case, an anonymous GtkAdjustment is created with all of its
2479 values set to <tt/0.0/ (which isn't very useful in this case). In
2480 order to avoid confusing yourself, you probably want to create your
2481 adjustment with a <tt/page_size/ of <tt/0.0/ so that its <tt/upper/
2482 value actually corresponds to the highest value the user can select.
2483 (If you're <em/already/ thoroughly confused, read the section on <ref
2484 id="sec_Adjustment" name="Adjustments"> again for an explanation of
2485 what exactly adjustments do and how to create and manipulate them).
2487 <!-- ----------------------------------------------------------------- -->
2488 <sect2> Functions and Signals (well, functions, at least)
2490 Scale widgets can display their current value as a number beside the
2491 trough. The default behaviour is to show the value, but you can change
2492 this with this function:
2495 void gtk_scale_set_draw_value( GtkScale *scale,
2499 As you might have guessed, <tt/draw_value/ is either <tt/TRUE/ or
2500 <tt/FALSE/, with predictable consequences for either one.
2502 The value displayed by a scale widget is rounded to one decimal point
2503 by default, as is the <tt/value/ field in its GtkAdjustment. You can
2508 void gtk_scale_set_digits( GtkScale *scale,
2513 where <tt/digits/ is the number of decimal places you want. You can
2514 set <tt/digits/ to anything you like, but no more than 13 decimal
2515 places will actually be drawn on screen.
2517 Finally, the value can be drawn in different positions
2518 relative to the trough:
2522 void gtk_scale_set_value_pos( GtkScale *scale,
2523 GtkPositionType pos );
2527 The argument <tt/pos/ is of type <tt>GtkPositionType</tt>, which is
2528 defined in <tt><gtk/gtkenums.h></tt>, and can take one of the
2533 <item> GTK_POS_RIGHT
2535 <item> GTK_POS_BOTTOM
2538 If you position the value on the "side" of the trough (e.g. on the top
2539 or bottom of a horizontal scale widget), then it will follow the
2540 slider up and down the trough.
2542 All the preceding functions are defined in
2543 <tt><gtk/gtkscale.h></tt>.
2547 <!-- ----------------------------------------------------------------- -->
2548 <sect1> Common Functions <label id="sec_Range_Functions">
2550 The GtkRange widget class is fairly complicated internally, but, like
2551 all the "base class" widgets, most of its complexity is only
2552 interesting if you want to hack on it. Also, almost all of the
2553 functions and signals it defines are only really used in writing
2554 derived widgets. There are, however, a few useful functions that are
2555 defined in <tt><gtk/gtkrange.h></tt> and will work on all range
2558 <!-- ----------------------------------------------------------------- -->
2559 <sect2> Setting the Update Policy
2561 The "update policy" of a range widget defines at what points during
2562 user interaction it will change the <tt/value/ field of its
2563 GtkAdjustment and emit the "value_changed" signal on this
2564 GtkAdjustment. The update policies, defined in
2565 <tt><gtk/gtkenums.h></tt> as type <tt>enum GtkUpdateType</tt>,
2569 <item>GTK_UPDATE_POLICY_CONTINUOUS - This is the default. The
2570 "value_changed" signal is emitted continuously, i.e. whenever the
2571 slider is moved by even the tiniest amount.
2573 <item>GTK_UPDATE_POLICY_DISCONTINUOUS - The "value_changed" signal is
2574 only emitted once the slider has stopped moving and the user has
2575 released the mouse button.
2577 <item>GTK_UPDATE_POLICY_DELAYED - The "value_change" signal is emitted
2578 when the user releases the mouse button, or if the slider stops moving
2579 for a short period of time.
2583 The update policy of a range widget can be set by casting it using the
2584 <tt>GTK_RANGE (Widget)</tt> macro and passing it to this function:
2587 void gtk_range_set_update_policy( GtkRange *range,
2588 GtkUpdateType policy) ;
2591 <!-- ----------------------------------------------------------------- -->
2592 <sect2>Getting and Setting Adjustments
2594 Getting and setting the adjustment for a range widget "on the fly" is
2595 done, predictably, with:
2598 GtkAdjustment* gtk_range_get_adjustment( GtkRange *range );
2600 void gtk_range_set_adjustment( GtkRange *range,
2601 GtkAdjustment *adjustment );
2604 <tt/gtk_range_get_adjustment()/ returns a pointer to the adjustment to
2605 which <tt/range/ is connected.
2607 <tt/gtk_range_set_adjustment()/ does absolutely nothing if you pass it
2608 the adjustment that <tt/range/ is already using, regardless of whether
2609 you changed any of its fields or not. If you pass it a new
2610 GtkAdjustment, it will unreference the old one if it exists (possibly
2611 destroying it), connect the appropriate signals to the new one, and
2612 call the private function <tt/gtk_range_adjustment_changed()/, which
2613 will (or at least, is supposed to...) recalculate the size and/or
2614 position of the slider and redraw if necessary. As mentioned in the
2615 section on adjustments, if you wish to reuse the same GtkAdjustment,
2616 when you modify its values directly, you should emit the "changed"
2617 signal on it, like this:
2620 gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");
2625 <!-- ----------------------------------------------------------------- -->
2626 <sect1> Key and Mouse bindings
2628 All of the GTK+ range widgets react to mouse clicks in more or less
2629 the same way. Clicking button-1 in the trough will cause its
2630 adjustment's <tt/page_increment/ to be added or subtracted from its
2631 <tt/value/, and the slider to be moved accordingly. Clicking mouse
2632 button-2 in the trough will jump the slider to the point at which the
2633 button was clicked. Clicking any button on a scrollbar's arrows will
2634 cause its adjustment's value to change <tt/step_increment/ at a time.
2636 It may take a little while to get used to, but by default, scrollbars
2637 as well as scale widgets can take the keyboard focus in GTK+. If you
2638 think your users will find this too confusing, you can always disable
2639 this by unsetting the GTK_CAN_FOCUS flag on the scrollbar, like this:
2642 GTK_WIDGET_UNSET_FLAGS (scrollbar, GTK_CAN_FOCUS);
2645 The key bindings (which are, of course, only active when the widget
2646 has focus) are slightly different between horizontal and vertical
2647 range widgets, for obvious reasons. They are also not quite the same
2648 for scale widgets as they are for scrollbars, for somewhat less
2649 obvious reasons (possibly to avoid confusion between the keys for
2650 horizontal and vertical scrollbars in scrolled windows, where both
2651 operate on the same area).
2653 <sect2> Vertical Range Widgets
2655 All vertical range widgets can be operated with the up and down arrow
2656 keys, as well as with the <tt/Page Up/ and <tt/Page Down/ keys. The
2657 arrows move the slider up and down by <tt/step_increment/, while
2658 <tt/Page Up/ and <tt/Page Down/ move it by <tt/page_increment/.
2660 The user can also move the slider all the way to one end or the other
2661 of the trough using the keyboard. With the GtkVScale widget, this is
2662 done with the <tt/Home/ and <tt/End/ keys, whereas with the
2663 GtkVScrollbar widget, this is done by typing <tt>Control-Page Up</tt>
2664 and <tt>Control-Page Down</tt>.
2666 <!-- ----------------------------------------------------------------- -->
2667 <sect2> Horizontal Range Widgets
2669 The left and right arrow keys work as you might expect in these
2670 widgets, moving the slider back and forth by <tt/step_increment/. The
2671 <tt/Home/ and <tt/End/ keys move the slider to the ends of the trough.
2672 For the GtkHScale widget, moving the slider by <tt/page_increment/ is
2673 accomplished with <tt>Control-Left</tt> and <tt>Control-Right</tt>,
2674 while for GtkHScrollbar, it's done with <tt>Control-Home</tt> and
2675 <tt>Control-End</tt>.
2679 <!-- ----------------------------------------------------------------- -->
2680 <sect1> Example<label id="sec_Range_Example">
2682 This example is a somewhat modified version of the "range controls"
2683 test from <tt/testgtk.c/. It basically puts up a window with three
2684 range widgets all connected to the same adjustment, and a couple of
2685 controls for adjusting some of the parameters mentioned above and in
2686 the seciton on adjustments, so you can see how they affect the way
2687 these widgets work for the user.
2690 /* example-start rangewidgets rangewidgets.c */
2692 #include <gtk/gtk.h>
2694 GtkWidget *hscale, *vscale;
2696 void cb_pos_menu_select( GtkWidget *item,
2697 GtkPositionType pos )
2699 /* Set the value position on both scale widgets */
2700 gtk_scale_set_value_pos (GTK_SCALE (hscale), pos);
2701 gtk_scale_set_value_pos (GTK_SCALE (vscale), pos);
2704 void cb_update_menu_select( GtkWidget *item,
2705 GtkUpdateType policy )
2707 /* Set the update policy for both scale widgets */
2708 gtk_range_set_update_policy (GTK_RANGE (hscale), policy);
2709 gtk_range_set_update_policy (GTK_RANGE (vscale), policy);
2712 void cb_digits_scale( GtkAdjustment *adj )
2714 /* Set the number of decimal places to which adj->value is rounded */
2715 gtk_scale_set_digits (GTK_SCALE (hscale), (gint) adj->value);
2716 gtk_scale_set_digits (GTK_SCALE (vscale), (gint) adj->value);
2719 void cb_page_size( GtkAdjustment *get,
2720 GtkAdjustment *set )
2722 /* Set the page size and page increment size of the sample
2723 * adjustment to the value specified by the "Page Size" scale */
2724 set->page_size = get->value;
2725 set->page_increment = get->value;
2726 /* Now emit the "changed" signal to reconfigure all the widgets that
2727 * are attached to this adjustment */
2728 gtk_signal_emit_by_name (GTK_OBJECT (set), "changed");
2731 void cb_draw_value( GtkToggleButton *button )
2733 /* Turn the value display on the scale widgets off or on depending
2734 * on the state of the checkbutton */
2735 gtk_scale_set_draw_value (GTK_SCALE (hscale), button->active);
2736 gtk_scale_set_draw_value (GTK_SCALE (vscale), button->active);
2739 /* Convenience functions */
2741 GtkWidget *make_menu_item( gchar *name,
2742 GtkSignalFunc callback,
2747 item = gtk_menu_item_new_with_label (name);
2748 gtk_signal_connect (GTK_OBJECT (item), "activate",
2750 gtk_widget_show (item);
2755 void scale_set_default_values( GtkScale *scale )
2757 gtk_range_set_update_policy (GTK_RANGE (scale),
2758 GTK_UPDATE_CONTINUOUS);
2759 gtk_scale_set_digits (scale, 1);
2760 gtk_scale_set_value_pos (scale, GTK_POS_TOP);
2761 gtk_scale_set_draw_value (scale, TRUE);
2764 /* makes the sample window */
2766 void create_range_controls( void )
2769 GtkWidget *box1, *box2, *box3;
2771 GtkWidget *scrollbar;
2772 GtkWidget *separator;
2773 GtkWidget *opt, *menu, *item;
2776 GtkObject *adj1, *adj2;
2778 /* Standard window-creating stuff */
2779 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2780 gtk_signal_connect (GTK_OBJECT (window), "destroy",
2781 GTK_SIGNAL_FUNC(gtk_main_quit),
2783 gtk_window_set_title (GTK_WINDOW (window), "range controls");
2785 box1 = gtk_vbox_new (FALSE, 0);
2786 gtk_container_add (GTK_CONTAINER (window), box1);
2787 gtk_widget_show (box1);
2789 box2 = gtk_hbox_new (FALSE, 10);
2790 gtk_container_border_width (GTK_CONTAINER (box2), 10);
2791 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2792 gtk_widget_show (box2);
2794 /* calue, lower, upper, step_increment, page_increment, page_size */
2795 /* Note that the page_size value only makes a difference for
2796 * scrollbar widgets, and the highest value you'll get is actually
2797 * (upper - page_size). */
2798 adj1 = gtk_adjustment_new (0.0, 0.0, 101.0, 0.1, 1.0, 1.0);
2800 vscale = gtk_vscale_new (GTK_ADJUSTMENT (adj1));
2801 scale_set_default_values (GTK_SCALE (vscale));
2802 gtk_box_pack_start (GTK_BOX (box2), vscale, TRUE, TRUE, 0);
2803 gtk_widget_show (vscale);
2805 box3 = gtk_vbox_new (FALSE, 10);
2806 gtk_box_pack_start (GTK_BOX (box2), box3, TRUE, TRUE, 0);
2807 gtk_widget_show (box3);
2809 /* Reuse the same adjustment */
2810 hscale = gtk_hscale_new (GTK_ADJUSTMENT (adj1));
2811 gtk_widget_set_usize (GTK_WIDGET (hscale), 200, 30);
2812 scale_set_default_values (GTK_SCALE (hscale));
2813 gtk_box_pack_start (GTK_BOX (box3), hscale, TRUE, TRUE, 0);
2814 gtk_widget_show (hscale);
2816 /* Reuse the same adjustment again */
2817 scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adj1));
2818 /* Notice how this causes the scales to always be updated
2819 * continuously when the scrollbar is moved */
2820 gtk_range_set_update_policy (GTK_RANGE (scrollbar),
2821 GTK_UPDATE_CONTINUOUS);
2822 gtk_box_pack_start (GTK_BOX (box3), scrollbar, TRUE, TRUE, 0);
2823 gtk_widget_show (scrollbar);
2825 box2 = gtk_hbox_new (FALSE, 10);
2826 gtk_container_border_width (GTK_CONTAINER (box2), 10);
2827 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2828 gtk_widget_show (box2);
2830 /* A checkbutton to control whether the value is displayed or not */
2831 button = gtk_check_button_new_with_label("Display value on scale widgets");
2832 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
2833 gtk_signal_connect (GTK_OBJECT (button), "toggled",
2834 GTK_SIGNAL_FUNC(cb_draw_value), NULL);
2835 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2836 gtk_widget_show (button);
2838 box2 = gtk_hbox_new (FALSE, 10);
2839 gtk_container_border_width (GTK_CONTAINER (box2), 10);
2841 /* An option menu to change the position of the value */
2842 label = gtk_label_new ("Scale Value Position:");
2843 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
2844 gtk_widget_show (label);
2846 opt = gtk_option_menu_new();
2847 menu = gtk_menu_new();
2849 item = make_menu_item ("Top",
2850 GTK_SIGNAL_FUNC(cb_pos_menu_select),
2851 GINT_TO_POINTER (GTK_POS_TOP));
2852 gtk_menu_append (GTK_MENU (menu), item);
2854 item = make_menu_item ("Bottom", GTK_SIGNAL_FUNC (cb_pos_menu_select),
2855 GINT_TO_POINTER (GTK_POS_BOTTOM));
2856 gtk_menu_append (GTK_MENU (menu), item);
2858 item = make_menu_item ("Left", GTK_SIGNAL_FUNC (cb_pos_menu_select),
2859 GINT_TO_POINTER (GTK_POS_LEFT));
2860 gtk_menu_append (GTK_MENU (menu), item);
2862 item = make_menu_item ("Right", GTK_SIGNAL_FUNC (cb_pos_menu_select),
2863 GINT_TO_POINTER (GTK_POS_RIGHT));
2864 gtk_menu_append (GTK_MENU (menu), item);
2866 gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
2867 gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
2868 gtk_widget_show (opt);
2870 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2871 gtk_widget_show (box2);
2873 box2 = gtk_hbox_new (FALSE, 10);
2874 gtk_container_border_width (GTK_CONTAINER (box2), 10);
2876 /* Yet another option menu, this time for the update policy of the
2878 label = gtk_label_new ("Scale Update Policy:");
2879 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
2880 gtk_widget_show (label);
2882 opt = gtk_option_menu_new();
2883 menu = gtk_menu_new();
2885 item = make_menu_item ("Continuous",
2886 GTK_SIGNAL_FUNC (cb_update_menu_select),
2887 GINT_TO_POINTER (GTK_UPDATE_CONTINUOUS));
2888 gtk_menu_append (GTK_MENU (menu), item);
2890 item = make_menu_item ("Discontinuous",
2891 GTK_SIGNAL_FUNC (cb_update_menu_select),
2892 GINT_TO_POINTER (GTK_UPDATE_DISCONTINUOUS));
2893 gtk_menu_append (GTK_MENU (menu), item);
2895 item = make_menu_item ("Delayed",
2896 GTK_SIGNAL_FUNC (cb_update_menu_select),
2897 GINT_TO_POINTER (GTK_UPDATE_DELAYED));
2898 gtk_menu_append (GTK_MENU (menu), item);
2900 gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
2901 gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
2902 gtk_widget_show (opt);
2904 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2905 gtk_widget_show (box2);
2907 box2 = gtk_hbox_new (FALSE, 10);
2908 gtk_container_border_width (GTK_CONTAINER (box2), 10);
2910 /* A GtkHScale widget for adjusting the number of digits on the
2912 label = gtk_label_new ("Scale Digits:");
2913 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
2914 gtk_widget_show (label);
2916 adj2 = gtk_adjustment_new (1.0, 0.0, 5.0, 1.0, 1.0, 0.0);
2917 gtk_signal_connect (GTK_OBJECT (adj2), "value_changed",
2918 GTK_SIGNAL_FUNC (cb_digits_scale), NULL);
2919 scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
2920 gtk_scale_set_digits (GTK_SCALE (scale), 0);
2921 gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
2922 gtk_widget_show (scale);
2924 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2925 gtk_widget_show (box2);
2927 box2 = gtk_hbox_new (FALSE, 10);
2928 gtk_container_border_width (GTK_CONTAINER (box2), 10);
2930 /* And, one last GtkHScale widget for adjusting the page size of the
2932 label = gtk_label_new ("Scrollbar Page Size:");
2933 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
2934 gtk_widget_show (label);
2936 adj2 = gtk_adjustment_new (1.0, 1.0, 101.0, 1.0, 1.0, 0.0);
2937 gtk_signal_connect (GTK_OBJECT (adj2), "value_changed",
2938 GTK_SIGNAL_FUNC (cb_page_size), adj1);
2939 scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
2940 gtk_scale_set_digits (GTK_SCALE (scale), 0);
2941 gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
2942 gtk_widget_show (scale);
2944 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2945 gtk_widget_show (box2);
2947 separator = gtk_hseparator_new ();
2948 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
2949 gtk_widget_show (separator);
2951 box2 = gtk_vbox_new (FALSE, 10);
2952 gtk_container_border_width (GTK_CONTAINER (box2), 10);
2953 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
2954 gtk_widget_show (box2);
2956 button = gtk_button_new_with_label ("Quit");
2957 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2958 GTK_SIGNAL_FUNC(gtk_main_quit),
2960 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2961 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
2962 gtk_widget_grab_default (button);
2963 gtk_widget_show (button);
2965 gtk_widget_show (window);
2971 gtk_init(&argc, &argv);
2973 create_range_controls();
2985 <!-- ***************************************************************** -->
2986 <sect> Miscellaneous Widgets
2987 <!-- ***************************************************************** -->
2989 <!-- ----------------------------------------------------------------- -->
2992 Labels are used a lot in GTK, and are relatively simple. Labels emit
2993 no signals as they do not have an associated X window. If you need to
2994 catch signals, or do clipping, use the <ref id="sec_EventBox"
2995 name="EventBox"> widget.
2997 To create a new label, use:
3000 GtkWidget *gtk_label_new( char *str );
3003 Where the sole argument is the string you wish the label to display.
3005 To change the label's text after creation, use the function:
3008 void gtk_label_set( GtkLabel *label,
3012 Where the first argument is the label you created previously (cast
3013 using the GTK_LABEL() macro), and the second is the new string.
3015 The space needed for the new string will be automatically adjusted if
3018 To retrieve the current string, use:
3021 void gtk_label_get( GtkLabel *label,
3025 Where the first argument is the label you've created, and the second,
3026 the return for the string.
3028 <!-- ----------------------------------------------------------------- -->
3029 <sect1>The Tooltips Widget
3031 These are the little text strings that pop up when you leave your
3032 pointer over a button or other widget for a few seconds. They are easy
3033 to use, so I will just explain them without giving an example. If you
3034 want to see some code, take a look at the testgtk.c program
3035 distributed with GTK.
3037 Widgets that do not receieve events (widgets that do not have their
3038 own window) will not work with tooltips.
3040 The first call you will use creates a new tooltip. You only need to do
3041 this once for a set of tooltips as the <tt/GtkTooltip/ object this
3042 function returns can be used to create multiple tooltips.
3045 GtkTooltips *gtk_tooltips_new( void );
3048 Once you have created a new tooltip, and the widget you wish to use it
3049 on, simply use this call to set it:
3052 void gtk_tooltips_set_tip( GtkTooltips *tooltips,
3054 const gchar *tip_text,
3055 const gchar *tip_private );
3058 The first argument is the tooltip you've already created, followed by
3059 the widget you wish to have this tooltip pop up for, and the text you
3060 wish it to say. The last argument is a text string that can be used as
3061 an identifier when using GtkTipsQuery to implement context sensitive
3062 help. For now, you can set it to NULL.
3064 <!-- TODO: sort out what how to do the context sensitive help -->
3066 Here's a short example:
3069 GtkTooltips *tooltips;
3074 tooltips = gtk_tooltips_new ();
3075 button = gtk_button_new_with_label ("button 1");
3079 gtk_tooltips_set_tip (tooltips, button, "This is button 1", NULL);
3082 There are other calls that can be used with tooltips. I will just list
3083 them with a brief description of what they do.
3086 void gtk_tooltips_enable( GtkTooltips *tooltips );
3089 Enable a disabled set of tooltips.
3092 void gtk_tooltips_disable( GtkTooltips *tooltips );
3095 Disable an enabled set of tooltips.
3098 void gtk_tooltips_set_delay( GtkTooltips *tooltips,
3103 Sets how many milliseconds you have to hold your pointer over the
3104 widget before the tooltip will pop up. The default is 500
3105 milliseconds (half a second).
3108 void gtk_tooltips_set_colors( GtkTooltips *tooltips,
3109 GdkColor *background,
3110 GdkColor *foreground );
3113 Set the foreground and background color of the tooltips.
3115 And that's all the functions associated with tooltips. More than
3116 you'll ever want to know :-)
3118 <!-- ----------------------------------------------------------------- -->
3119 <sect1> Progress Bars
3121 Progress bars are used to show the status of an operation. They are
3122 pretty easy to use, as you will see with the code below. But first
3123 lets start out with the calls to create a new progress bar.
3125 There are two ways to create a progress bar, one simple one takes
3126 no arguments, and one that takes a GtkAdjustment object as an
3127 argument. If the former is used, the progress bar creates it's own
3131 GtkWidget *gtk_progress_bar_new( void );
3133 GtkWidget *gtk_progress_bar_new_with_adjustment( GtkAdjustment *adjustment );
3136 The second method has the advantage that we can use the adjustment
3137 object to specify our own range parameters for the progress bar.
3139 Now that the progress bar has been created we can use it.
3142 void gtk_progress_bar_update( GtkProgressBar *pbar,
3143 gfloat percentage );
3146 The first argument is the progress bar you wish to operate on, and the
3147 second argument is the amount 'completed', meaning the amount the
3148 progress bar has been filled from 0-100%. This is passed to the
3149 function as a real number ranging from 0 to 1.
3151 GTK v1.1 has added new functionality to the progress bar that enables
3152 it to display it's value in different ways, and to inform the user of
3153 its current value and its range.
3155 A progress bar may be set to one of a number of orientations using the
3159 void gtk_progress_bar_set_orientation( GtkProgressBar *pbar,
3160 GtkProgressBarOrientation orientation );
3163 Where the <tt/orientation/ argument may take one of the following
3164 values to indicate the direction in which the progress bar moves:
3167 <item> GTK_PROGRESS_LEFT_TO_RIGHT
3168 <item> GTK_PROGRESS_RIGHT_TO_LEFT
3169 <item> GTK_PROGRESS_BOTTOM_TO_TOP
3170 <item> GTK_PROGRESS_TOP_TO_BOTTOM
3173 When used as a measure of how far a process has progressed, the
3174 GtkProgressBar can be set to display it's value in either a continuous
3175 or discrete mode. In continuous mode, the progress bar is updated for
3176 each value. In discrete mode, the progress bar is updated in a number
3177 of discrete blocks. The number of blocks is also configurable.
3179 The style of a progress bar can be set using the following function.
3182 void gtk_progress_bar_set_bar_style( GtkProgressBar *pbar,
3183 GtkProgressBarStyle style );
3186 The <tt/style/ parameter can take one of two values:
3189 <item>GTK_PROGRESS_CONTINUOUS
3190 <item>GTK_PROGRESS_DISCRETE
3193 The number of discrete blocks can be set by calling
3196 void gtk_progress_bar_set_discrete_blocks( GtkProgressBar *pbar,
3200 As well as indicating the amount of progress that has occured, the
3201 progress bar may be set to just indicate that there is some
3202 activity. This can be useful in situations where progress cannot be
3203 measured against a value range. Activity mode is not effected by the
3204 bar style that is described above, and overrides it.This mode is
3205 selected by the following function.
3208 void gtk_progress_set_activity_mode( GtkProgress *progress,
3209 guint activity_mode );
3212 The step size of the activity indicator, and the number of blocks are
3213 set using the following functions.
3216 void gtk_progress_bar_set_activity_step( GtkProgressBar *pbar,
3219 void gtk_progress_bar_set_activity_blocks( GtkProgressBar *pbar,
3223 When in continuous mode, the progress bar can also display a
3224 configurable text string within it's trough, using the following
3228 void gtk_progress_set_format_string( GtkProgress *progress,
3232 The <tt/format/ argument is similiar to one that would be used in a C
3233 <tt/printf/ statement. The following directives may be used within the
3237 <item> %p - percentage
3239 <item> %l - lower range value
3240 <item> %u - upper range value
3243 Progress Bars are usually used with timeouts or other such functions
3244 (see section on <ref id="sec_timeouts" name="Timeouts, I/O and Idle
3245 Functions">) to give the illusion of multitasking. All will employ the
3246 gtk_progress_bar_update function in the same manner.
3248 Here is an example of the progress bar, updated using timeouts. This
3249 code also shows you how to reset the Progress Bar.
3252 /* example-start progressbar progressbar.c */
3254 #include <gtk/gtk.h>
3256 typedef struct _ProgressData {
3262 /* Update the value of the progress bar so that we get
3264 gint progress_timeout( gpointer data )
3269 adj = GTK_PROGRESS (data)->adjustment;
3271 /* Calculate the value of the progress bar using the
3272 * value range set in the adjustment object */
3273 new_val = adj->value + 1;
3274 if (new_val > adj->upper)
3275 new_val = adj->lower;
3277 /* Set the new value */
3278 gtk_progress_set_value (GTK_PROGRESS (data), new_val);
3280 /* As this is a timeout function, return TRUE so that it
3281 * continues to get called */
3285 /* Callback that toggles the text display within the progress
3287 void toggle_show_text( GtkWidget *widget,
3288 ProgressData *pdata )
3290 gtk_progress_set_show_text (GTK_PROGRESS (pdata->pbar),
3291 GTK_TOGGLE_BUTTON (widget)->active);
3294 /* Callback that toggles the activity mode of the progress
3296 void toggle_activity_mode( GtkWidget *widget,
3297 ProgressData *pdata )
3299 gtk_progress_set_activity_mode (GTK_PROGRESS (pdata->pbar),
3300 GTK_TOGGLE_BUTTON (widget)->active);
3303 /* Callback that toggles the continuous mode of the progress
3305 void set_continuous_mode( GtkWidget *widget,
3306 ProgressData *pdata )
3308 gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
3309 GTK_PROGRESS_CONTINUOUS);
3312 /* Callback that toggles the discrete mode of the progress
3314 void set_discrete_mode( GtkWidget *widget,
3315 ProgressData *pdata )
3317 gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
3318 GTK_PROGRESS_DISCRETE);
3321 /* Clean up allocated memory and remove the timer */
3322 void destroy_progress( GtkWidget *widget,
3323 ProgressData *pdata)
3325 gtk_timeout_remove (pdata->timer);
3327 pdata->window = NULL;
3335 ProgressData *pdata;
3337 GtkWidget *separator;
3344 gtk_init (&argc, &argv);
3346 /* Allocate memory for the data that is passwd to the callbacks */
3347 pdata = g_malloc( sizeof(ProgressData) );
3349 pdata->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3350 gtk_window_set_policy (GTK_WINDOW (pdata->window), FALSE, FALSE, TRUE);
3352 gtk_signal_connect (GTK_OBJECT (pdata->window), "destroy",
3353 GTK_SIGNAL_FUNC (destroy_progress),
3355 gtk_window_set_title (GTK_WINDOW (pdata->window), "GtkProgressBar");
3356 gtk_container_set_border_width (GTK_CONTAINER (pdata->window), 0);
3358 vbox = gtk_vbox_new (FALSE, 5);
3359 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
3360 gtk_container_add (GTK_CONTAINER (pdata->window), vbox);
3361 gtk_widget_show(vbox);
3363 /* Create a centering alignment object */
3364 align = gtk_alignment_new (0.5, 0.5, 0, 0);
3365 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 5);
3366 gtk_widget_show(align);
3368 /* Create a GtkAdjusment object to hold the range of the
3370 adj = (GtkAdjustment *) gtk_adjustment_new (0, 1, 150, 0, 0, 0);
3372 /* Create the GtkProgressBar using the adjustment */
3373 pdata->pbar = gtk_progress_bar_new_with_adjustment (adj);
3375 /* Set the format of the string that can be displayed in the
3376 * trough of the progress bar:
3379 * %l - lower range value
3380 * %u - upper range value */
3381 gtk_progress_set_format_string (GTK_PROGRESS (pdata->pbar),
3382 "%v from [%l-%u] (=%p%%)");
3383 gtk_container_add (GTK_CONTAINER (align), pdata->pbar);
3384 gtk_widget_show(pdata->pbar);
3386 /* Add a timer callback to update the value of the progress bar */
3387 pdata->timer = gtk_timeout_add (100, progress_timeout, pdata->pbar);
3389 separator = gtk_hseparator_new ();
3390 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
3391 gtk_widget_show(separator);
3393 /* rows, columns, homogeneous */
3394 table = gtk_table_new (2, 3, FALSE);
3395 gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0);
3396 gtk_widget_show(table);
3398 /* Add a check button to select displaying of the trough text */
3399 check = gtk_check_button_new_with_label ("Show text");
3400 gtk_table_attach (GTK_TABLE (table), check, 0, 1, 0, 1,
3401 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3403 gtk_signal_connect (GTK_OBJECT (check), "clicked",
3404 GTK_SIGNAL_FUNC (toggle_show_text),
3406 gtk_widget_show(check);
3408 /* Add a check button to toggle activity mode */
3409 check = gtk_check_button_new_with_label ("Activity mode");
3410 gtk_table_attach (GTK_TABLE (table), check, 0, 1, 1, 2,
3411 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3413 gtk_signal_connect (GTK_OBJECT (check), "clicked",
3414 GTK_SIGNAL_FUNC (toggle_activity_mode),
3416 gtk_widget_show(check);
3418 separator = gtk_vseparator_new ();
3419 gtk_table_attach (GTK_TABLE (table), separator, 1, 2, 0, 2,
3420 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3422 gtk_widget_show(separator);
3424 /* Add a radio button to select continuous display mode */
3425 button = gtk_radio_button_new_with_label (NULL, "Continuous");
3426 gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1,
3427 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3429 gtk_signal_connect (GTK_OBJECT (button), "clicked",
3430 GTK_SIGNAL_FUNC (set_continuous_mode),
3432 gtk_widget_show (button);
3434 /* Add a radio button to select discrete display mode */
3435 button = gtk_radio_button_new_with_label(
3436 gtk_radio_button_group (GTK_RADIO_BUTTON (button)),
3438 gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2,
3439 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3441 gtk_signal_connect (GTK_OBJECT (button), "clicked",
3442 GTK_SIGNAL_FUNC (set_discrete_mode),
3444 gtk_widget_show (button);
3446 separator = gtk_hseparator_new ();
3447 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
3448 gtk_widget_show(separator);
3450 /* Add a button to exit the program */
3451 button = gtk_button_new_with_label ("close");
3452 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
3453 (GtkSignalFunc) gtk_widget_destroy,
3454 GTK_OBJECT (pdata->window));
3455 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
3457 /* This makes it so the button is the default. */
3458 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
3460 /* This grabs this button to be the default button. Simply hitting
3461 * the "Enter" key will cause this button to activate. */
3462 gtk_widget_grab_default (button);
3463 gtk_widget_show(button);
3465 gtk_widget_show (pdata->window);
3474 <!-- ----------------------------------------------------------------- -->
3477 The Dialog widget is very simple, and is actually just a window with a
3478 few things pre-packed into it for you. The structure for a Dialog is:
3486 GtkWidget *action_area;
3490 So you see, it simply creates a window, and then packs a vbox into the
3491 top, then a separator, and then an hbox for the "action_area".
3493 The Dialog widget can be used for pop-up messages to the user, and
3494 other similar tasks. It is really basic, and there is only one
3495 function for the dialog box, which is:
3498 GtkWidget *gtk_dialog_new( void );
3501 So to create a new dialog box, use,
3505 window = gtk_dialog_new ();
3508 This will create the dialog box, and it is now up to you to use it.
3509 you could pack a button in the action_area by doing something like this:
3513 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area),
3514 button, TRUE, TRUE, 0);
3515 gtk_widget_show (button);
3518 And you could add to the vbox area by packing, for instance, a label
3519 in it, try something like this:
3522 label = gtk_label_new ("Dialogs are groovy");
3523 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox),
3524 label, TRUE, TRUE, 0);
3525 gtk_widget_show (label);
3528 As an example in using the dialog box, you could put two buttons in
3529 the action_area, a Cancel button and an Ok button, and a label in the
3530 vbox area, asking the user a question or giving an error etc. Then
3531 you could attach a different signal to each of the buttons and perform
3532 the operation the user selects.
3534 If the simple functionality provided by the default vertical and
3535 horizontal boxes in the two areas does't give you enough control for
3536 your application, then you can simply pack another layout widget into
3537 the boxes provided. For example, you could pack a table into the
3540 <!-- ----------------------------------------------------------------- -->
3541 <sect1> Pixmaps <label id="sec_Pixmaps">
3543 Pixmaps are data structures that contain pictures. These pictures can
3544 be used in various places, but most visibly as icons on the X-Windows
3545 desktop, or as cursors. A bitmap is a 2-color pixmap.
3547 To use pixmaps in GTK, we must first build a GdkPixmap structure using
3548 routines from the GDK layer. Pixmaps can either be created from
3549 in-memory data, or from data read from a file. We'll go through each
3550 of the calls to create a pixmap.
3553 GdkPixmap *gdk_bitmap_create_from_data( GdkWindow *window,
3559 This routine is used to create a single-plane pixmap (2 colors) from
3560 data in memory. Each bit of the data represents whether that pixel is
3561 off or on. Width and height are in pixels. The GdkWindow pointer is
3562 to the current window, since a pixmap resources are meaningful only in
3563 the context of the screen where it is to be displayed.
3566 GdkPixmap *gdk_pixmap_create_from_data( GdkWindow *window,
3575 This is used to create a pixmap of the given depth (number of colors) from
3576 the bitmap data specified. <tt/fg/ and <tt/bg/ are the foreground and
3577 background color to use.
3580 GdkPixmap *gdk_pixmap_create_from_xpm( GdkWindow *window,
3582 GdkColor *transparent_color,
3583 const gchar *filename );
3586 XPM format is a readable pixmap representation for the X Window
3587 System. It is widely used and many different utilities are available
3588 for creating image files in this format. The file specified by
3589 filename must contain an image in that format and it is loaded into
3590 the pixmap structure. The mask specifies which bits of the pixmap are
3591 opaque. All other bits are colored using the color specified by
3592 transparent_color. An example using this follows below.
3595 GdkPixmap *gdk_pixmap_create_from_xpm_d( GdkWindow *window,
3597 GdkColor *transparent_color,
3601 Small images can be incorporated into a program as data in the XPM
3602 format. A pixmap is created using this data, instead of reading it
3603 from a file. An example of such data is
3607 static const char * xpm_data[] = {
3610 ". c #000000000000",
3611 "X c #FFFFFFFFFFFF",
3630 When we're done using a pixmap and not likely to reuse it again soon,
3631 it is a good idea to release the resource using
3632 gdk_pixmap_unref(). Pixmaps should be considered a precious resource.
3634 Once we've created a pixmap, we can display it as a GTK widget. We
3635 must create a GTK pixmap widget to contain the GDK pixmap. This is
3639 GtkWidget *gtk_pixmap_new( GdkPixmap *pixmap,
3643 The other pixmap widget calls are
3646 guint gtk_pixmap_get_type( void );
3648 void gtk_pixmap_set( GtkPixmap *pixmap,
3652 void gtk_pixmap_get( GtkPixmap *pixmap,
3657 gtk_pixmap_set is used to change the pixmap that the widget is currently
3658 managing. Val is the pixmap created using GDK.
3660 The following is an example of using a pixmap in a button.
3663 /* example-start pixmap pixmap.c */
3665 #include <gtk/gtk.h>
3668 /* XPM data of Open-File icon */
3669 static const char * xpm_data[] = {
3672 ". c #000000000000",
3673 "X c #FFFFFFFFFFFF",
3692 /* when invoked (via signal delete_event), terminates the application.
3694 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
3699 /* is invoked when the button is clicked. It just prints a message.
3701 void button_clicked( GtkWidget *widget, gpointer data ) {
3702 printf( "button clicked\n" );
3705 int main( int argc, char *argv[] )
3707 /* GtkWidget is the storage type for widgets */
3708 GtkWidget *window, *pixmapwid, *button;
3713 /* create the main window, and attach delete_event signal to terminating
3715 gtk_init( &argc, &argv );
3716 window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
3717 gtk_signal_connect( GTK_OBJECT (window), "delete_event",
3718 GTK_SIGNAL_FUNC (close_application), NULL );
3719 gtk_container_border_width( GTK_CONTAINER (window), 10 );
3720 gtk_widget_show( window );
3722 /* now for the pixmap from gdk */
3723 style = gtk_widget_get_style( window );
3724 pixmap = gdk_pixmap_create_from_xpm_d( window->window, &mask,
3725 &style->bg[GTK_STATE_NORMAL],
3726 (gchar **)xpm_data );
3728 /* a pixmap widget to contain the pixmap */
3729 pixmapwid = gtk_pixmap_new( pixmap, mask );
3730 gtk_widget_show( pixmapwid );
3732 /* a button to contain the pixmap widget */
3733 button = gtk_button_new();
3734 gtk_container_add( GTK_CONTAINER(button), pixmapwid );
3735 gtk_container_add( GTK_CONTAINER(window), button );
3736 gtk_widget_show( button );
3738 gtk_signal_connect( GTK_OBJECT(button), "clicked",
3739 GTK_SIGNAL_FUNC(button_clicked), NULL );
3741 /* show the window */
3749 To load a file from an XPM data file called icon0.xpm in the current
3750 directory, we would have created the pixmap thus
3753 /* load a pixmap from a file */
3754 pixmap = gdk_pixmap_create_from_xpm( window->window, &mask,
3755 &style->bg[GTK_STATE_NORMAL],
3757 pixmapwid = gtk_pixmap_new( pixmap, mask );
3758 gtk_widget_show( pixmapwid );
3759 gtk_container_add( GTK_CONTAINER(window), pixmapwid );
3762 A disadvantage of using pixmaps is that the displayed object is always
3763 rectangular, regardless of the image. We would like to create desktops
3764 and applications with icons that have more natural shapes. For
3765 example, for a game interface, we would like to have round buttons to
3766 push. The way to do this is using shaped windows.
3768 A shaped window is simply a pixmap where the background pixels are
3769 transparent. This way, when the background image is multi-colored, we
3770 don't overwrite it with a rectangular, non-matching border around our
3771 icon. The following example displays a full wheelbarrow image on the
3775 /* example-start wheelbarrow wheelbarrow.c */
3777 #include <gtk/gtk.h>
3780 static char * WheelbarrowFull_xpm[] = {
3783 ". c #DF7DCF3CC71B",
3784 "X c #965875D669A6",
3785 "o c #71C671C671C6",
3786 "O c #A699A289A699",
3787 "+ c #965892489658",
3788 "@ c #8E38410330C2",
3789 "# c #D75C7DF769A6",
3790 "$ c #F7DECF3CC71B",
3791 "% c #96588A288E38",
3792 "& c #A69992489E79",
3793 "* c #8E3886178E38",
3794 "= c #104008200820",
3795 "- c #596510401040",
3796 "; c #C71B30C230C2",
3797 ": c #C71B9A699658",
3798 "> c #618561856185",
3799 ", c #20811C712081",
3800 "< c #104000000000",
3801 "1 c #861720812081",
3802 "2 c #DF7D4D344103",
3803 "3 c #79E769A671C6",
3804 "4 c #861782078617",
3805 "5 c #41033CF34103",
3806 "6 c #000000000000",
3807 "7 c #49241C711040",
3808 "8 c #492445144924",
3809 "9 c #082008200820",
3810 "0 c #69A618611861",
3811 "q c #B6DA71C65144",
3812 "w c #410330C238E3",
3813 "e c #CF3CBAEAB6DA",
3814 "r c #71C6451430C2",
3815 "t c #EFBEDB6CD75C",
3816 "y c #28A208200820",
3817 "u c #186110401040",
3818 "i c #596528A21861",
3819 "p c #71C661855965",
3820 "a c #A69996589658",
3821 "s c #30C228A230C2",
3822 "d c #BEFBA289AEBA",
3823 "f c #596545145144",
3824 "g c #30C230C230C2",
3825 "h c #8E3882078617",
3826 "j c #208118612081",
3827 "k c #38E30C300820",
3828 "l c #30C2208128A2",
3829 "z c #38E328A238E3",
3830 "x c #514438E34924",
3831 "c c #618555555965",
3832 "v c #30C2208130C2",
3833 "b c #38E328A230C2",
3834 "n c #28A228A228A2",
3835 "m c #41032CB228A2",
3836 "M c #104010401040",
3837 "N c #492438E34103",
3838 "B c #28A2208128A2",
3839 "V c #A699596538E3",
3840 "C c #30C21C711040",
3841 "Z c #30C218611040",
3842 "A c #965865955965",
3843 "S c #618534D32081",
3844 "D c #38E31C711040",
3845 "F c #082000000820",
3854 "ty> 459@>+&& ",
3856 "%$;=* *3:.Xa.dfg> ",
3857 "Oh$;ya *3d.a8j,Xe.d3g8+ ",
3858 " Oh$;ka *3d$a8lz,,xxc:.e3g54 ",
3859 " Oh$;kO *pd$%svbzz,sxxxxfX..&wn> ",
3860 " Oh$@mO *3dthwlsslszjzxxxxxxx3:td8M4 ",
3861 " Oh$@g& *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B* ",
3862 " Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5& ",
3863 " Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM* ",
3864 " OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
3865 " 2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
3866 " :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
3867 " +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
3868 " *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&en",
3869 " p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>",
3870 " OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ",
3871 " 3206Bwxxszx%et.eaAp77m77mmmf3&eeeg* ",
3872 " @26MvzxNzvlbwfpdettttttttttt.c,n& ",
3873 " *;16=lsNwwNwgsvslbwwvccc3pcfu<o ",
3874 " p;<69BvwwsszslllbBlllllllu<5+ ",
3875 " OS0y6FBlvvvzvzss,u=Blllj=54 ",
3876 " c1-699Blvlllllu7k96MMMg4 ",
3877 " *10y8n6FjvllllB<166668 ",
3878 " S-kg+>666<M<996-y6n<8* ",
3879 " p71=4 m69996kD8Z-66698&& ",
3880 " &i0ycm6n4 ogk17,0<6666g ",
3881 " N-k-<> >=01-kuu666> ",
3882 " ,6ky& &46-10ul,66, ",
3883 " Ou0<> o66y<ulw<66& ",
3884 " *kk5 >66By7=xu664 ",
3885 " <<M4 466lj<Mxu66o ",
3886 " *>> +66uv,zN666* ",
3896 /* When invoked (via signal delete_event), terminates the application */
3897 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
3901 int main (int argc, char *argv[])
3903 /* GtkWidget is the storage type for widgets */
3904 GtkWidget *window, *pixmap, *fixed;
3905 GdkPixmap *gdk_pixmap;
3910 /* Create the main window, and attach delete_event signal to terminate
3911 * the application. Note that the main window will not have a titlebar
3912 * since we're making it a popup. */
3913 gtk_init (&argc, &argv);
3914 window = gtk_window_new( GTK_WINDOW_POPUP );
3915 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
3916 GTK_SIGNAL_FUNC (close_application), NULL);
3917 gtk_widget_show (window);
3919 /* Now for the pixmap and the pixmap widget */
3920 style = gtk_widget_get_default_style();
3921 gc = style->black_gc;
3922 gdk_pixmap = gdk_pixmap_create_from_xpm_d( window->window, &mask,
3923 &style->bg[GTK_STATE_NORMAL],
3924 WheelbarrowFull_xpm );
3925 pixmap = gtk_pixmap_new( gdk_pixmap, mask );
3926 gtk_widget_show( pixmap );
3928 /* To display the pixmap, we use a fixed widget to place the pixmap */
3929 fixed = gtk_fixed_new();
3930 gtk_widget_set_usize( fixed, 200, 200 );
3931 gtk_fixed_put( GTK_FIXED(fixed), pixmap, 0, 0 );
3932 gtk_container_add( GTK_CONTAINER(window), fixed );
3933 gtk_widget_show( fixed );
3935 /* This masks out everything except for the image itself */
3936 gtk_widget_shape_combine_mask( window, mask, 0, 0 );
3938 /* show the window */
3939 gtk_widget_set_uposition( window, 20, 400 );
3940 gtk_widget_show( window );
3948 To make the wheelbarrow image sensitive, we could attach the button
3949 press event signal to make it do something. The following few lines
3950 would make the picture sensitive to a mouse button being pressed which
3951 makes the application terminate.
3954 gtk_widget_set_events( window,
3955 gtk_widget_get_events( window ) |
3956 GDK_BUTTON_PRESS_MASK );
3958 gtk_signal_connect( GTK_OBJECT(window), "button_press_event",
3959 GTK_SIGNAL_FUNC(close_application), NULL );
3962 <!-- ----------------------------------------------------------------- -->
3965 Ruler widgets are used to indicate the location of the mouse pointer
3966 in a given window. A window can have a vertical ruler spanning across
3967 the width and a horizontal ruler spanning down the height. A small
3968 triangular indicator on the ruler shows the exact location of the
3969 pointer relative to the ruler.
3971 A ruler must first be created. Horizontal and vertical rulers are
3975 GtkWidget *gtk_hruler_new( void ); /* horizontal ruler */
3977 GtkWidget *gtk_vruler_new( void ); /* vertical ruler */
3980 Once a ruler is created, we can define the unit of measurement. Units
3981 of measure for rulers can be GTK_PIXELS, GTK_INCHES or
3982 GTK_CENTIMETERS. This is set using
3985 void gtk_ruler_set_metric( GtkRuler *ruler,
3986 GtkMetricType metric );
3989 The default measure is GTK_PIXELS.
3992 gtk_ruler_set_metric( GTK_RULER(ruler), GTK_PIXELS );
3995 Other important characteristics of a ruler are how to mark the units
3996 of scale and where the position indicator is initially placed. These
3997 are set for a ruler using
4000 void gtk_ruler_set_range( GtkRuler *ruler,
4007 The lower and upper arguments define the extent of the ruler, and
4008 max_size is the largest possible number that will be displayed.
4009 Position defines the initial position of the pointer indicator within
4012 A vertical ruler can span an 800 pixel wide window thus
4015 gtk_ruler_set_range( GTK_RULER(vruler), 0, 800, 0, 800);
4018 The markings displayed on the ruler will be from 0 to 800, with a
4019 number for every 100 pixels. If instead we wanted the ruler to range
4020 from 7 to 16, we would code
4023 gtk_ruler_set_range( GTK_RULER(vruler), 7, 16, 0, 20);
4026 The indicator on the ruler is a small triangular mark that indicates
4027 the position of the pointer relative to the ruler. If the ruler is
4028 used to follow the mouse pointer, the motion_notify_event signal
4029 should be connected to the motion_notify_event method of the ruler.
4030 To follow all mouse movements within a window area, we would use
4033 #define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
4035 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4036 (GtkSignalFunc)EVENT_METHOD(ruler, motion_notify_event),
4037 GTK_OBJECT(ruler) );
4040 The following example creates a drawing area with a horizontal ruler
4041 above it and a vertical ruler to the left of it. The size of the
4042 drawing area is 600 pixels wide by 400 pixels high. The horizontal
4043 ruler spans from 7 to 13 with a mark every 100 pixels, while the
4044 vertical ruler spans from 0 to 400 with a mark every 100 pixels.
4045 Placement of the drawing area and the rulers is done using a table.
4048 /* example-start rulers rulers.c */
4050 #include <gtk/gtk.h>
4052 #define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
4057 /* This routine gets control when the close button is clicked */
4058 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
4062 /* The main routine */
4063 int main( int argc, char *argv[] ) {
4064 GtkWidget *window, *table, *area, *hrule, *vrule;
4066 /* Initialize GTK and create the main window */
4067 gtk_init( &argc, &argv );
4069 window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
4070 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
4071 GTK_SIGNAL_FUNC( close_application ), NULL);
4072 gtk_container_border_width (GTK_CONTAINER (window), 10);
4074 /* Create a table for placing the ruler and the drawing area */
4075 table = gtk_table_new( 3, 2, FALSE );
4076 gtk_container_add( GTK_CONTAINER(window), table );
4078 area = gtk_drawing_area_new();
4079 gtk_drawing_area_size( (GtkDrawingArea *)area, XSIZE, YSIZE );
4080 gtk_table_attach( GTK_TABLE(table), area, 1, 2, 1, 2,
4081 GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0 );
4082 gtk_widget_set_events( area, GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK );
4084 /* The horizontal ruler goes on top. As the mouse moves across the drawing area,
4085 * a motion_notify_event is passed to the appropriate event handler for the ruler. */
4086 hrule = gtk_hruler_new();
4087 gtk_ruler_set_metric( GTK_RULER(hrule), GTK_PIXELS );
4088 gtk_ruler_set_range( GTK_RULER(hrule), 7, 13, 0, 20 );
4089 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4090 (GtkSignalFunc)EVENT_METHOD(hrule, motion_notify_event),
4091 GTK_OBJECT(hrule) );
4092 /* GTK_WIDGET_CLASS(GTK_OBJECT(hrule)->klass)->motion_notify_event, */
4093 gtk_table_attach( GTK_TABLE(table), hrule, 1, 2, 0, 1,
4094 GTK_EXPAND|GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0 );
4096 /* The vertical ruler goes on the left. As the mouse moves across the drawing area,
4097 * a motion_notify_event is passed to the appropriate event handler for the ruler. */
4098 vrule = gtk_vruler_new();
4099 gtk_ruler_set_metric( GTK_RULER(vrule), GTK_PIXELS );
4100 gtk_ruler_set_range( GTK_RULER(vrule), 0, YSIZE, 10, YSIZE );
4101 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4103 GTK_WIDGET_CLASS(GTK_OBJECT(vrule)->klass)->motion_notify_event,
4104 GTK_OBJECT(vrule) );
4105 gtk_table_attach( GTK_TABLE(table), vrule, 0, 1, 1, 2,
4106 GTK_FILL, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0 );
4108 /* Now show everything */
4109 gtk_widget_show( area );
4110 gtk_widget_show( hrule );
4111 gtk_widget_show( vrule );
4112 gtk_widget_show( table );
4113 gtk_widget_show( window );
4121 <!-- ----------------------------------------------------------------- -->
4124 Statusbars are simple widgets used to display a text message. They
4125 keep a stack of the messages pushed onto them, so that popping the
4126 current message will re-display the previous text message.
4128 In order to allow different parts of an application to use the same
4129 statusbar to display messages, the statusbar widget issues Context
4130 Identifiers which are used to identify different 'users'. The message
4131 on top of the stack is the one displayed, no matter what context it is
4132 in. Messages are stacked in last-in-first-out order, not context
4135 A statusbar is created with a call to:
4138 GtkWidget *gtk_statusbar_new( void );
4141 A new Context Identifier is requested using a call to the following
4142 function with a short textual description of the context:
4145 guint gtk_statusbar_get_context_id( GtkStatusbar *statusbar,
4146 const gchar *context_description );
4149 There are three functions that can operate on statusbars:
4152 guint gtk_statusbar_push( GtkStatusbar *statusbar,
4156 void gtk_statusbar_pop( GtkStatusbar *statusbar)
4159 void gtk_statusbar_remove( GtkStatusbar *statusbar,
4164 The first, gtk_statusbar_push, is used to add a new message to the
4165 statusbar. It returns a Message Identifier, which can be passed later
4166 to the function gtk_statusbar_remove to remove the message with the
4167 given Message and Context Identifiers from the statusbar's stack.
4169 The function gtk_statusbar_pop removes the message highest in the
4170 stack with the given Context Identifier.
4172 The following example creates a statusbar and two buttons, one for
4173 pushing items onto the statusbar, and one for popping the last item
4177 /* example-start statusbar statusbar.c */
4179 #include <gtk/gtk.h>
4182 GtkWidget *status_bar;
4184 void push_item (GtkWidget *widget, gpointer data)
4186 static int count = 1;
4189 g_snprintf(buff, 20, "Item %d", count++);
4190 gtk_statusbar_push( GTK_STATUSBAR(status_bar), (guint) &data, buff);
4195 void pop_item (GtkWidget *widget, gpointer data)
4197 gtk_statusbar_pop( GTK_STATUSBAR(status_bar), (guint) &data );
4201 int main (int argc, char *argv[])
4210 gtk_init (&argc, &argv);
4212 /* create a new window */
4213 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4214 gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
4215 gtk_window_set_title(GTK_WINDOW (window), "GTK Statusbar Example");
4216 gtk_signal_connect(GTK_OBJECT (window), "delete_event",
4217 (GtkSignalFunc) gtk_exit, NULL);
4219 vbox = gtk_vbox_new(FALSE, 1);
4220 gtk_container_add(GTK_CONTAINER(window), vbox);
4221 gtk_widget_show(vbox);
4223 status_bar = gtk_statusbar_new();
4224 gtk_box_pack_start (GTK_BOX (vbox), status_bar, TRUE, TRUE, 0);
4225 gtk_widget_show (status_bar);
4227 context_id = gtk_statusbar_get_context_id( GTK_STATUSBAR(status_bar), "Statusbar example");
4229 button = gtk_button_new_with_label("push item");
4230 gtk_signal_connect(GTK_OBJECT(button), "clicked",
4231 GTK_SIGNAL_FUNC (push_item), &context_id);
4232 gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 2);
4233 gtk_widget_show(button);
4235 button = gtk_button_new_with_label("pop last item");
4236 gtk_signal_connect(GTK_OBJECT(button), "clicked",
4237 GTK_SIGNAL_FUNC (pop_item), &context_id);
4238 gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 2);
4239 gtk_widget_show(button);
4241 /* always display the window as the last step so it all splashes on
4242 * the screen at once. */
4243 gtk_widget_show(window);
4252 <!-- ----------------------------------------------------------------- -->
4255 The Entry widget allows text to be typed and displayed in a single line
4256 text box. The text may be set with function calls that allow new text
4257 to replace, prepend or append the current contents of the Entry widget.
4259 There are two functions for creating Entry widgets:
4262 GtkWidget *gtk_entry_new( void );
4264 GtkWidget *gtk_entry_new_with_max_length( guint16 max );
4267 The first just creates a new Entry widget, whilst the second creates a
4268 new Entry and sets a limit on the length of the text within the Entry.
4270 There are several functions for altering the text which is currently
4271 within the Entry widget.
4274 void gtk_entry_set_text( GtkEntry *entry,
4275 const gchar *text );
4277 void gtk_entry_append_text( GtkEntry *entry,
4278 const gchar *text );
4280 void gtk_entry_prepend_text( GtkEntry *entry,
4281 const gchar *text );
4284 The function gtk_entry_set_text sets the contents of the Entry widget,
4285 replacing the current contents. The functions gtk_entry_append_text
4286 and gtk_entry_prepend_text allow the current contents to be appended
4289 The next function allows the current insertion point to be set.
4292 void gtk_entry_set_position( GtkEntry *entry,
4296 The contents of the Entry can be retrieved by using a call to the
4297 following function. This is useful in the callback functions described below.
4300 gchar *gtk_entry_get_text( GtkEntry *entry );
4303 If we don't want the contents of the Entry to be changed by someone typing
4304 into it, we can change its editable state.
4307 void gtk_entry_set_editable( GtkEntry *entry,
4308 gboolean editable );
4311 The function above allows us to toggle the editable state of the
4312 Entry widget by passing in a TRUE or FALSE value for the <tt/editable/
4315 If we are using the Entry where we don't want the text entered to be
4316 visible, for example when a password is being entered, we can use the
4317 following function, which also takes a boolean flag.
4320 void gtk_entry_set_visibility( GtkEntry *entry,
4324 A region of the text may be set as selected by using the following
4325 function. This would most often be used after setting some default
4326 text in an Entry, making it easy for the user to remove it.
4329 void gtk_entry_select_region( GtkEntry *entry,
4334 If we want to catch when the user has entered text, we can connect to
4335 the <tt/activate/ or <tt/changed/ signal. Activate is raised when the
4336 user hits the enter key within the Entry widget. Changed is raised
4337 when the text changes at all, e.g. for every character entered or
4340 The following code is an example of using an Entry widget.
4343 /* example-start entry entry.c */
4345 #include <gtk/gtk.h>
4347 void enter_callback(GtkWidget *widget, GtkWidget *entry)
4350 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
4351 printf("Entry contents: %s\n", entry_text);
4354 void entry_toggle_editable (GtkWidget *checkbutton,
4357 gtk_entry_set_editable(GTK_ENTRY(entry),
4358 GTK_TOGGLE_BUTTON(checkbutton)->active);
4361 void entry_toggle_visibility (GtkWidget *checkbutton,
4364 gtk_entry_set_visibility(GTK_ENTRY(entry),
4365 GTK_TOGGLE_BUTTON(checkbutton)->active);
4368 int main (int argc, char *argv[])
4372 GtkWidget *vbox, *hbox;
4377 gtk_init (&argc, &argv);
4379 /* create a new window */
4380 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4381 gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
4382 gtk_window_set_title(GTK_WINDOW (window), "GTK Entry");
4383 gtk_signal_connect(GTK_OBJECT (window), "delete_event",
4384 (GtkSignalFunc) gtk_exit, NULL);
4386 vbox = gtk_vbox_new (FALSE, 0);
4387 gtk_container_add (GTK_CONTAINER (window), vbox);
4388 gtk_widget_show (vbox);
4390 entry = gtk_entry_new_with_max_length (50);
4391 gtk_signal_connect(GTK_OBJECT(entry), "activate",
4392 GTK_SIGNAL_FUNC(enter_callback),
4394 gtk_entry_set_text (GTK_ENTRY (entry), "hello");
4395 gtk_entry_append_text (GTK_ENTRY (entry), " world");
4396 gtk_entry_select_region (GTK_ENTRY (entry),
4397 0, GTK_ENTRY(entry)->text_length);
4398 gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0);
4399 gtk_widget_show (entry);
4401 hbox = gtk_hbox_new (FALSE, 0);
4402 gtk_container_add (GTK_CONTAINER (vbox), hbox);
4403 gtk_widget_show (hbox);
4405 check = gtk_check_button_new_with_label("Editable");
4406 gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
4407 gtk_signal_connect (GTK_OBJECT(check), "toggled",
4408 GTK_SIGNAL_FUNC(entry_toggle_editable), entry);
4409 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
4410 gtk_widget_show (check);
4412 check = gtk_check_button_new_with_label("Visible");
4413 gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
4414 gtk_signal_connect (GTK_OBJECT(check), "toggled",
4415 GTK_SIGNAL_FUNC(entry_toggle_visibility), entry);
4416 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
4417 gtk_widget_show (check);
4419 button = gtk_button_new_with_label ("Close");
4420 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
4421 GTK_SIGNAL_FUNC(gtk_exit),
4422 GTK_OBJECT (window));
4423 gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
4424 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
4425 gtk_widget_grab_default (button);
4426 gtk_widget_show (button);
4428 gtk_widget_show(window);
4436 <!-- ----------------------------------------------------------------- -->
4437 <sect1> Color Selection
4439 The color selection widget is, not surprisingly, a widget for
4440 interactive selection of colors. This composite widget lets the user
4441 select a color by manipulating RGB (Red, Green, Blue) and HSV (Hue,
4442 Saturation, Value) triples. This is done either by adjusting single
4443 values with sliders or entries, or by picking the desired color from a
4444 hue-saturation wheel/value bar. Optionally, the opacity of the color
4447 The color selection widget currently emits only one signal,
4448 "color_changed", which is emitted whenever the current color in the
4449 widget changes, either when the user changes it or if it's set
4450 explicitly through gtk_color_selection_set_color().
4452 Lets have a look at what the color selection widget has to offer
4453 us. The widget comes in two flavours: gtk_color_selection and
4454 gtk_color_selection_dialog.
4457 GtkWidget *gtk_color_selection_new( void );
4460 You'll probably not be using this constructor directly. It creates an
4461 orphan GtkColorSelection widget which you'll have to parent
4462 yourself. The GtkColorSelection widget inherits from the GtkVBox
4466 GtkWidget *gtk_color_selection_dialog_new( const gchar *title );
4469 This is the most common color selection constructor. It creates a
4470 GtkColorSelectionDialog, which inherits from a GtkDialog. It consists
4471 of a GtkFrame containing a GtkColorSelection widget, a GtkHSeparator
4472 and a GtkHBox with three buttons, "Ok", "Cancel" and "Help". You can
4473 reach these buttons by accessing the "ok_button", "cancel_button" and
4474 "help_button" widgets in the GtkColorSelectionDialog structure,
4475 (i.e. GTK_COLOR_SELECTION_DIALOG(colorseldialog)->ok_button).
4478 void gtk_color_selection_set_update_policy( GtkColorSelection *colorsel,
4479 GtkUpdateType policy );
4482 This function sets the update policy. The default policy is
4483 GTK_UPDATE_CONTINUOUS which means that the current color is updated
4484 continuously when the user drags the sliders or presses the mouse and
4485 drags in the hue-saturation wheel or value bar. If you experience
4486 performance problems, you may want to set the policy to
4487 GTK_UPDATE_DISCONTINUOUS or GTK_UPDATE_DELAYED.
4490 void gtk_color_selection_set_opacity( GtkColorSelection *colorsel,
4494 The color selection widget supports adjusting the opacity of a color
4495 (also known as the alpha channel). This is disabled by
4496 default. Calling this function with use_opacity set to TRUE enables
4497 opacity. Likewise, use_opacity set to FALSE will disable opacity.
4500 void gtk_color_selection_set_color( GtkColorSelection *colorsel,
4504 You can set the current color explicitly by calling this function with
4505 a pointer to an array of colors (gdouble). The length of the array
4506 depends on whether opacity is enabled or not. Position 0 contains the
4507 red component, 1 is green, 2 is blue and opacity is at position 3
4508 (only if opacity is enabled, see
4509 gtk_color_selection_set_opacity()). All values are between 0.0 and
4513 void gtk_color_selection_get_color( GtkColorSelection *colorsel,
4517 When you need to query the current color, typically when you've
4518 received a "color_changed" signal, you use this function. Color is a
4519 pointer to the array of colors to fill in. See the
4520 gtk_color_selection_set_color() function for the description of this
4523 <!-- Need to do a whole section on DnD - TRG
4527 The color sample areas (right under the hue-saturation wheel) supports
4528 drag and drop. The type of drag and drop is "application/x-color". The
4529 message data consists of an array of 4 (or 5 if opacity is enabled)
4530 gdouble values, where the value at position 0 is 0.0 (opacity on) or
4531 1.0 (opacity off) followed by the red, green and blue values at
4532 positions 1,2 and 3 respectively. If opacity is enabled, the opacity
4533 is passed in the value at position 4.
4536 Here's a simple example demonstrating the use of the
4537 GtkColorSelectionDialog. The program displays a window containing a
4538 drawing area. Clicking on it opens a color selection dialog, and
4539 changing the color in the color selection dialog changes the
4543 /* example-start colorsel colorsel.c */
4546 #include <gdk/gdk.h>
4547 #include <gtk/gtk.h>
4549 GtkWidget *colorseldlg = NULL;
4550 GtkWidget *drawingarea = NULL;
4552 /* Color changed handler */
4554 void color_changed_cb (GtkWidget *widget, GtkColorSelection *colorsel)
4558 GdkColormap *colormap;
4560 /* Get drawingarea colormap */
4562 colormap = gdk_window_get_colormap (drawingarea->window);
4564 /* Get current color */
4566 gtk_color_selection_get_color (colorsel,color);
4568 /* Fit to a unsigned 16 bit integer (0..65535) and insert into the GdkColor structure */
4570 gdk_color.red = (guint16)(color[0]*65535.0);
4571 gdk_color.green = (guint16)(color[1]*65535.0);
4572 gdk_color.blue = (guint16)(color[2]*65535.0);
4574 /* Allocate color */
4576 gdk_color_alloc (colormap, &gdk_color);
4578 /* Set window background color */
4580 gdk_window_set_background (drawingarea->window, &gdk_color);
4584 gdk_window_clear (drawingarea->window);
4587 /* Drawingarea event handler */
4589 gint area_event (GtkWidget *widget, GdkEvent *event, gpointer client_data)
4591 gint handled = FALSE;
4592 GtkWidget *colorsel;
4594 /* Check if we've received a button pressed event */
4596 if (event->type == GDK_BUTTON_PRESS && colorseldlg == NULL)
4598 /* Yes, we have an event and there's no colorseldlg yet! */
4602 /* Create color selection dialog */
4604 colorseldlg = gtk_color_selection_dialog_new("Select background color");
4606 /* Get the GtkColorSelection widget */
4608 colorsel = GTK_COLOR_SELECTION_DIALOG(colorseldlg)->colorsel;
4610 /* Connect to the "color_changed" signal, set the client-data to the colorsel widget */
4612 gtk_signal_connect(GTK_OBJECT(colorsel), "color_changed",
4613 (GtkSignalFunc)color_changed_cb, (gpointer)colorsel);
4615 /* Show the dialog */
4617 gtk_widget_show(colorseldlg);
4623 /* Close down and exit handler */
4625 void destroy_window (GtkWidget *widget, gpointer client_data)
4632 gint main (gint argc, gchar *argv[])
4636 /* Initialize the toolkit, remove gtk-related commandline stuff */
4638 gtk_init (&argc,&argv);
4640 /* Create toplevel window, set title and policies */
4642 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4643 gtk_window_set_title (GTK_WINDOW(window), "Color selection test");
4644 gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, TRUE);
4646 /* Attach to the "delete" and "destroy" events so we can exit */
4648 gtk_signal_connect (GTK_OBJECT(window), "delete_event",
4649 (GtkSignalFunc)destroy_window, (gpointer)window);
4651 gtk_signal_connect (GTK_OBJECT(window), "destroy",
4652 (GtkSignalFunc)destroy_window, (gpointer)window);
4654 /* Create drawingarea, set size and catch button events */
4656 drawingarea = gtk_drawing_area_new ();
4658 gtk_drawing_area_size (GTK_DRAWING_AREA(drawingarea), 200, 200);
4660 gtk_widget_set_events (drawingarea, GDK_BUTTON_PRESS_MASK);
4662 gtk_signal_connect (GTK_OBJECT(drawingarea), "event",
4663 (GtkSignalFunc)area_event, (gpointer)drawingarea);
4665 /* Add drawingarea to window, then show them both */
4667 gtk_container_add (GTK_CONTAINER(window), drawingarea);
4669 gtk_widget_show (drawingarea);
4670 gtk_widget_show (window);
4672 /* Enter the gtk main loop (this never returns) */
4676 /* Satisfy grumpy compilers */
4683 <!-- ----------------------------------------------------------------- -->
4684 <sect1> File Selections
4686 The file selection widget is a quick and simple way to display a File
4687 dialog box. It comes complete with Ok, Cancel, and Help buttons, a
4688 great way to cut down on programming time.
4690 To create a new file selection box use:
4693 GtkWidget *gtk_file_selection_new( gchar *title );
4696 To set the filename, for example to bring up a specific directory, or
4697 give a default filename, use this function:
4700 void gtk_file_selection_set_filename( GtkFileSelection *filesel,
4704 To grab the text that the user has entered or clicked on, use this
4708 gchar *gtk_file_selection_get_filename( GtkFileSelection *filesel );
4711 There are also pointers to the widgets contained within the file
4712 selection widget. These are:
4717 <item>selection_entry
4718 <item>selection_text
4725 Most likely you will want to use the ok_button, cancel_button, and
4726 help_button pointers in signaling their use.
4728 Included here is an example stolen from testgtk.c, modified to run on
4729 its own. As you will see, there is nothing much to creating a file
4730 selection widget. While in this example the Help button appears on the
4731 screen, it does nothing as there is not a signal attached to it.
4734 /* example-start filesel filesel.c */
4736 #include <gtk/gtk.h>
4738 /* Get the selected filename and print it to the console */
4739 void file_ok_sel (GtkWidget *w, GtkFileSelection *fs)
4741 g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
4744 void destroy (GtkWidget *widget, gpointer data)
4749 int main (int argc, char *argv[])
4753 gtk_init (&argc, &argv);
4755 /* Create a new file selection widget */
4756 filew = gtk_file_selection_new ("File selection");
4758 gtk_signal_connect (GTK_OBJECT (filew), "destroy",
4759 (GtkSignalFunc) destroy, &filew);
4760 /* Connect the ok_button to file_ok_sel function */
4761 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
4762 "clicked", (GtkSignalFunc) file_ok_sel, filew );
4764 /* Connect the cancel_button to destroy the widget */
4765 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button),
4766 "clicked", (GtkSignalFunc) gtk_widget_destroy,
4767 GTK_OBJECT (filew));
4769 /* Lets set the filename, as if this were a save dialog, and we are giving
4770 a default filename */
4771 gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew),
4774 gtk_widget_show(filew);
4781 <!-- ***************************************************************** -->
4782 <sect> Container Widgets
4783 <!-- ***************************************************************** -->
4785 <!-- ----------------------------------------------------------------- -->
4788 The NoteBook Widget is a collection of 'pages' that overlap each
4789 other, each page contains different information. This widget has
4790 become more common lately in GUI programming, and it is a good way to
4791 show blocks of similar information that warrant separation in their
4794 The first function call you will need to know, as you can probably
4795 guess by now, is used to create a new notebook widget.
4798 GtkWidget *gtk_notebook_new( void );
4801 Once the notebook has been created, there are a number of functions
4802 that operate on the notebook widget. Let's look at them individually.
4804 The first one we will look at is how to position the page indicators.
4805 These page indicators or 'tabs' as they are referred to, can be
4806 positioned in four ways: top, bottom, left, or right.
4809 void gtk_notebook_set_tab_pos( GtkNotebook *notebook,
4810 GtkPositionType pos );
4813 GtkPostionType will be one of the following, and they are pretty self explanatory:
4816 <item> GTK_POS_RIGHT
4818 <item> GTK_POS_BOTTOM
4821 GTK_POS_TOP is the default.
4823 Next we will look at how to add pages to the notebook. There are three
4824 ways to add pages to the NoteBook. Let's look at the first two
4825 together as they are quite similar.
4828 void gtk_notebook_append_page( GtkNotebook *notebook,
4830 GtkWidget *tab_label );
4832 void gtk_notebook_prepend_page( GtkNotebook *notebook,
4834 GtkWidget *tab_label );
4837 These functions add pages to the notebook by inserting them from the
4838 back of the notebook (append), or the front of the notebook (prepend).
4839 <tt/child/ is the widget that is placed within the notebook page, and
4840 <tt/tab_label/ is the label for the page being added. The <tt/child/
4841 widget must be created separately, and is typically a set of options
4842 setout witin one of the other container widgets, such as a table.
4844 The final function for adding a page to the notebook contains all of
4845 the properties of the previous two, but it allows you to specify what
4846 position you want the page to be in the notebook.
4849 void gtk_notebook_insert_page( GtkNotebook *notebook,
4851 GtkWidget *tab_label,
4855 The parameters are the same as _append_ and _prepend_ except it
4856 contains an extra parameter, <tt/position/. This parameter is used to
4857 specify what place this page will be inserted into.
4859 Now that we know how to add a page, lets see how we can remove a page
4863 void gtk_notebook_remove_page( GtkNotebook *notebook,
4867 This function takes the page specified by <tt/page_num/ and removes it
4868 from the widget pointed to by <tt/notebook/.
4870 To find out what the current page is in a notebook use the function:
4873 gint gtk_notebook_get_current_page( GtkNotebook *notebook );
4876 These next two functions are simple calls to move the notebook page
4877 forward or backward. Simply provide the respective function call with
4878 the notebook widget you wish to operate on. Note: when the NoteBook is
4879 currently on the last page, and gtk_notebook_next_page is called, the
4880 notebook will wrap back to the first page. Likewise, if the NoteBook
4881 is on the first page, and gtk_notebook_prev_page is called, the
4882 notebook will wrap to the last page.
4885 void gtk_notebook_next_page( GtkNoteBook *notebook );
4887 void gtk_notebook_prev_page( GtkNoteBook *notebook );
4890 This next function sets the 'active' page. If you wish the notebook to
4891 be opened to page 5 for example, you would use this function. Without
4892 using this function, the notebook defaults to the first page.
4895 void gtk_notebook_set_page( GtkNotebook *notebook,
4899 The next two functions add or remove the notebook page tabs and the
4900 notebook border respectively.
4903 void gtk_notebook_set_show_tabs( GtkNotebook *notebook,
4904 gboolean show_tabs);
4906 void gtk_notebook_set_show_border( GtkNotebook *notebook,
4907 gboolean show_border );
4910 The next function is useful when the you have a large number of pages,
4911 and the tabs don't fit on the page. It allows the tabs to be scrolled
4912 through using two arrow buttons.
4915 void gtk_notebook_set_scrollable( GtkNotebook *notebook,
4916 gboolean scrollable );
4919 <tt/show_tabs/, <tt/show_border/ and <tt/scrollable/ can be either
4922 Now lets look at an example, it is expanded from the testgtk.c code
4923 that comes with the GTK distribution. This small program creates a
4924 window with a notebook and six buttons. The notebook contains 11
4925 pages, added in three different ways, appended, inserted, and
4926 prepended. The buttons allow you rotate the tab positions, add/remove
4927 the tabs and border, remove a page, change pages in both a forward and
4928 backward manner, and exit the program.
4931 /* example-start notebook notebook.c */
4933 #include <gtk/gtk.h>
4935 /* This function rotates the position of the tabs */
4936 void rotate_book (GtkButton *button, GtkNotebook *notebook)
4938 gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos +1) %4);
4941 /* Add/Remove the page tabs and the borders */
4942 void tabsborder_book (GtkButton *button, GtkNotebook *notebook)
4946 if (notebook->show_tabs == 0)
4948 if (notebook->show_border == 0)
4951 gtk_notebook_set_show_tabs (notebook, tval);
4952 gtk_notebook_set_show_border (notebook, bval);
4955 /* Remove a page from the notebook */
4956 void remove_book (GtkButton *button, GtkNotebook *notebook)
4960 page = gtk_notebook_get_current_page(notebook);
4961 gtk_notebook_remove_page (notebook, page);
4962 /* Need to refresh the widget --
4963 This forces the widget to redraw itself. */
4964 gtk_widget_draw(GTK_WIDGET(notebook), NULL);
4967 void delete (GtkWidget *widget, GtkWidget *event, gpointer data)
4972 int main (int argc, char *argv[])
4977 GtkWidget *notebook;
4980 GtkWidget *checkbutton;
4985 gtk_init (&argc, &argv);
4987 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4989 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
4990 GTK_SIGNAL_FUNC (delete), NULL);
4992 gtk_container_border_width (GTK_CONTAINER (window), 10);
4994 table = gtk_table_new(3,6,FALSE);
4995 gtk_container_add (GTK_CONTAINER (window), table);
4997 /* Create a new notebook, place the position of the tabs */
4998 notebook = gtk_notebook_new ();
4999 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
5000 gtk_table_attach_defaults(GTK_TABLE(table), notebook, 0,6,0,1);
5001 gtk_widget_show(notebook);
5003 /* Lets append a bunch of pages to the notebook */
5004 for (i=0; i < 5; i++) {
5005 sprintf(bufferf, "Append Frame %d", i+1);
5006 sprintf(bufferl, "Page %d", i+1);
5008 frame = gtk_frame_new (bufferf);
5009 gtk_container_border_width (GTK_CONTAINER (frame), 10);
5010 gtk_widget_set_usize (frame, 100, 75);
5011 gtk_widget_show (frame);
5013 label = gtk_label_new (bufferf);
5014 gtk_container_add (GTK_CONTAINER (frame), label);
5015 gtk_widget_show (label);
5017 label = gtk_label_new (bufferl);
5018 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
5021 /* Now lets add a page to a specific spot */
5022 checkbutton = gtk_check_button_new_with_label ("Check me please!");
5023 gtk_widget_set_usize(checkbutton, 100, 75);
5024 gtk_widget_show (checkbutton);
5026 label = gtk_label_new ("Add page");
5027 gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, label, 2);
5029 /* Now finally lets prepend pages to the notebook */
5030 for (i=0; i < 5; i++) {
5031 sprintf(bufferf, "Prepend Frame %d", i+1);
5032 sprintf(bufferl, "PPage %d", i+1);
5034 frame = gtk_frame_new (bufferf);
5035 gtk_container_border_width (GTK_CONTAINER (frame), 10);
5036 gtk_widget_set_usize (frame, 100, 75);
5037 gtk_widget_show (frame);
5039 label = gtk_label_new (bufferf);
5040 gtk_container_add (GTK_CONTAINER (frame), label);
5041 gtk_widget_show (label);
5043 label = gtk_label_new (bufferl);
5044 gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook), frame, label);
5047 /* Set what page to start at (page 4) */
5048 gtk_notebook_set_page (GTK_NOTEBOOK(notebook), 3);
5050 /* Create a bunch of buttons */
5051 button = gtk_button_new_with_label ("close");
5052 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
5053 GTK_SIGNAL_FUNC (delete), NULL);
5054 gtk_table_attach_defaults(GTK_TABLE(table), button, 0,1,1,2);
5055 gtk_widget_show(button);
5057 button = gtk_button_new_with_label ("next page");
5058 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
5059 (GtkSignalFunc) gtk_notebook_next_page,
5060 GTK_OBJECT (notebook));
5061 gtk_table_attach_defaults(GTK_TABLE(table), button, 1,2,1,2);
5062 gtk_widget_show(button);
5064 button = gtk_button_new_with_label ("prev page");
5065 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
5066 (GtkSignalFunc) gtk_notebook_prev_page,
5067 GTK_OBJECT (notebook));
5068 gtk_table_attach_defaults(GTK_TABLE(table), button, 2,3,1,2);
5069 gtk_widget_show(button);
5071 button = gtk_button_new_with_label ("tab position");
5072 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
5073 (GtkSignalFunc) rotate_book, GTK_OBJECT(notebook));
5074 gtk_table_attach_defaults(GTK_TABLE(table), button, 3,4,1,2);
5075 gtk_widget_show(button);
5077 button = gtk_button_new_with_label ("tabs/border on/off");
5078 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
5079 (GtkSignalFunc) tabsborder_book,
5080 GTK_OBJECT (notebook));
5081 gtk_table_attach_defaults(GTK_TABLE(table), button, 4,5,1,2);
5082 gtk_widget_show(button);
5084 button = gtk_button_new_with_label ("remove page");
5085 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
5086 (GtkSignalFunc) remove_book,
5087 GTK_OBJECT(notebook));
5088 gtk_table_attach_defaults(GTK_TABLE(table), button, 5,6,1,2);
5089 gtk_widget_show(button);
5091 gtk_widget_show(table);
5092 gtk_widget_show(window);
5101 Hopefully this helps you on your way with creating notebooks for your
5104 <!-- ----------------------------------------------------------------- -->
5105 <sect1>Scrolled Windows
5107 Scrolled windows are used to create a scrollable area inside a real
5108 window. You may insert any type of widget into a scrolled window, and
5109 it will be accessible regardless of the size by using the scrollbars.
5111 The following function is used to create a new scrolled window.
5114 GtkWidget *gtk_scrolled_window_new( GtkAdjustment *hadjustment,
5115 GtkAdjustment *vadjustment );
5118 Where the first argument is the adjustment for the horizontal
5119 direction, and the second, the adjustment for the vertical direction.
5120 These are almost always set to NULL.
5123 void gtk_scrolled_window_set_policy( GtkScrolledWindow *scrolled_window,
5124 GtkPolicyType hscrollbar_policy,
5125 GtkPolicyType vscrollbar_policy );
5128 This sets the policy to be used with respect to the scrollbars.
5129 The first argument is the scrolled window you wish to change. The second
5130 sets the policy for the horizontal scrollbar, and the third the policy for
5131 the vertical scrollbar.
5133 The policy may be one of GTK_POLICY_AUTOMATIC, or GTK_POLICY_ALWAYS.
5134 GTK_POLICY_AUTOMATIC will automatically decide whether you need
5135 scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars
5138 You can then place your object into the scrolled window using the
5142 void gtk_scrolled_window_add_with_viewport( GtkScrolledWindow *scrolled_window,
5146 Here is a simple example that packs 100 toggle buttons into a scrolled
5147 window. I've only commented on the parts that may be new to you.
5150 /* example-start scrolledwin scrolledwin.c */
5152 #include <gtk/gtk.h>
5154 void destroy(GtkWidget *widget, gpointer data)
5159 int main (int argc, char *argv[])
5161 static GtkWidget *window;
5162 GtkWidget *scrolled_window;
5168 gtk_init (&argc, &argv);
5170 /* Create a new dialog window for the scrolled window to be
5171 * packed into. A dialog is just like a normal window except it has a
5172 * vbox and a horizontal separator packed into it. It's just a shortcut
5173 * for creating dialogs */
5174 window = gtk_dialog_new ();
5175 gtk_signal_connect (GTK_OBJECT (window), "destroy",
5176 (GtkSignalFunc) destroy, NULL);
5177 gtk_window_set_title (GTK_WINDOW (window), "GtkScrolledWindow example");
5178 gtk_container_border_width (GTK_CONTAINER (window), 0);
5179 gtk_widget_set_usize(window, 300, 300);
5181 /* create a new scrolled window. */
5182 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
5184 gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10);
5186 /* the policy is one of GTK_POLICY AUTOMATIC, or GTK_POLICY_ALWAYS.
5187 * GTK_POLICY_AUTOMATIC will automatically decide whether you need
5188 * scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars
5189 * there. The first one is the horizontal scrollbar, the second,
5191 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
5192 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
5193 /* The dialog window is created with a vbox packed into it. */
5194 gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)->vbox), scrolled_window,
5196 gtk_widget_show (scrolled_window);
5198 /* create a table of 10 by 10 squares. */
5199 table = gtk_table_new (10, 10, FALSE);
5201 /* set the spacing to 10 on x and 10 on y */
5202 gtk_table_set_row_spacings (GTK_TABLE (table), 10);
5203 gtk_table_set_col_spacings (GTK_TABLE (table), 10);
5205 /* pack the table into the scrolled window */
5206 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window),
5208 gtk_widget_show (table);
5210 /* this simply creates a grid of toggle buttons on the table
5211 * to demonstrate the scrolled window. */
5212 for (i = 0; i < 10; i++)
5213 for (j = 0; j < 10; j++) {
5214 sprintf (buffer, "button (%d,%d)\n", i, j);
5215 button = gtk_toggle_button_new_with_label (buffer);
5216 gtk_table_attach_defaults (GTK_TABLE (table), button,
5218 gtk_widget_show (button);
5221 /* Add a "close" button to the bottom of the dialog */
5222 button = gtk_button_new_with_label ("close");
5223 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
5224 (GtkSignalFunc) gtk_widget_destroy,
5225 GTK_OBJECT (window));
5227 /* this makes it so the button is the default. */
5229 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
5230 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0);
5232 /* This grabs this button to be the default button. Simply hitting
5233 * the "Enter" key will cause this button to activate. */
5234 gtk_widget_grab_default (button);
5235 gtk_widget_show (button);
5237 gtk_widget_show (window);
5246 Try playing with resizing the window. You'll notice how the scrollbars
5247 react. You may also wish to use the gtk_widget_set_usize() call to set
5248 the default size of the window or other widgets.
5250 <!-- ----------------------------------------------------------------- -->
5251 <sect1> Paned Window Widgets
5253 The paned window widgets are useful when you want to divide an area
5254 into two parts, with the relative size of the two parts controlled by
5255 the user. A groove is drawn between the two portions with a handle
5256 that the user can drag to change the ratio. The division can either be
5257 horizontal (HPaned) or vertical (VPaned).
5259 To create a new paned window, call one of:
5262 GtkWidget *gtk_hpaned_new (void);
5264 GtkWidget *gtk_vpaned_new (void);
5267 After creating the paned window widget, you need to add child widgets
5268 to its two halves. To do this, use the functions:
5271 void gtk_paned_add1 (GtkPaned *paned, GtkWidget *child);
5273 void gtk_paned_add2 (GtkPaned *paned, GtkWidget *child);
5276 <tt/gtk_paned_add1()/ adds the child widget to the left or top half of
5277 the paned window. <tt/gtk_paned_add2()/ adds the child widget to the
5278 right or bottom half of the paned window.
5280 A paned widget can be changed visually using the following two
5284 void gtk_paned_set_handle_size( GtkPaned *paned,
5287 void gtk_paned_set_gutter_size( GtkPaned *paned,
5291 The first of these sets the size of the handle and the second sets the
5292 size of the gutter that is between the two parts of the paned window.
5294 As an example, we will create part of the user interface of an
5295 imaginary email program. A window is divided into two portions
5296 vertically, with the top portion being a list of email messages and
5297 the bottom portion the text of the email message. Most of the program
5298 is pretty straightforward. A couple of points to note: text can't be
5299 added to a Text widget until it is realized. This could be done by
5300 calling <tt/gtk_widget_realize()/, but as a demonstration of an
5301 alternate technique, we connect a handler to the "realize" signal to
5302 add the text. Also, we need to add the <tt/GTK_SHRINK/ option to some
5303 of the items in the table containing the text window and its
5304 scrollbars, so that when the bottom portion is made smaller, the
5305 correct portions shrink instead of being pushed off the bottom of the
5309 /* example-start paned paned.c */
5311 #include <gtk/gtk.h>
5313 /* Create the list of "messages" */
5318 GtkWidget *scrolled_window;
5320 GtkWidget *list_item;
5325 /* Create a new scrolled window, with scrollbars only if needed */
5326 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
5327 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
5328 GTK_POLICY_AUTOMATIC,
5329 GTK_POLICY_AUTOMATIC);
5331 /* Create a new list and put it in the scrolled window */
5332 list = gtk_list_new ();
5333 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window),
5335 gtk_widget_show (list);
5337 /* Add some messages to the window */
5338 for (i=0; i<10; i++) {
5340 sprintf(buffer,"Message #%d",i);
5341 list_item = gtk_list_item_new_with_label (buffer);
5342 gtk_container_add (GTK_CONTAINER(list), list_item);
5343 gtk_widget_show (list_item);
5347 return scrolled_window;
5350 /* Add some text to our text widget - this is a callback that is invoked
5351 when our window is realized. We could also force our window to be
5352 realized with gtk_widget_realize, but it would have to be part of
5353 a hierarchy first */
5356 realize_text (GtkWidget *text, gpointer data)
5358 gtk_text_freeze (GTK_TEXT (text));
5359 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
5360 "From: pathfinder@nasa.gov\n"
5361 "To: mom@nasa.gov\n"
5362 "Subject: Made it!\n"
5364 "We just got in this morning. The weather has been\n"
5365 "great - clear but cold, and there are lots of fun sights.\n"
5366 "Sojourner says hi. See you soon.\n"
5369 gtk_text_thaw (GTK_TEXT (text));
5372 /* Create a scrolled text area that displays a "message" */
5378 GtkWidget *hscrollbar;
5379 GtkWidget *vscrollbar;
5381 /* Create a table to hold the text widget and scrollbars */
5382 table = gtk_table_new (2, 2, FALSE);
5384 /* Put a text widget in the upper left hand corner. Note the use of
5385 * GTK_SHRINK in the y direction */
5386 text = gtk_text_new (NULL, NULL);
5387 gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
5388 GTK_FILL | GTK_EXPAND,
5389 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
5390 gtk_widget_show (text);
5392 /* Put a HScrollbar in the lower left hand corner */
5393 hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
5394 gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
5395 GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
5396 gtk_widget_show (hscrollbar);
5398 /* And a VScrollbar in the upper right */
5399 vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
5400 gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
5401 GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
5402 gtk_widget_show (vscrollbar);
5404 /* Add a handler to put a message in the text widget when it is realized */
5405 gtk_signal_connect (GTK_OBJECT (text), "realize",
5406 GTK_SIGNAL_FUNC (realize_text), NULL);
5412 main (int argc, char *argv[])
5419 gtk_init (&argc, &argv);
5421 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5422 gtk_window_set_title (GTK_WINDOW (window), "Paned Windows");
5423 gtk_signal_connect (GTK_OBJECT (window), "destroy",
5424 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
5425 gtk_container_border_width (GTK_CONTAINER (window), 10);
5426 gtk_widget_set_usize (GTK_WIDGET(window), 450, 400);
5428 /* create a vpaned widget and add it to our toplevel window */
5430 vpaned = gtk_vpaned_new ();
5431 gtk_container_add (GTK_CONTAINER(window), vpaned);
5432 gtk_paned_set_handle_size (GTK_PANED(vpaned),
5434 gtk_paned_set_gutter_size (GTK_PANED(vpaned),
5436 gtk_widget_show (vpaned);
5438 /* Now create the contents of the two halves of the window */
5440 list = create_list ();
5441 gtk_paned_add1 (GTK_PANED(vpaned), list);
5442 gtk_widget_show (list);
5444 text = create_text ();
5445 gtk_paned_add2 (GTK_PANED(vpaned), text);
5446 gtk_widget_show (text);
5447 gtk_widget_show (window);
5454 <!-- ----------------------------------------------------------------- -->
5457 Toolbars are usually used to group some number of widgets in order to
5458 simplify customization of their look and layout. Typically a toolbar
5459 consists of buttons with icons, labels and tooltips, but any other
5460 widget can also be put inside a toolbar. Finally, items can be
5461 arranged horizontally or vertically and buttons can be displayed with
5462 icons, labels or both.
5464 Creating a toolbar is (as one may already suspect) done with the
5468 GtkWidget *gtk_toolbar_new( GtkOrientation orientation,
5469 GtkToolbarStyle style );
5472 where orientation may be one of:
5475 GTK_ORIENTATION_HORIZONTAL
5476 GTK_ORIENTATION_VERTICAL
5487 The style applies to all the buttons created with the `item' functions
5488 (not to buttons inserted into toolbar as separate widgets).
5490 After creating a toolbar one can append, prepend and insert items
5491 (that means simple buttons) into the toolbar. To describe an item we
5492 need a label text, a tooltip text, a private tooltip text, an icon for
5493 the button and a callback function for it. For example, to append or
5494 prepend an item you may use the following functions:
5497 GtkWidget *gtk_toolbar_append_item( GtkToolbar *toolbar,
5499 const char *tooltip_text,
5500 const char *tooltip_private_text,
5502 GtkSignalFunc callback,
5503 gpointer user_data );
5505 GtkWidget *gtk_toolbar_prepend_item( GtkToolbar *toolbar,
5507 const char *tooltip_text,
5508 const char *tooltip_private_text,
5510 GtkSignalFunc callback,
5511 gpointer user_data );
5514 If you want to use gtk_toolbar_insert_item, the only additional
5515 parameter which must be specified is the position in which the item
5516 should be inserted, thus:
5519 GtkWidget *gtk_toolbar_insert_item( GtkToolbar *toolbar,
5521 const char *tooltip_text,
5522 const char *tooltip_private_text,
5524 GtkSignalFunc callback,
5529 To simplify adding spaces between toolbar items, you may use the
5530 following functions:
5533 void gtk_toolbar_append_space( GtkToolbar *toolbar );
5535 void gtk_toolbar_prepend_space( GtkToolbar *toolbar );
5537 void gtk_toolbar_insert_space( GtkToolbar *toolbar,
5542 While the size of the added space can be set globally for a
5543 whole toolbar with the function:
5546 void gtk_toolbar_set_space_size( GtkToolbar *toolbar,
5550 If it's required, the orientation of a toolbar and its style can be
5551 changed `on the fly' using the following functions:
5554 void gtk_toolbar_set_orientation( GtkToolbar *toolbar,
5555 GtkOrientation orientation );
5557 void gtk_toolbar_set_style( GtkToolbar *toolbar,
5558 GtkToolbarStyle style );
5560 void gtk_toolbar_set_tooltips( GtkToolbar *toolbar,
5564 Where <tt/orientation/ is one of GTK_ORIENTATION_HORIZONTAL or
5565 GTK_ORIENTATION_VERTICAL. The <tt/style/ is used to set appearance of
5566 the toolbar items by using one of GTK_TOOLBAR_ICONS, GTK_TOOLBAR_TEXT
5567 or GTK_TOOLBAR_BOTH.
5569 To show some other things that can be done with a toolbar, let's take
5570 the following program (we'll interrupt the listing with some
5571 additional explanations):
5574 #include <gtk/gtk.h>
5578 /* This function is connected to the Close button or
5579 * closing the window from the WM */
5580 void delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
5586 The above beginning seems for sure familiar to you if it's not your first
5587 GTK program. There is one additional thing though, we include a nice XPM
5588 picture to serve as an icon for all of the buttons.
5591 GtkWidget* close_button; // this button will emit signal to close application
5592 GtkWidget* tooltips_button; // to enable/disable tooltips
5593 GtkWidget* text_button,
5595 * both_button; // radio buttons for toolbar style
5596 GtkWidget* entry; // a text entry to show packing any widget into toolbar
5599 In fact not all of the above widgets are needed here, but to make things
5600 clearer I put them all together.
5603 /* that's easy... when one of the buttons is toggled, we just
5604 * check which one is active and set the style of the toolbar
5606 * ATTENTION: our toolbar is passed as data to callback ! */
5607 void radio_event (GtkWidget *widget, gpointer data)
5609 if (GTK_TOGGLE_BUTTON (text_button)->active)
5610 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_TEXT);
5611 else if (GTK_TOGGLE_BUTTON (icon_button)->active)
5612 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_ICONS);
5613 else if (GTK_TOGGLE_BUTTON (both_button)->active)
5614 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_BOTH);
5617 /* even easier, just check given toggle button and enable/disable
5619 void toggle_event (GtkWidget *widget, gpointer data)
5621 gtk_toolbar_set_tooltips (GTK_TOOLBAR ( data ),
5622 GTK_TOGGLE_BUTTON (widget)->active );
5626 The above are just two callback functions that will be called when
5627 one of the buttons on a toolbar is pressed. You should already be
5628 familiar with things like this if you've already used toggle buttons (and
5632 int main (int argc, char *argv[])
5634 /* Here is our main window (a dialog) and a handle for the handlebox */
5636 GtkWidget* handlebox;
5638 /* Ok, we need a toolbar, an icon with a mask (one for all of
5639 the buttons) and an icon widget to put this icon in (but
5640 we'll create a separate widget for each button) */
5641 GtkWidget * toolbar;
5646 /* this is called in all GTK application. */
5647 gtk_init (&argc, &argv);
5649 /* create a new window with a given title, and nice size */
5650 dialog = gtk_dialog_new ();
5651 gtk_window_set_title ( GTK_WINDOW ( dialog ) , "GTKToolbar Tutorial");
5652 gtk_widget_set_usize( GTK_WIDGET ( dialog ) , 600 , 300 );
5653 GTK_WINDOW ( dialog ) ->allow_shrink = TRUE;
5655 /* typically we quit if someone tries to close us */
5656 gtk_signal_connect ( GTK_OBJECT ( dialog ), "delete_event",
5657 GTK_SIGNAL_FUNC ( delete_event ), NULL);
5659 /* we need to realize the window because we use pixmaps for
5660 * items on the toolbar in the context of it */
5661 gtk_widget_realize ( dialog );
5663 /* to make it nice we'll put the toolbar into the handle box,
5664 * so that it can be detached from the main window */
5665 handlebox = gtk_handle_box_new ();
5666 gtk_box_pack_start ( GTK_BOX ( GTK_DIALOG(dialog)->vbox ),
5667 handlebox, FALSE, FALSE, 5 );
5670 The above should be similar to any other GTK application. Just
5671 initialization of GTK, creating the window etc.. There is only one
5672 thing that probably needs some explanation: a handle box. A handle box
5673 is just another box that can be used to pack widgets in to. The
5674 difference between it and typical boxes is that it can be detached
5675 from a parent window (or, in fact, the handle box remains in the
5676 parent, but it is reduced to a very small rectangle, while all of its
5677 contents are reparented to a new freely floating window). It is
5678 usually nice to have a detachable toolbar, so these two widgets occur
5679 together quite often.
5682 /* toolbar will be horizontal, with both icons and text, and
5683 * with 5pxl spaces between items and finally,
5684 * we'll also put it into our handlebox */
5685 toolbar = gtk_toolbar_new ( GTK_ORIENTATION_HORIZONTAL,
5687 gtk_container_border_width ( GTK_CONTAINER ( toolbar ) , 5 );
5688 gtk_toolbar_set_space_size ( GTK_TOOLBAR ( toolbar ), 5 );
5689 gtk_container_add ( GTK_CONTAINER ( handlebox ) , toolbar );
5691 /* now we create icon with mask: we'll reuse it to create
5692 * icon widgets for toolbar items */
5693 icon = gdk_pixmap_create_from_xpm_d ( dialog->window, &mask,
5694 &dialog->style->white, gtk_xpm );
5697 Well, what we do above is just a straight-forward initialization of
5698 the toolbar widget and creation of a GDK pixmap with its mask. If you
5699 want to know something more about using pixmaps, refer to GDK
5700 documentation or to the <ref id="sec_Pixmaps" name="Pixmaps"> section
5701 earlier in this tutorial.
5704 /* our first item is <close> button */
5705 iconw = gtk_pixmap_new ( icon, mask ); // icon widget
5707 gtk_toolbar_append_item ( GTK_TOOLBAR (toolbar), // our toolbar
5708 "Close", // button label
5709 "Closes this app", // tooltip for this button
5710 "Private", // tooltip private string
5711 iconw, // icon widget
5712 GTK_SIGNAL_FUNC (delete_event), // a signal
5714 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) ); // space after item
5717 In the above code you see the simplest case: adding a button to
5718 toolbar. Just before appending a new item, we have to construct a
5719 pixmap widget to serve as an icon for this item; this step will have
5720 to be repeated for each new item. Just after the item we also add a
5721 space, so the following items will not touch each other. As you see
5722 gtk_toolbar_append_item returns a pointer to our newly created button
5723 widget, so that we can work with it in the normal way.
5726 /* now, let's make our radio buttons group... */
5727 iconw = gtk_pixmap_new ( icon, mask );
5729 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
5730 GTK_TOOLBAR_CHILD_RADIOBUTTON, // a type of element
5731 NULL, // pointer to widget
5733 "Only icons in toolbar", // tooltip
5734 "Private", // tooltip private string
5736 GTK_SIGNAL_FUNC (radio_event), // signal
5737 toolbar); // data for signal
5738 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
5741 Here we begin creating a radio buttons group. To do this we use
5742 gtk_toolbar_append_element. In fact, using this function one can also
5743 add simple items or even spaces (type = GTK_TOOLBAR_CHILD_SPACE or
5744 GTK_TOOLBAR_CHILD_BUTTON). In the above case we start creating a radio
5745 group. In creating other radio buttons for this group a pointer to the
5746 previous button in the group is required, so that a list of buttons
5747 can be easily constructed (see the section on <ref
5748 id="sec_Radio_Buttons" name="Radio Buttons"> earlier in this
5752 /* following radio buttons refer to previous ones */
5753 iconw = gtk_pixmap_new ( icon, mask );
5755 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
5756 GTK_TOOLBAR_CHILD_RADIOBUTTON,
5759 "Only texts in toolbar",
5762 GTK_SIGNAL_FUNC (radio_event),
5764 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
5766 iconw = gtk_pixmap_new ( icon, mask );
5768 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
5769 GTK_TOOLBAR_CHILD_RADIOBUTTON,
5772 "Icons and text in toolbar",
5775 GTK_SIGNAL_FUNC (radio_event),
5777 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
5778 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(both_button),TRUE);
5781 In the end we have set the state of one of the buttons manually (otherwise
5782 they all stay in active state, preventing us from switching between them).
5785 /* here we have just a simple toggle button */
5786 iconw = gtk_pixmap_new ( icon, mask );
5788 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
5789 GTK_TOOLBAR_CHILD_TOGGLEBUTTON,
5792 "Toolbar with or without tips",
5795 GTK_SIGNAL_FUNC (toggle_event),
5797 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
5798 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(tooltips_button),TRUE);
5801 A toggle button can be created in the obvious way (if one knows how to create
5802 radio buttons already).
5805 /* to pack a widget into toolbar, we only have to
5806 * create it and append it with an appropriate tooltip */
5807 entry = gtk_entry_new ();
5808 gtk_toolbar_append_widget( GTK_TOOLBAR (toolbar),
5810 "This is just an entry",
5813 /* well, it isn't created within thetoolbar, so we must still show it */
5814 gtk_widget_show ( entry );
5817 As you see, adding any kind of widget to a toolbar is simple. The
5818 one thing you have to remember is that this widget must be shown manually
5819 (contrary to other items which will be shown together with the toolbar).
5822 /* that's it ! let's show everything. */
5823 gtk_widget_show ( toolbar );
5824 gtk_widget_show (handlebox);
5825 gtk_widget_show ( dialog );
5827 /* rest in gtk_main and wait for the fun to begin! */
5834 So, here we are at the end of toolbar tutorial. Of course, to appreciate
5835 it in full you need also this nice XPM icon, so here it is:
5839 static char * gtk_xpm[] = {
5846 "................+...............",
5847 "..............+++++.............",
5848 "............+++++@@++...........",
5849 "..........+++++@@@@@@++.........",
5850 "........++++@@@@@@@@@@++........",
5851 "......++++@@++++++++@@@++.......",
5852 ".....+++@@@+++++++++++@@@++.....",
5853 "...+++@@@@+++@@@@@@++++@@@@+....",
5854 "..+++@@@@+++@@@@@@@@+++@@@@@++..",
5855 ".++@@@@@@+++@@@@@@@@@@@@@@@@@@++",
5856 ".+#+@@@@@@++@@@@+++@@@@@@@@@@@@+",
5857 ".+##++@@@@+++@@@+++++@@@@@@@@$@.",
5858 ".+###++@@@@+++@@@+++@@@@@++$$$@.",
5859 ".+####+++@@@+++++++@@@@@+@$$$$@.",
5860 ".+#####+++@@@@+++@@@@++@$$$$$$+.",
5861 ".+######++++@@@@@@@++@$$$$$$$$+.",
5862 ".+#######+##+@@@@+++$$$$$$@@$$+.",
5863 ".+###+++##+##+@@++@$$$$$$++$$$+.",
5864 ".+###++++##+##+@@$$$$$$$@+@$$@+.",
5865 ".+###++++++#+++@$$@+@$$@++$$$@+.",
5866 ".+####+++++++#++$$@+@$$++$$$$+..",
5867 ".++####++++++#++$$@+@$++@$$$$+..",
5868 ".+#####+++++##++$$++@+++$$$$$+..",
5869 ".++####+++##+#++$$+++++@$$$$$+..",
5870 ".++####+++####++$$++++++@$$$@+..",
5871 ".+#####++#####++$$+++@++++@$@+..",
5872 ".+#####++#####++$$++@$$@+++$@@..",
5873 ".++####++#####++$$++$$$$$+@$@++.",
5874 ".++####++#####++$$++$$$$$$$$+++.",
5875 ".+++####+#####++$$++$$$$$$$@+++.",
5876 "..+++#########+@$$+@$$$$$$+++...",
5877 "...+++########+@$$$$$$$$@+++....",
5878 ".....+++######+@$$$$$$$+++......",
5879 "......+++#####+@$$$$$@++........",
5880 ".......+++####+@$$$$+++.........",
5881 ".........++###+$$$@++...........",
5882 "..........++##+$@+++............",
5883 "...........+++++++..............",
5884 ".............++++..............."};
5887 <!-- ----------------------------------------------------------------- -->
5888 <sect1> Aspect Frames
5890 The aspect frame widget is like a frame widget, except that it also
5891 enforces the aspect ratio (that is, the ratio of the width to the
5892 height) of the child widget to have a certain value, adding extra
5893 space if necessary. This is useful, for instance, if you want to
5894 preview a larger image. The size of the preview should vary when the
5895 user resizes the window, but the aspect ratio needs to always match
5898 To create a new aspect frame use:
5901 GtkWidget *gtk_aspect_frame_new( const gchar *label,
5908 <tt/xalign/ and <tt/yalign/ specify alignment as with Alignment
5909 widgets. If <tt/obey_child/ is true, the aspect ratio of a child
5910 widget will match the aspect ratio of the ideal size it requests.
5911 Otherwise, it is given by <tt/ratio/.
5913 To change the options of an existing aspect frame, you can use:
5916 void gtk_aspect_frame_set( GtkAspectFrame *aspect_frame,
5923 As an example, the following program uses an AspectFrame to present a
5924 drawing area whose aspect ratio will always be 2:1, no matter how the
5925 user resizes the top-level window.
5928 /* example-start aspectframe aspectframe.c */
5930 #include <gtk/gtk.h>
5933 main (int argc, char *argv[])
5936 GtkWidget *aspect_frame;
5937 GtkWidget *drawing_area;
5938 gtk_init (&argc, &argv);
5940 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5941 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
5942 gtk_signal_connect (GTK_OBJECT (window), "destroy",
5943 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
5944 gtk_container_border_width (GTK_CONTAINER (window), 10);
5946 /* Create an aspect_frame and add it to our toplevel window */
5948 aspect_frame = gtk_aspect_frame_new ("2x1", /* label */
5951 2, /* xsize/ysize = 2 */
5952 FALSE /* ignore child's aspect */);
5954 gtk_container_add (GTK_CONTAINER(window), aspect_frame);
5955 gtk_widget_show (aspect_frame);
5957 /* Now add a child widget to the aspect frame */
5959 drawing_area = gtk_drawing_area_new ();
5961 /* Ask for a 200x200 window, but the AspectFrame will give us a 200x100
5962 * window since we are forcing a 2x1 aspect ratio */
5963 gtk_widget_set_usize (drawing_area, 200, 200);
5964 gtk_container_add (GTK_CONTAINER(aspect_frame), drawing_area);
5965 gtk_widget_show (drawing_area);
5967 gtk_widget_show (window);
5974 <!-- ***************************************************************** -->
5976 <!-- ***************************************************************** -->
5978 <!-- ----------------------------------------------------------------- -->
5980 The GtkCList widget has replaced the GtkList widget (which is still
5983 The GtkCList widget is a multi-column list widget that is capable of
5984 handling literally thousands of rows of information. Each column can
5985 optionally have a title, which itself is optionally active, allowing
5986 us to bind a function to its selection.
5988 <!-- ----------------------------------------------------------------- -->
5989 <sect1>Creating a GtkCList widget
5991 Creating a GtkCList is quite straightforward, once you have learned
5992 about widgets in general. It provides the almost standard two ways,
5993 that is the hard way, and the easy way. But before we create it, there
5994 is one thing we should figure out beforehand: how many columns should
5997 Not all columns have to be visible and can be used to store data that
5998 is related to a certain cell in the list.
6001 GtkWidget *gtk_clist_new ( gint columns );
6003 GtkWidget *gtk_clist_new_with_titles( gint columns,
6007 The first form is very straight forward, the second might require some
6008 explanation. Each column can have a title associated with it, and this
6009 title can be a label or a button that reacts when we click on it. If
6010 we use the second form, we must provide pointers to the title texts,
6011 and the number of pointers should equal the number of columns
6012 specified. Of course we can always use the first form, and manually
6015 Note: the GtkCList widget does not have it's own scrollbars and should
6016 be placed within a GtkScrolledWindow widget if your require this
6017 functionality. This is a change from the GTK 1.0 implementation.
6019 <!-- ----------------------------------------------------------------- -->
6020 <sect1>Modes of operation
6022 There are several attributes that can be used to alter the behaviour of
6023 a GtkCList. First there is
6026 void gtk_clist_set_selection_mode( GtkCList *clist,
6027 GtkSelectionMode mode );
6030 which, as the name implies, sets the selection mode of the GtkCList. The first
6031 argument is the GtkCList widget, and the second specifies the cell selection
6032 mode (they are defined in gtkenums.h). At the time of this writing, the following
6033 modes are available to us:
6036 <item> GTK_SELECTION_SINGLE - The selection is either NULL or contains a GList
6037 pointer for a single selected item.
6039 <item> GTK_SELECTION_BROWSE - The selection is NULL if the list contains no
6040 widgets or insensitive ones only, otherwise it contains a GList pointer for
6041 one GList structure, and therefore exactly one list item.
6043 <item> GTK_SELECTION_MULTIPLE - The selection is NULL if no list items are
6044 selected or a GList pointer for the first selected item. That in turn points
6045 to a GList structure for the second selected item and so on. This is currently
6046 the <bf>default</bf> for the GtkCList widget.
6048 <item> GTK_SELECTION_EXTENDED - The selection is always NULL.
6051 Others might be added in later revisions of GTK.
6053 We can also define what the border of the GtkCList widget should look
6054 like. It is done through
6057 void gtk_clist_set_shadow_type( GtkCList *clist,
6058 GtkShadowType border );
6061 And the possible values for the second argument are
6064 <item> GTK_SHADOW_NONE
6066 <item> GTK_SHADOW_IN
6068 <item> GTK_SHADOW_OUT
6070 <item> GTK_SHADOW_ETCHED_IN
6072 <item> GTK_SHADOW_ETCHED_OUT
6075 <!-- ----------------------------------------------------------------- -->
6076 <sect1>Working with titles
6078 When you create a GtkCList widget, you will also get a set of title
6079 buttons automatically. They live in the top of the CList window, and
6080 can act either as normal buttons that respond to being pressed, or
6081 they can be passive, in which case they are nothing more than a
6082 title. There are four different calls that aid us in setting the
6083 status of the title buttons.
6086 void gtk_clist_column_title_active( GtkCList *clist,
6089 void gtk_clist_column_title_passive( GtkCList *clist,
6092 void gtk_clist_column_titles_active( GtkCList *clist );
6094 void gtk_clist_column_titles_passive( GtkCList *clist );
6097 An active title is one which acts as a normal button, a passive one is
6098 just a label. The first two calls above will activate/deactivate the
6099 title button above the specific column, while the last two calls
6100 activate/deactivate all title buttons in the supplied clist widget.
6102 But of course there are those cases when we don't want them at all,
6103 and so they can be hidden and shown at will using the following two
6107 void gtk_clist_column_titles_show( GtkCList *clist );
6109 void gtk_clist_column_titles_hide( GtkCList *clist );
6112 For titles to be really useful we need a mechanism to set and change
6113 them, and this is done using
6116 void gtk_clist_set_column_title( GtkCList *clist,
6121 Note that only the title of one column can be set at a time, so if all
6122 the titles are known from the beginning, then I really suggest using
6123 gtk_clist_new_with_titles (as described above) to set them. Saves you
6124 coding time, and makes your program smaller. There are some cases
6125 where getting the job done the manual way is better, and that's when
6126 not all titles will be text. GtkCList provides us with title buttons
6127 that can in fact incorporate whole widgets, for example a pixmap. It's
6131 void gtk_clist_set_column_widget( GtkCList *clist,
6133 GtkWidget *widget );
6136 which should require no special explanation.
6138 <!-- ----------------------------------------------------------------- -->
6139 <sect1>Manipulating the list itself
6141 It is possible to change the justification for a column, and it is
6145 void gtk_clist_set_column_justification( GtkCList *clist,
6147 GtkJustification justification );
6150 The GtkJustification type can take the following values:
6153 <item>GTK_JUSTIFY_LEFT - The text in the column will begin from the
6156 <item>GTK_JUSTIFY_RIGHT - The text in the column will begin from the
6159 <item>GTK_JUSTIFY_CENTER - The text is placed in the center of the
6162 <item>GTK_JUSTIFY_FILL - The text will use up all available space in
6163 the column. It is normally done by inserting extra blank spaces
6164 between words (or between individual letters if it's a single
6165 word). Much in the same way as any ordinary WYSIWYG text editor.
6168 The next function is a very important one, and should be standard in
6169 the setup of all GtkCList widgets. When the list is created, the width
6170 of the various columns are chosen to match their titles, and since
6171 this is seldom the right width we have to set it using
6174 void gtk_clist_set_column_width( GtkCList *clist,
6179 Note that the width is given in pixels and not letters. The same goes
6180 for the height of the cells in the columns, but as the default value
6181 is the height of the current font this isn't as critical to the
6182 application. Still, it is done through
6185 void gtk_clist_set_row_height( GtkCList *clist,
6189 Again, note that the height is given in pixels.
6191 We can also move the list around without user interaction, however, it
6192 does require that we know what we are looking for. Or in other words,
6193 we need the row and column of the item we want to scroll to.
6196 void gtk_clist_moveto( GtkCList *clist,
6203 The gfloat row_align is pretty important to understand. It's a value
6204 between 0.0 and 1.0, where 0.0 means that we should scroll the list so
6205 the row appears at the top, while if the value of row_align is 1.0,
6206 the row will appear at the bottom instead. All other values between
6207 0.0 and 1.0 are also valid and will place the row between the top and
6208 the bottom. The last argument, gfloat col_align works in the same way,
6209 though 0.0 marks left and 1.0 marks right instead.
6211 Depending on the application's needs, we don't have to scroll to an
6212 item that is already visible to us. So how do we know if it is
6213 visible? As usual, there is a function to find that out as well.
6216 GtkVisibility gtk_clist_row_is_visible( GtkCList *clist,
6220 The return value is is one of the following:
6223 <item>GTK_VISIBILITY_NONE
6225 <item>GTK_VISIBILITY_PARTIAL
6227 <item>GTK_VISIBILITY_FULL
6230 Note that it will only tell us if a row is visible. Currently there is
6231 no way to determine this for a column. We can get partial information
6232 though, because if the return is GTK_VISIBILITY_PARTIAL, then some of
6233 it is hidden, but we don't know if it is the row that is being cut by
6234 the lower edge of the listbox, or if the row has columns that are
6237 We can also change both the foreground and background colors of a
6238 particular row. This is useful for marking the row selected by the
6239 user, and the two functions that is used to do it are
6242 void gtk_clist_set_foreground( GtkCList *clist,
6246 void gtk_clist_set_background( GtkCList *clist,
6251 Please note that the colors must have been previously allocated.
6253 <!-- ----------------------------------------------------------------- -->
6254 <sect1>Adding rows to the list
6256 We can add rows in three ways. They can be prepended or appended to
6260 gint gtk_clist_prepend( GtkCList *clist,
6263 gint gtk_clist_append( GtkCList *clist,
6267 The return value of these two functions indicate the index of the row
6268 that was just added. We can insert a row at a given place using
6271 void gtk_clist_insert( GtkCList *clist,
6276 In these calls we have to provide a collection of pointers that are
6277 the texts we want to put in the columns. The number of pointers should
6278 equal the number of columns in the list. If the text[] argument is
6279 NULL, then there will be no text in the columns of the row. This is
6280 useful, for example, if we want to add pixmaps instead (something that
6281 has to be done manually).
6283 Also, please note that the numbering of both rows and columns start at 0.
6285 To remove an individual row we use
6288 void gtk_clist_remove( GtkCList *clist,
6292 There is also a call that removes all rows in the list. This is a lot
6293 faster than calling gtk_clist_remove once for each row, which is the
6297 void gtk_clist_clear( GtkCList *clist );
6300 There are also two convenience functions that should be used when a
6301 lot of changes have to be made to the list. This is to prevent the
6302 list flickering while being repeatedly updated, which may be highly
6303 annoying to the user. So instead it is a good idea to freeze the list,
6304 do the updates to it, and finally thaw it which causes the list to be
6305 updated on the screen.
6308 void gtk_clist_freeze( GtkCList * clist );
6310 void gtk_clist_thaw( GtkCList * clist );
6313 <!-- ----------------------------------------------------------------- -->
6314 <sect1>Setting text and pixmaps in the cells
6316 A cell can contain a pixmap, text or both. To set them the following
6320 void gtk_clist_set_text( GtkCList *clist,
6325 void gtk_clist_set_pixmap( GtkCList *clist,
6331 void gtk_clist_set_pixtext( GtkCList *clist,
6340 It's quite straightforward. All the calls have the GtkCList as the
6341 first argument, followed by the row and column of the cell, followed
6342 by the data to be set. The <tt/spacing/ argument in
6343 gtk_clist_set_pixtext is the number of pixels between the pixmap and
6344 the beginning of the text.
6346 To read back the data, we instead use
6349 gint gtk_clist_get_text( GtkCList *clist,
6354 gint gtk_clist_get_pixmap( GtkCList *clist,
6360 gint gtk_clist_get_pixtext( GtkCList *clist,
6369 It isn't necessary to read it all back in case you aren't
6370 interested. Any of the pointers that are meant for return values (all
6371 except the clist) can be NULL. So if we want to read back only the
6372 text from a cell that is of type pixtext, then we would do the
6373 following, assuming that clist, row and column already exist:
6378 gtk_clist_get_pixtext(clist, row, column, &mytext, NULL, NULL, NULL);
6381 There is one more call that is related to what's inside a cell in the
6385 GtkCellType gtk_clist_get_cell_type( GtkCList *clist,
6390 which returns the type of data in a cell. The return value is one of
6393 <item>GTK_CELL_EMPTY
6397 <item>GTK_CELL_PIXMAP
6399 <item>GTK_CELL_PIXTEXT
6401 <item>GTK_CELL_WIDGET
6404 There is also a function that will let us set the indentation, both
6405 vertical and horizontal, of a cell. The indentation value is of type
6406 gint, given in pixels, and can be both positive and negative.
6409 void gtk_clist_set_shift( GtkCList *clist,
6416 <!-- ----------------------------------------------------------------- -->
6417 <sect1>Storing data pointers
6419 With a GtkCList it is possible to set a data pointer for a row. This
6420 pointer will not be visible for the user, but is merely a convenience
6421 for the programmer to associate a row with a pointer to some
6424 The functions should be fairly self-explanatory by now
6427 void gtk_clist_set_row_data( GtkCList *clist,
6431 void gtk_clist_set_row_data_full( GtkCList *clist,
6434 GtkDestroyNotify destroy );
6436 gpointer gtk_clist_get_row_data( GtkCList *clist,
6439 gint gtk_clist_find_row_from_data( GtkCList *clist,
6443 <!-- ----------------------------------------------------------------- -->
6444 <sect1>Working with selections
6446 There are also functions available that let us force the (un)selection
6450 void gtk_clist_select_row( GtkCList *clist,
6454 void gtk_clist_unselect_row( GtkCList *clist,
6459 And also a function that will take x and y coordinates (for example,
6460 read from the mousepointer), and map that onto the list, returning the
6461 corresponding row and column.
6464 gint gtk_clist_get_selection_info( GtkCList *clist,
6471 When we detect something of interest, it might be movement of the
6472 pointer, a click somewhere in the list, we can read the pointer
6473 coordinates and find out where in the list the pointer is. Cumbersome?
6474 Luckily, there is a simpler way...
6476 <!-- ----------------------------------------------------------------- -->
6477 <sect1>The signals that bring it together
6479 As with all other widgets, there are a few signals that can be used. The
6480 GtkCList widget is derived from the GtkContainer widget, and so has all the
6481 same signals, but also the adds following:
6484 <item>select_row - This signal will send the following information, in
6485 order: GtkCList *clist, gint row, gint column, GtkEventButton *event
6487 <item>unselect_row - When the user unselects a row, this signal is
6488 activated. It sends the same information as select_row
6490 <item>click_column - Send GtkCList *clist, gint column
6493 So if we want to connect a callback to select_row, the callback
6494 function would be declared like this
6497 void select_row_callback(GtkWidget *widget,
6500 GdkEventButton *event,
6504 The callback is connected as usual with
6507 gtk_signal_connect(GTK_OBJECT( clist),
6509 GTK_SIGNAL_FUNC(select_row_callback),
6513 <!-- ----------------------------------------------------------------- -->
6514 <sect1>A GtkCList example
6518 /* example-start clist clist.c */
6520 #include <gtk/gtk.h>
6523 /* These are just the prototypes of the various callbacks */
6524 void button_add_clicked( GtkWidget *button, gpointer data);
6525 void button_clear_clicked( GtkWidget *button, gpointer data);
6526 void button_hide_show_clicked( GtkWidget *button, gpointer data);
6527 void selection_made( GtkWidget *clist, gint row, gint column,
6528 GdkEventButton *event, gpointer data);
6530 gint main (int argc, gchar *argv[])
6533 GtkWidget *vbox, *hbox;
6535 GtkWidget *button_add, *button_clear, *button_hide_show;
6536 gchar *titles[2] = {"Ingredients","Amount"};
6538 gtk_init(&argc, &argv);
6541 window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
6542 gtk_widget_set_usize(GTK_WIDGET(window), 300, 150);
6544 gtk_window_set_title(GTK_WINDOW(window), "GtkCList Example");
6545 gtk_signal_connect(GTK_OBJECT(window),
6547 GTK_SIGNAL_FUNC(gtk_main_quit),
6550 vbox=gtk_vbox_new(FALSE, 5);
6551 gtk_container_border_width(GTK_CONTAINER(vbox), 5);
6552 gtk_container_add(GTK_CONTAINER(window), vbox);
6553 gtk_widget_show(vbox);
6555 /* Create the GtkCList. For this example we use 2 columns */
6556 clist = gtk_clist_new_with_titles( 2, titles);
6558 /* When a selection is made, we want to know about it. The callback
6559 * used is selection_made, and its code can be found further down */
6560 gtk_signal_connect(GTK_OBJECT(clist), "select_row",
6561 GTK_SIGNAL_FUNC(selection_made),
6564 /* It isn't necessary to shadow the border, but it looks nice :) */
6565 gtk_clist_set_shadow_type (GTK_CLIST(clist), GTK_SHADOW_OUT);
6567 /* What however is important, is that we set the column widths as
6568 * they will never be right otherwise. Note that the columns are
6569 * numbered from 0 and up (to 1 in this case).
6571 gtk_clist_set_column_width (GTK_CLIST(clist), 0, 150);
6573 /* Add the GtkCList widget to the vertical box and show it. */
6574 gtk_box_pack_start(GTK_BOX(vbox), clist, TRUE, TRUE, 0);
6575 gtk_widget_show(clist);
6577 /* Create the buttons and add them to the window. See the button
6578 * tutorial for more examples and comments on this.
6580 hbox = gtk_hbox_new(FALSE, 0);
6581 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
6582 gtk_widget_show(hbox);
6584 button_add = gtk_button_new_with_label("Add List");
6585 button_clear = gtk_button_new_with_label("Clear List");
6586 button_hide_show = gtk_button_new_with_label("Hide/Show titles");
6588 gtk_box_pack_start(GTK_BOX(hbox), button_add, TRUE, TRUE, 0);
6589 gtk_box_pack_start(GTK_BOX(hbox), button_clear, TRUE, TRUE, 0);
6590 gtk_box_pack_start(GTK_BOX(hbox), button_hide_show, TRUE, TRUE, 0);
6592 /* Connect our callbacks to the three buttons */
6593 gtk_signal_connect_object(GTK_OBJECT(button_add), "clicked",
6594 GTK_SIGNAL_FUNC(button_add_clicked),
6596 gtk_signal_connect_object(GTK_OBJECT(button_clear), "clicked",
6597 GTK_SIGNAL_FUNC(button_clear_clicked),
6599 gtk_signal_connect_object(GTK_OBJECT(button_hide_show), "clicked",
6600 GTK_SIGNAL_FUNC(button_hide_show_clicked),
6603 gtk_widget_show(button_add);
6604 gtk_widget_show(button_clear);
6605 gtk_widget_show(button_hide_show);
6607 /* The interface is completely set up so we show the window and
6608 * enter the gtk_main loop.
6610 gtk_widget_show(window);
6616 /* User clicked the "Add List" button. */
6617 void button_add_clicked( GtkWidget *button, gpointer data)
6621 /* Something silly to add to the list. 4 rows of 2 columns each */
6622 gchar *drink[4][2] = {{"Milk", "3 Oz"},
6627 /* Here we do the actual adding of the text. It's done once for
6630 for( indx=0; indx < 4; indx++)
6631 gtk_clist_append( (GtkCList*) data, drink[indx]);
6636 /* User clicked the "Clear List" button. */
6637 void button_clear_clicked( GtkWidget *button, gpointer data)
6639 /* Clear the list using gtk_clist_clear. This is much faster than
6640 * calling gtk_clist_remove once for each row.
6642 gtk_clist_clear((GtkCList*) data);
6647 /* The user clicked the "Hide/Show titles" button. */
6648 void button_hide_show_clicked( GtkWidget *button, gpointer data)
6650 /* Just a flag to remember the status. 0 = currently visible */
6651 static short int flag = 0;
6655 /* Hide the titles and set the flag to 1 */
6656 gtk_clist_column_titles_hide((GtkCList*) data);
6661 /* Show the titles and reset flag to 0 */
6662 gtk_clist_column_titles_show((GtkCList*) data);
6669 /* If we come here, then the user has selected a row in the list. */
6670 void selection_made( GtkWidget *clist, gint row, gint column,
6671 GdkEventButton *event, gpointer data)
6675 /* Get the text that is stored in the selected row and column
6676 * which was clicked in. We will receive it as a pointer in the
6679 gtk_clist_get_text(GTK_CLIST(clist), row, column, &text);
6681 /* Just prints some information about the selected row */
6682 g_print("You selected row %d. More specifically you clicked in column %d, and the text in this cell is %s\n\n", row, column, text);
6689 <!-- ***************************************************************** -->
6691 <!-- ***************************************************************** -->
6693 NOTE: The GtkList widget has been superseded by the GtkCList widget.
6695 The GtkList widget is designed to act as a vertical container for
6696 widgets that should be of the type GtkListItem.
6698 A GtkList widget has its own window to receive events and its own
6699 background color which is usually white. As it is directly derived
6700 from a GtkContainer it can be treated as such by using the
6701 GTK_CONTAINER(List) macro, see the GtkContainer widget for more on
6702 this. One should already be familiar with the usage of a GList and
6703 its related functions g_list_*() to be able to use the GtkList widget
6706 There is one field inside the structure definition of the GtkList
6707 widget that will be of greater interest to us, this is:
6714 guint selection_mode;
6719 The selection field of a GtkList points to a linked list of all items
6720 that are currently selected, or NULL if the selection is empty. So to
6721 learn about the current selection we read the GTK_LIST()->selection
6722 field, but do not modify it since the internal fields are maintained
6723 by the gtk_list_*() functions.
6725 The selection_mode of the GtkList determines the selection facilities
6726 of a GtkList and therefore the contents of the GTK_LIST()->selection
6727 field. The selection_mode may be one of the following:
6730 <item> GTK_SELECTION_SINGLE - The selection is either NULL
6731 or contains a GList pointer
6732 for a single selected item.
6734 <item> GTK_SELECTION_BROWSE - The selection is NULL if the list
6735 contains no widgets or insensitive
6736 ones only, otherwise it contains
6737 a GList pointer for one GList
6738 structure, and therefore exactly
6741 <item> GTK_SELECTION_MULTIPLE - The selection is NULL if no list
6742 items are selected or a GList pointer
6743 for the first selected item. That
6744 in turn points to a GList structure
6745 for the second selected item and so
6748 <item> GTK_SELECTION_EXTENDED - The selection is always NULL.
6751 The default is GTK_SELECTION_MULTIPLE.
6753 <!-- ----------------------------------------------------------------- -->
6757 void selection_changed( GtkList *list );
6760 This signal will be invoked whenever the selection field of a GtkList
6761 has changed. This happens when a child of the GtkList got selected or
6765 void select_child( GtkList *list,
6769 This signal is invoked when a child of the GtkList is about to get
6770 selected. This happens mainly on calls to gtk_list_select_item(),
6771 gtk_list_select_child(), button presses and sometimes indirectly
6772 triggered on some else occasions where children get added to or
6773 removed from the GtkList.
6776 void unselect_child( GtkList *list,
6780 This signal is invoked when a child of the GtkList is about to get
6781 deselected. This happens mainly on calls to gtk_list_unselect_item(),
6782 gtk_list_unselect_child(), button presses and sometimes indirectly
6783 triggered on some else occasions where children get added to or
6784 removed from the GtkList.
6786 <!-- ----------------------------------------------------------------- -->
6790 guint gtk_list_get_type( void );
6793 Returns the `GtkList' type identifier.
6796 GtkWidget *gtk_list_new( void );
6799 Create a new GtkList object. The new widget is returned as a pointer
6800 to a GtkWidget object. NULL is returned on failure.
6803 void gtk_list_insert_items( GtkList *list,
6808 Insert list items into the list, starting at <tt/position/.
6809 <tt/items/ is a doubly linked list where each nodes data pointer is
6810 expected to point to a newly created GtkListItem. The GList nodes of
6811 <tt/items/ are taken over by the list.
6814 void gtk_list_append_items( GtkList *list,
6818 Insert list items just like gtk_list_insert_items() at the end of the
6819 list. The GList nodes of <tt/items/ are taken over by the list.
6822 void gtk_list_prepend_items( GtkList *list,
6826 Insert list items just like gtk_list_insert_items() at the very
6827 beginning of the list. The GList nodes of <tt/items/ are taken over by
6831 void gtk_list_remove_items( GtkList *list,
6835 Remove list items from the list. <tt/items/ is a doubly linked list
6836 where each nodes data pointer is expected to point to a direct child
6837 of list. It is the callers responsibility to make a call to
6838 g_list_free(items) afterwards. Also the caller has to destroy the list
6842 void gtk_list_clear_items( GtkList *list,
6847 Remove and destroy list items from the list. A widget is affected if
6848 its current position within the list is in the range specified by
6849 <tt/start/ and <tt/end/.
6852 void gtk_list_select_item( GtkList *list,
6856 Invoke the select_child signal for a list item specified through its
6857 current position within the list.
6860 void gtk_list_unselect_item( GtkList *list,
6864 Invoke the unselect_child signal for a list item specified through its
6865 current position within the list.
6868 void gtk_list_select_child( GtkList *list,
6872 Invoke the select_child signal for the specified child.
6875 void gtk_list_unselect_child( GtkList *list,
6879 Invoke the unselect_child signal for the specified child.
6882 gint gtk_list_child_position( GtkList *list,
6886 Return the position of <tt/child/ within the list. "-1" is returned on
6890 void gtk_list_set_selection_mode( GtkList *list,
6891 GtkSelectionMode mode );
6894 Set the selection mode MODE which can be of GTK_SELECTION_SINGLE,
6895 GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE or
6896 GTK_SELECTION_EXTENDED.
6899 GtkList *GTK_LIST( gpointer obj );
6902 Cast a generic pointer to `GtkList *'. *Note Standard Macros::, for
6906 GtkListClass *GTK_LIST_CLASS( gpointer class);
6909 Cast a generic pointer to `GtkListClass*'. *Note Standard Macros::,
6913 gint GTK_IS_LIST( gpointer obj);
6916 Determine if a generic pointer refers to a `GtkList' object. *Note
6917 Standard Macros::, for more info.
6919 <!-- ----------------------------------------------------------------- -->
6922 Following is an example program that will print out the changes of the
6923 selection of a GtkList, and lets you "arrest" list items into a prison
6924 by selecting them with the rightmost mouse button.
6927 /* example-start list list.c */
6929 /* Include the gtk+ header files
6930 * Include stdio.h, we need that for the printf() function
6932 #include <gtk/gtk.h>
6935 /* This is our data identification string to store
6936 * data in list items
6938 const gchar *list_item_data_key="list_item_data";
6941 /* prototypes for signal handler that we are going to connect
6942 * to the GtkList widget
6944 static void sigh_print_selection( GtkWidget *gtklist,
6945 gpointer func_data);
6947 static void sigh_button_event( GtkWidget *gtklist,
6948 GdkEventButton *event,
6952 /* Main function to set up the user interface */
6954 gint main (int argc,
6957 GtkWidget *separator;
6960 GtkWidget *scrolled_window;
6964 GtkWidget *list_item;
6970 /* Initialize gtk+ (and subsequently gdk) */
6972 gtk_init(&argc, &argv);
6975 /* Create a window to put all the widgets in
6976 * connect gtk_main_quit() to the "destroy" event of
6977 * the window to handle window manager close-window-events
6979 window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
6980 gtk_window_set_title(GTK_WINDOW(window), "GtkList Example");
6981 gtk_signal_connect(GTK_OBJECT(window),
6983 GTK_SIGNAL_FUNC(gtk_main_quit),
6987 /* Inside the window we need a box to arrange the widgets
6989 vbox=gtk_vbox_new(FALSE, 5);
6990 gtk_container_border_width(GTK_CONTAINER(vbox), 5);
6991 gtk_container_add(GTK_CONTAINER(window), vbox);
6992 gtk_widget_show(vbox);
6994 /* This is the scrolled window to put the GtkList widget inside */
6995 scrolled_window=gtk_scrolled_window_new(NULL, NULL);
6996 gtk_widget_set_usize(scrolled_window, 250, 150);
6997 gtk_container_add(GTK_CONTAINER(vbox), scrolled_window);
6998 gtk_widget_show(scrolled_window);
7000 /* Create the GtkList widget.
7001 * Connect the sigh_print_selection() signal handler
7002 * function to the "selection_changed" signal of the GtkList
7003 * to print out the selected items each time the selection
7005 gtklist=gtk_list_new();
7006 gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(scrolled_window),
7008 gtk_widget_show(gtklist);
7009 gtk_signal_connect(GTK_OBJECT(gtklist),
7010 "selection_changed",
7011 GTK_SIGNAL_FUNC(sigh_print_selection),
7014 /* We create a "Prison" to put a list item in ;) */
7015 frame=gtk_frame_new("Prison");
7016 gtk_widget_set_usize(frame, 200, 50);
7017 gtk_container_border_width(GTK_CONTAINER(frame), 5);
7018 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
7019 gtk_container_add(GTK_CONTAINER(vbox), frame);
7020 gtk_widget_show(frame);
7022 /* Connect the sigh_button_event() signal handler to the GtkList
7023 * which will handle the "arresting" of list items
7025 gtk_signal_connect(GTK_OBJECT(gtklist),
7026 "button_release_event",
7027 GTK_SIGNAL_FUNC(sigh_button_event),
7030 /* Create a separator */
7031 separator=gtk_hseparator_new();
7032 gtk_container_add(GTK_CONTAINER(vbox), separator);
7033 gtk_widget_show(separator);
7035 /* Finally create a button and connect it's "clicked" signal
7036 * to the destruction of the window */
7037 button=gtk_button_new_with_label("Close");
7038 gtk_container_add(GTK_CONTAINER(vbox), button);
7039 gtk_widget_show(button);
7040 gtk_signal_connect_object(GTK_OBJECT(button),
7042 GTK_SIGNAL_FUNC(gtk_widget_destroy),
7043 GTK_OBJECT(window));
7046 /* Now we create 5 list items, each having it's own
7047 * label and add them to the GtkList using gtk_container_add()
7048 * Also we query the text string from the label and
7049 * associate it with the list_item_data_key for each list item
7051 for (i=0; i<5; i++) {
7055 sprintf(buffer, "ListItemContainer with Label #%d", i);
7056 label=gtk_label_new(buffer);
7057 list_item=gtk_list_item_new();
7058 gtk_container_add(GTK_CONTAINER(list_item), label);
7059 gtk_widget_show(label);
7060 gtk_container_add(GTK_CONTAINER(gtklist), list_item);
7061 gtk_widget_show(list_item);
7062 gtk_label_get(GTK_LABEL(label), &string);
7063 gtk_object_set_data(GTK_OBJECT(list_item),
7067 /* Here, we are creating another 5 labels, this time
7068 * we use gtk_list_item_new_with_label() for the creation
7069 * we can't query the text string from the label because
7070 * we don't have the labels pointer and therefore
7071 * we just associate the list_item_data_key of each
7072 * list item with the same text string.
7073 * For adding of the list items we put them all into a doubly
7074 * linked list (GList), and then add them by a single call to
7075 * gtk_list_append_items().
7076 * Because we use g_list_prepend() to put the items into the
7077 * doubly linked list, their order will be descending (instead
7078 * of ascending when using g_list_append())
7082 sprintf(buffer, "List Item with Label %d", i);
7083 list_item=gtk_list_item_new_with_label(buffer);
7084 dlist=g_list_prepend(dlist, list_item);
7085 gtk_widget_show(list_item);
7086 gtk_object_set_data(GTK_OBJECT(list_item),
7088 "ListItem with integrated Label");
7090 gtk_list_append_items(GTK_LIST(gtklist), dlist);
7092 /* Finally we want to see the window, don't we? ;) */
7093 gtk_widget_show(window);
7095 /* Fire up the main event loop of gtk */
7098 /* We get here after gtk_main_quit() has been called which
7099 * happens if the main window gets destroyed
7104 /* This is the signal handler that got connected to button
7105 * press/release events of the GtkList
7107 void sigh_button_event( GtkWidget *gtklist,
7108 GdkEventButton *event,
7111 /* We only do something if the third (rightmost mouse button
7114 if (event->type==GDK_BUTTON_RELEASE &&
7116 GList *dlist, *free_list;
7117 GtkWidget *new_prisoner;
7119 /* Fetch the currently selected list item which
7120 * will be our next prisoner ;)
7122 dlist=GTK_LIST(gtklist)->selection;
7124 new_prisoner=GTK_WIDGET(dlist->data);
7128 /* Look for already imprisoned list items, we
7129 * will put them back into the list.
7130 * Remember to free the doubly linked list that
7131 * gtk_container_children() returns
7133 dlist=gtk_container_children(GTK_CONTAINER(frame));
7136 GtkWidget *list_item;
7138 list_item=dlist->data;
7140 gtk_widget_reparent(list_item, gtklist);
7144 g_list_free(free_list);
7146 /* If we have a new prisoner, remove him from the
7147 * GtkList and put him into the frame "Prison".
7148 * We need to unselect the item first.
7153 static_dlist.data=new_prisoner;
7154 static_dlist.next=NULL;
7155 static_dlist.prev=NULL;
7157 gtk_list_unselect_child(GTK_LIST(gtklist),
7159 gtk_widget_reparent(new_prisoner, frame);
7164 /* This is the signal handler that gets called if GtkList
7165 * emits the "selection_changed" signal
7167 void sigh_print_selection( GtkWidget *gtklist,
7172 /* Fetch the doubly linked list of selected items
7173 * of the GtkList, remember to treat this as read-only!
7175 dlist=GTK_LIST(gtklist)->selection;
7177 /* If there are no selected items there is nothing more
7178 * to do than just telling the user so
7181 g_print("Selection cleared\n");
7184 /* Ok, we got a selection and so we print it
7186 g_print("The selection is a ");
7188 /* Get the list item from the doubly linked list
7189 * and then query the data associated with list_item_data_key.
7190 * We then just print it */
7192 GtkObject *list_item;
7193 gchar *item_data_string;
7195 list_item=GTK_OBJECT(dlist->data);
7196 item_data_string=gtk_object_get_data(list_item,
7197 list_item_data_key);
7198 g_print("%s ", item_data_string);
7207 <!-- ----------------------------------------------------------------- -->
7208 <sect1> List Item Widget
7210 The GtkListItem widget is designed to act as a container holding up to
7211 one child, providing functions for selection/deselection just like the
7212 GtkList widget requires them for its children.
7214 A GtkListItem has its own window to receive events and has its own
7215 background color which is usually white.
7217 As it is directly derived from a GtkItem it can be treated as such by
7218 using the GTK_ITEM(ListItem) macro, see the GtkItem widget for more on
7219 this. Usually a GtkListItem just holds a label to identify e.g. a
7220 filename within a GtkList -- therefore the convenience function
7221 gtk_list_item_new_with_label() is provided. The same effect can be
7222 achieved by creating a GtkLabel on its own, setting its alignment to
7223 xalign=0 and yalign=0.5 with a subsequent container addition to the
7226 As one is not forced to add a GtkLabel to a GtkListItem, you could
7227 also add a GtkVBox or a GtkArrow etc. to the GtkListItem.
7229 <!-- ----------------------------------------------------------------- -->
7232 A GtkListItem does not create new signals on its own, but inherits
7233 the signals of a GtkItem. *Note GtkItem::, for more info.
7235 <!-- ----------------------------------------------------------------- -->
7239 guint gtk_list_item_get_type( void );
7242 Returns the `GtkListItem' type identifier.
7245 GtkWidget *gtk_list_item_new( void );
7248 Create a new GtkListItem object. The new widget is returned as a
7249 pointer to a GtkWidget object. NULL is returned on failure.
7252 GtkWidget *gtk_list_item_new_with_label( gchar *label );
7255 Create a new GtkListItem object, having a single GtkLabel as the sole
7256 child. The new widget is returned as a pointer to a GtkWidget
7257 object. NULL is returned on failure.
7260 void gtk_list_item_select( GtkListItem *list_item );
7263 This function is basically a wrapper around a call to gtk_item_select
7264 (GTK_ITEM (list_item)) which will emit the select signal. *Note
7265 GtkItem::, for more info.
7268 void gtk_list_item_deselect( GtkListItem *list_item );
7271 This function is basically a wrapper around a call to
7272 gtk_item_deselect (GTK_ITEM (list_item)) which will emit the deselect
7273 signal. *Note GtkItem::, for more info.
7276 GtkListItem *GTK_LIST_ITEM( gpointer obj );
7279 Cast a generic pointer to `GtkListItem*'. *Note Standard Macros::, for
7283 GtkListItemClass *GTK_LIST_ITEM_CLASS( gpointer class );
7286 Cast a generic pointer to GtkListItemClass*. *Note Standard Macros::,
7290 gint GTK_IS_LIST_ITEM( gpointer obj );
7293 Determine if a generic pointer refers to a `GtkListItem' object.
7294 *Note Standard Macros::, for more info.
7296 <!-- ----------------------------------------------------------------- -->
7299 Please see the GtkList example on this, which covers the usage of a
7300 GtkListItem as well.
7302 <!-- ***************************************************************** -->
7303 <sect> Tree Widget<label id="sec_Tree_Widgets">
7304 <!-- ***************************************************************** -->
7306 The purpose of tree widgets is to display hierarchically-organized
7307 data. The GtkTree widget itself is a vertical container for widgets of
7308 type GtkTreeItem. GtkTree itself is not terribly different from
7309 GtkList - both are derived directly from GtkContainer, and the
7310 GtkContainer methods work in the same way on GtkTree widgets as on
7311 GtkList widgets. The difference is that GtkTree widgets can be nested
7312 within other GtkTree widgets. We'll see how to do this shortly.
7314 The GtkTree widget has its own window, and defaults to a white
7315 background, as does GtkList. Also, most of the GtkTree methods work in
7316 the same way as the corresponding GtkList ones. However, GtkTree is
7317 not derived from GtkList, so you cannot use them interchangeably.
7319 <sect1> Creating a Tree
7321 A GtkTree is created in the usual way, using:
7324 GtkWidget* gtk_tree_new( void );
7327 Like the GtkList widget, a GtkTree will simply keep growing as more
7328 items are added to it, as well as when subtrees are expanded. For
7329 this reason, they are almost always packed into a
7330 GtkScrolledWindow. You might want to use gtk_widget_set_usize() on the
7331 scrolled window to ensure that it is big enough to see the tree's
7332 items, as the default size for GtkScrolledWindow is quite small.
7334 Now that you have a tree, you'll probably want to add some items to
7335 it. <ref id="sec_Tree_Item_Widget" name="The Tree Item Widget"> below
7336 explains the gory details of GtkTreeItem. For now, it'll suffice to
7340 GtkWidget* gtk_tree_item_new_with_label( gchar *label );
7343 You can then add it to the tree using one of the following (see
7344 <ref id="sec_GtkTree_Functions" name="Functions and Macros">
7345 below for more options):
7348 void gtk_tree_append( GtkTree *tree,
7349 GtkWidget *tree_item );
7351 void gtk_tree_prepend( GtkTree *tree,
7352 GtkWidget *tree_item );
7355 Note that you must add items to a GtkTree one at a time - there is no
7356 equivalent to gtk_list_*_items().
7358 <!-- ----------------------------------------------------------------- -->
7359 <sect1> Adding a Subtree
7361 A subtree is created like any other GtkTree widget. A subtree is added
7362 to another tree beneath a tree item, using:
7365 void gtk_tree_item_set_subtree( GtkTreeItem *tree_item,
7366 GtkWidget *subtree );
7369 You do not need to call gtk_widget_show() on a subtree before or after
7370 adding it to a GtkTreeItem. However, you <em>must</em> have added the
7371 GtkTreeItem in question to a parent tree before calling
7372 gtk_tree_item_set_subtree(). This is because, technically, the parent
7373 of the subtree is <em>not</em> the GtkTreeItem which "owns" it, but
7374 rather the GtkTree which holds that GtkTreeItem.
7376 When you add a subtree to a GtkTreeItem, a plus or minus sign appears
7377 beside it, which the user can click on to "expand" or "collapse" it,
7378 meaning, to show or hide its subtree. GtkTreeItems are collapsed by
7379 default. Note that when you collapse a GtkTreeItem, any selected
7380 items in its subtree remain selected, which may not be what the user
7383 <!-- ----------------------------------------------------------------- -->
7384 <sect1> Handling the Selection List
7386 As with GtkList, the GtkTree type has a <tt>selection</tt> field, and
7387 it is possible to control the behaviour of the tree (somewhat) by
7388 setting the selection type using:
7391 void gtk_tree_set_selection_mode( GtkTree *tree,
7392 GtkSelectionMode mode );
7395 The semantics associated with the various selection modes are
7396 described in the section on the GtkList widget. As with the GtkList
7397 widget, the "select_child", "unselect_child" (not really - see <ref
7398 id="sec_GtkTree_Signals" name="Signals"> below for an explanation),
7399 and "selection_changed" signals are emitted when list items are
7400 selected or unselected. However, in order to take advantage of these
7401 signals, you need to know <em>which</em> GtkTree widget they will be
7402 emitted by, and where to find the list of selected items.
7404 This is a source of potential confusion. The best way to explain this
7405 is that though all GtkTree widgets are created equal, some are more
7406 equal than others. All GtkTree widgets have their own X window, and
7407 can therefore receive events such as mouse clicks (if their
7408 GtkTreeItems or their children don't catch them first!). However, to
7409 make GTK_SELECTION_SINGLE and GTK_SELECTION_BROWSE selection types
7410 behave in a sane manner, the list of selected items is specific to the
7411 topmost GtkTree widget in a hierarchy, known as the "root tree".
7413 Thus, accessing the <tt>selection</tt>field directly in an arbitrary
7414 GtkTree widget is not a good idea unless you <em>know</em> it's the
7415 root tree. Instead, use the GTK_TREE_SELECTION (Tree) macro, which
7416 gives the root tree's selection list as a GList pointer. Of course,
7417 this list can include items that are not in the subtree in question if
7418 the selection type is GTK_SELECTION_MULTIPLE.
7420 Finally, the "select_child" (and "unselect_child", in theory) signals
7421 are emitted by all trees, but the "selection_changed" signal is only
7422 emitted by the root tree. Consequently, if you want to handle the
7423 "select_child" signal for a tree and all its subtrees, you will have
7424 to call gtk_signal_connect() for every subtree.
7426 <sect1> Tree Widget Internals
7428 The GtkTree's struct definition looks like this:
7433 GtkContainer container;
7437 GtkTree* root_tree; /* owner of selection list */
7438 GtkWidget* tree_owner;
7442 guint current_indent;
7443 guint selection_mode : 2;
7444 guint view_mode : 1;
7445 guint view_line : 1;
7449 The perils associated with accessing the <tt>selection</tt> field
7450 directly have already been mentioned. The other important fields of
7451 the struct can also be accessed with handy macros or class functions.
7452 GTK_TREE_IS_ROOT_TREE (Tree) returns a boolean value which indicates
7453 whether a tree is the root tree in a GtkTree hierarchy, while
7454 GTK_TREE_ROOT_TREE (Tree) returns the root tree, an object of type
7455 GtkTree (so, remember to cast it using GTK_WIDGET (Tree) if you want
7456 to use one of the gtk_widget_*() functions on it).
7458 Instead of directly accessing the children field of a GtkTree widget,
7459 it's probably best to cast it using GTK_CONTAINER (Tree), and pass it
7460 to the gtk_container_children() function. This creates a duplicate of
7461 the original list, so it's advisable to free it up using g_list_free()
7462 after you're done with it, or to iterate on it destructively, like
7466 children = gtk_container_children (GTK_CONTAINER (tree));
7468 do_something_nice (GTK_TREE_ITEM (children->data));
7469 children = g_list_remove_link (children, children);
7473 The <tt>tree_owner</tt> field is defined only in subtrees, where it
7474 points to the GtkTreeItem widget which holds the tree in question.
7475 The <tt>level</tt> field indicates how deeply nested a particular tree
7476 is; root trees have level 0, and each successive level of subtrees has
7477 a level one greater than the parent level. This field is set only
7478 after a GtkTree widget is actually mapped (i.e. drawn on the screen).
7480 <sect2> Signals<label id="sec_GtkTree_Signals">
7483 void selection_changed( GtkTree *tree );
7486 This signal will be emitted whenever the <tt>selection</tt> field of a
7487 GtkTree has changed. This happens when a child of the GtkTree is
7488 selected or deselected.
7491 void select_child( GtkTree *tree,
7495 This signal is emitted when a child of the GtkTree is about to get
7496 selected. This happens on calls to gtk_tree_select_item(),
7497 gtk_tree_select_child(), on <em>all</em> button presses and calls to
7498 gtk_tree_item_toggle() and gtk_item_toggle(). It may sometimes be
7499 indirectly triggered on other occasions where children get added to or
7500 removed from the GtkTree.
7503 void unselect_child (GtkTree *tree,
7507 This signal is emitted when a child of the GtkTree is about to get
7508 deselected. As of GTK+ 1.0.4, this seems to only occur on calls to
7509 gtk_tree_unselect_item() or gtk_tree_unselect_child(), and perhaps on
7510 other occasions, but <em>not</em> when a button press deselects a
7511 child, nor on emission of the "toggle" signal by gtk_item_toggle().
7513 <sect2> Functions and Macros<label id="sec_GtkTree_Functions">
7516 guint gtk_tree_get_type( void );
7519 Returns the `GtkTree' type identifier.
7522 GtkWidget* gtk_tree_new( void );
7525 Create a new GtkTree object. The new widget is returned as a pointer
7526 to a GtkWidget object. NULL is returned on failure.
7529 void gtk_tree_append( GtkTree *tree,
7530 GtkWidget *tree_item );
7533 Append a tree item to a GtkTree.
7536 void gtk_tree_prepend( GtkTree *tree,
7537 GtkWidget *tree_item );
7540 Prepend a tree item to a GtkTree.
7543 void gtk_tree_insert( GtkTree *tree,
7544 GtkWidget *tree_item,
7548 Insert a tree item into a GtkTree at the position in the list
7549 specified by <tt>position.</tt>
7552 void gtk_tree_remove_items( GtkTree *tree,
7556 Remove a list of items (in the form of a GList *) from a GtkTree.
7557 Note that removing an item from a tree dereferences (and thus usually)
7558 destroys it <em>and</em> its subtree, if it has one, <em>and</em> all
7559 subtrees in that subtree. If you want to remove only one item, you
7560 can use gtk_container_remove().
7563 void gtk_tree_clear_items( GtkTree *tree,
7568 Remove the items from position <tt>start</tt> to position <tt>end</tt>
7569 from a GtkTree. The same warning about dereferencing applies here, as
7570 gtk_tree_clear_items() simply constructs a list and passes it to
7571 gtk_tree_remove_items().
7574 void gtk_tree_select_item( GtkTree *tree,
7578 Emits the "select_item" signal for the child at position
7579 <tt>item</tt>, thus selecting the child (unless you unselect it in a
7583 void gtk_tree_unselect_item( GtkTree *tree,
7587 Emits the "unselect_item" signal for the child at position
7588 <tt>item</tt>, thus unselecting the child.
7591 void gtk_tree_select_child( GtkTree *tree,
7592 GtkWidget *tree_item );
7595 Emits the "select_item" signal for the child <tt>tree_item</tt>, thus
7599 void gtk_tree_unselect_child( GtkTree *tree,
7600 GtkWidget *tree_item );
7603 Emits the "unselect_item" signal for the child <tt>tree_item</tt>,
7604 thus unselecting it.
7607 gint gtk_tree_child_position( GtkTree *tree,
7611 Returns the position in the tree of <tt>child</tt>, unless
7612 <tt>child</tt> is not in the tree, in which case it returns -1.
7615 void gtk_tree_set_selection_mode( GtkTree *tree,
7616 GtkSelectionMode mode );
7619 Sets the selection mode, which can be one of GTK_SELECTION_SINGLE (the
7620 default), GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE, or
7621 GTK_SELECTION_EXTENDED. This is only defined for root trees, which
7622 makes sense, since the root tree "owns" the selection. Setting it for
7623 subtrees has no effect at all; the value is simply ignored.
7626 void gtk_tree_set_view_mode( GtkTree *tree,
7627 GtkTreeViewMode mode );
7630 Sets the "view mode", which can be either GTK_TREE_VIEW_LINE (the
7631 default) or GTK_TREE_VIEW_ITEM. The view mode propagates from a tree
7632 to its subtrees, and can't be set exclusively to a subtree (this is
7633 not exactly true - see the example code comments).
7635 The term "view mode" is rather ambiguous - basically, it controls the
7636 way the highlight is drawn when one of a tree's children is selected.
7637 If it's GTK_TREE_VIEW_LINE, the entire GtkTreeItem widget is
7638 highlighted, while for GTK_TREE_VIEW_ITEM, only the child widget
7639 (i.e. usually the label) is highlighted.
7642 void gtk_tree_set_view_lines( GtkTree *tree,
7646 Controls whether connecting lines between tree items are drawn.
7647 <tt>flag</tt> is either TRUE, in which case they are, or FALSE, in
7648 which case they aren't.
7651 GtkTree *GTK_TREE (gpointer obj);
7654 Cast a generic pointer to `GtkTree *'.
7657 GtkTreeClass *GTK_TREE_CLASS (gpointer class);
7660 Cast a generic pointer to `GtkTreeClass*'.
7663 gint GTK_IS_TREE (gpointer obj);
7666 Determine if a generic pointer refers to a `GtkTree' object.
7669 gint GTK_IS_ROOT_TREE (gpointer obj)
7672 Determine if a generic pointer refers to a `GtkTree' object
7673 <em>and</em> is a root tree. Though this will accept any pointer, the
7674 results of passing it a pointer that does not refer to a GtkTree are
7675 undefined and possibly harmful.
7678 GtkTree *GTK_TREE_ROOT_TREE (gpointer obj)
7681 Return the root tree of a pointer to a `GtkTree' object. The above
7685 GList *GTK_TREE_SELECTION( gpointer obj)
7688 Return the selection list of the root tree of a `GtkTree' object. The
7689 above warning applies here, too.
7691 <sect1> Tree Item Widget<label id="sec_Tree_Item_Widget">
7693 The GtkTreeItem widget, like GtkListItem, is derived from GtkItem,
7694 which in turn is derived from GtkBin. Therefore, the item itself is a
7695 generic container holding exactly one child widget, which can be of
7696 any type. The GtkTreeItem widget has a number of extra fields, but
7697 the only one we need be concerned with is the <tt>subtree</tt> field.
7699 The definition for the GtkTreeItem struct looks like this:
7707 GtkWidget *pixmaps_box;
7708 GtkWidget *plus_pix_widget, *minus_pix_widget;
7710 GList *pixmaps; /* pixmap node for this items color depth */
7716 The <tt>pixmaps_box</tt> field is a GtkEventBox which catches clicks
7717 on the plus/minus symbol which controls expansion and collapsing. The
7718 <tt>pixmaps</tt> field points to an internal data structure. Since
7719 you can always obtain the subtree of a GtkTreeItem in a (relatively)
7720 type-safe manner with the GTK_TREE_ITEM_SUBTREE (Item) macro, it's
7721 probably advisable never to touch the insides of a GtkTreeItem unless
7722 you <em>really</em> know what you're doing.
7724 Since it is directly derived from a GtkItem it can be treated as such
7725 by using the GTK_ITEM (TreeItem) macro. A GtkTreeItem usually holds a
7726 label, so the convenience function gtk_list_item_new_with_label() is
7727 provided. The same effect can be achieved using code like the
7728 following, which is actually copied verbatim from
7729 gtk_tree_item_new_with_label():
7732 tree_item = gtk_tree_item_new ();
7733 label_widget = gtk_label_new (label);
7734 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
7736 gtk_container_add (GTK_CONTAINER (tree_item), label_widget);
7737 gtk_widget_show (label_widget);
7740 As one is not forced to add a GtkLabel to a GtkTreeItem, you could
7741 also add a GtkHBox or a GtkArrow, or even a GtkNotebook (though your
7742 app will likely be quite unpopular in this case) to the GtkTreeItem.
7744 If you remove all the items from a subtree, it will be destroyed and
7745 unparented, unless you reference it beforehand, and the GtkTreeItem
7746 which owns it will be collapsed. So, if you want it to stick around,
7747 do something like the following:
7750 gtk_widget_ref (tree);
7751 owner = GTK_TREE(tree)->tree_owner;
7752 gtk_container_remove (GTK_CONTAINER(tree), item);
7753 if (tree->parent == NULL){
7754 gtk_tree_item_expand (GTK_TREE_ITEM(owner));
7755 gtk_tree_item_set_subtree (GTK_TREE_ITEM(owner), tree);
7758 gtk_widget_unref (tree);
7761 Finally, drag-n-drop <em>does</em> work with GtkTreeItems. You just
7762 have to make sure that the GtkTreeItem you want to make into a drag
7763 item or a drop site has not only been added to a GtkTree, but that
7764 each successive parent widget has a parent itself, all the way back to
7765 a toplevel or dialog window, when you call gtk_widget_dnd_drag_set()
7766 or gtk_widget_dnd_drop_set(). Otherwise, strange things will happen.
7770 GtkTreeItem inherits the "select", "deselect", and "toggle" signals
7771 from GtkItem. In addition, it adds two signals of its own, "expand"
7775 void select( GtkItem *tree_item );
7778 This signal is emitted when an item is about to be selected, either
7779 after it has been clicked on by the user, or when the program calls
7780 gtk_tree_item_select(), gtk_item_select(), or gtk_tree_select_child().
7783 void deselect( GtkItem *tree_item );
7786 This signal is emitted when an item is about to be unselected, either
7787 after it has been clicked on by the user, or when the program calls
7788 gtk_tree_item_deselect() or gtk_item_deselect(). In the case of
7789 GtkTreeItems, it is also emitted by gtk_tree_unselect_child(), and
7790 sometimes gtk_tree_select_child().
7793 void toggle( GtkItem *tree_item );
7796 This signal is emitted when the program calls gtk_item_toggle(). The
7797 effect it has when emitted on a GtkTreeItem is to call
7798 gtk_tree_select_child() (and never gtk_tree_unselect_child()) on the
7799 item's parent tree, if the item has a parent tree. If it doesn't,
7800 then the highlight is reversed on the item.
7803 void expand( GtkTreeItem *tree_item );
7806 This signal is emitted when the tree item's subtree is about to be
7807 expanded, that is, when the user clicks on the plus sign next to the
7808 item, or when the program calls gtk_tree_item_expand().
7811 void collapse( GtkTreeItem *tree_item );
7814 This signal is emitted when the tree item's subtree is about to be
7815 collapsed, that is, when the user clicks on the minus sign next to the
7816 item, or when the program calls gtk_tree_item_collapse().
7818 <sect2> Functions and Macros
7821 guint gtk_tree_item_get_type( void );
7824 Returns the `GtkTreeItem' type identifier.
7827 GtkWidget* gtk_tree_item_new( void );
7830 Create a new GtkTreeItem object. The new widget is returned as a
7831 pointer to a GtkWidget object. NULL is returned on failure.
7834 GtkWidget* gtk_tree_item_new_with_label (gchar *label);
7837 Create a new GtkTreeItem object, having a single GtkLabel as the sole
7838 child. The new widget is returned as a pointer to a GtkWidget
7839 object. NULL is returned on failure.
7842 void gtk_tree_item_select( GtkTreeItem *tree_item );
7845 This function is basically a wrapper around a call to gtk_item_select
7846 (GTK_ITEM (tree_item)) which will emit the select signal.
7849 void gtk_tree_item_deselect( GtkTreeItem *tree_item );
7852 This function is basically a wrapper around a call to
7853 gtk_item_deselect (GTK_ITEM (tree_item)) which will emit the deselect
7857 void gtk_tree_item_set_subtree( GtkTreeItem *tree_item,
7858 GtkWidget *subtree );
7861 This function adds subtree to tree_item, showing it if tree_item is
7862 expanded, or hiding it if tree_item is collapsed. Again, remember that
7863 the tree_item must have already been added to a tree for this to work.
7866 void gtk_tree_item_remove_subtree( GtkTreeItem *tree_item );
7869 This removes all of tree_item's subtree's children (thus unreferencing
7870 and destroying it, any of its children's subtrees, and so on...), then
7871 removes the subtree itself, and hides the plus/minus sign.
7874 void gtk_tree_item_expand( GtkTreeItem *tree_item );
7877 This emits the "expand" signal on tree_item, which expands it.
7880 void gtk_tree_item_collapse( GtkTreeItem *tree_item );
7883 This emits the "collapse" signal on tree_item, which collapses it.
7886 GtkTreeItem *GTK_TREE_ITEM (gpointer obj)
7889 Cast a generic pointer to `GtkTreeItem*'.
7892 GtkTreeItemClass *GTK_TREE_ITEM_CLASS (gpointer obj)
7895 Cast a generic pointer to `GtkTreeItemClass'.
7898 gint GTK_IS_TREE_ITEM (gpointer obj)
7901 Determine if a generic pointer refers to a `GtkTreeItem' object.
7904 GtkWidget GTK_TREE_ITEM_SUBTREE (gpointer obj)
7907 Returns a tree item's subtree (obj should point to a `GtkTreeItem'
7910 <sect1> Tree Example
7912 This is somewhat like the tree example in testgtk.c, but a lot less
7913 complete (although much better commented). It puts up a window with a
7914 tree, and connects all the signals for the relevant objects, so you
7915 can see when they are emitted.
7918 /* example-start tree tree.c */
7920 #include <gtk/gtk.h>
7922 /* for all the GtkItem:: and GtkTreeItem:: signals */
7923 static void cb_itemsignal (GtkWidget *item, gchar *signame)
7928 /* It's a GtkBin, so it has one child, which we know to be a
7929 label, so get that */
7930 label = GTK_LABEL (GTK_BIN (item)->child);
7931 /* Get the text of the label */
7932 gtk_label_get (label, &name);
7933 /* Get the level of the tree which the item is in */
7934 g_print ("%s called for item %s->%p, level %d\n", signame, name,
7935 item, GTK_TREE (item->parent)->level);
7938 /* Note that this is never called */
7939 static void cb_unselect_child (GtkWidget *root_tree, GtkWidget *child,
7942 g_print ("unselect_child called for root tree %p, subtree %p, child %p\n",
7943 root_tree, subtree, child);
7946 /* Note that this is called every time the user clicks on an item,
7947 whether it is already selected or not. */
7948 static void cb_select_child (GtkWidget *root_tree, GtkWidget *child,
7951 g_print ("select_child called for root tree %p, subtree %p, child %p\n",
7952 root_tree, subtree, child);
7955 static void cb_selection_changed (GtkWidget *tree)
7959 g_print ("selection_change called for tree %p\n", tree);
7960 g_print ("selected objects are:\n");
7962 i = GTK_TREE_SELECTION(tree);
7968 /* Get a GtkWidget pointer from the list node */
7969 item = GTK_WIDGET (i->data);
7970 label = GTK_LABEL (GTK_BIN (item)->child);
7971 gtk_label_get (label, &name);
7972 g_print ("\t%s on level %d\n", name, GTK_TREE
7973 (item->parent)->level);
7978 int main (int argc, char *argv[])
7980 GtkWidget *window, *scrolled_win, *tree;
7981 static gchar *itemnames[] = {"Foo", "Bar", "Baz", "Quux",
7985 gtk_init (&argc, &argv);
7987 /* a generic toplevel window */
7988 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
7989 gtk_signal_connect (GTK_OBJECT(window), "delete_event",
7990 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
7991 gtk_container_border_width (GTK_CONTAINER(window), 5);
7993 /* A generic scrolled window */
7994 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
7995 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
7996 GTK_POLICY_AUTOMATIC,
7997 GTK_POLICY_AUTOMATIC);
7998 gtk_widget_set_usize (scrolled_win, 150, 200);
7999 gtk_container_add (GTK_CONTAINER(window), scrolled_win);
8000 gtk_widget_show (scrolled_win);
8002 /* Create the root tree */
8003 tree = gtk_tree_new();
8004 g_print ("root tree is %p\n", tree);
8005 /* connect all GtkTree:: signals */
8006 gtk_signal_connect (GTK_OBJECT(tree), "select_child",
8007 GTK_SIGNAL_FUNC(cb_select_child), tree);
8008 gtk_signal_connect (GTK_OBJECT(tree), "unselect_child",
8009 GTK_SIGNAL_FUNC(cb_unselect_child), tree);
8010 gtk_signal_connect (GTK_OBJECT(tree), "selection_changed",
8011 GTK_SIGNAL_FUNC(cb_selection_changed), tree);
8012 /* Add it to the scrolled window */
8013 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW(scrolled_win),
8015 /* Set the selection mode */
8016 gtk_tree_set_selection_mode (GTK_TREE(tree),
8017 GTK_SELECTION_MULTIPLE);
8019 gtk_widget_show (tree);
8021 for (i = 0; i < 5; i++){
8022 GtkWidget *subtree, *item;
8025 /* Create a tree item */
8026 item = gtk_tree_item_new_with_label (itemnames[i]);
8027 /* Connect all GtkItem:: and GtkTreeItem:: signals */
8028 gtk_signal_connect (GTK_OBJECT(item), "select",
8029 GTK_SIGNAL_FUNC(cb_itemsignal), "select");
8030 gtk_signal_connect (GTK_OBJECT(item), "deselect",
8031 GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
8032 gtk_signal_connect (GTK_OBJECT(item), "toggle",
8033 GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
8034 gtk_signal_connect (GTK_OBJECT(item), "expand",
8035 GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
8036 gtk_signal_connect (GTK_OBJECT(item), "collapse",
8037 GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
8038 /* Add it to the parent tree */
8039 gtk_tree_append (GTK_TREE(tree), item);
8040 /* Show it - this can be done at any time */
8041 gtk_widget_show (item);
8042 /* Create this item's subtree */
8043 subtree = gtk_tree_new();
8044 g_print ("-> item %s->%p, subtree %p\n", itemnames[i], item,
8047 /* This is still necessary if you want these signals to be called
8048 for the subtree's children. Note that selection_change will be
8049 signalled for the root tree regardless. */
8050 gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
8051 GTK_SIGNAL_FUNC(cb_select_child), subtree);
8052 gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
8053 GTK_SIGNAL_FUNC(cb_unselect_child), subtree);
8054 /* This has absolutely no effect, because it is completely ignored
8056 gtk_tree_set_selection_mode (GTK_TREE(subtree),
8057 GTK_SELECTION_SINGLE);
8058 /* Neither does this, but for a rather different reason - the
8059 view_mode and view_line values of a tree are propagated to
8060 subtrees when they are mapped. So, setting it later on would
8061 actually have a (somewhat unpredictable) effect */
8062 gtk_tree_set_view_mode (GTK_TREE(subtree), GTK_TREE_VIEW_ITEM);
8063 /* Set this item's subtree - note that you cannot do this until
8064 AFTER the item has been added to its parent tree! */
8065 gtk_tree_item_set_subtree (GTK_TREE_ITEM(item), subtree);
8067 for (j = 0; j < 5; j++){
8070 /* Create a subtree item, in much the same way */
8071 subitem = gtk_tree_item_new_with_label (itemnames[j]);
8072 /* Connect all GtkItem:: and GtkTreeItem:: signals */
8073 gtk_signal_connect (GTK_OBJECT(subitem), "select",
8074 GTK_SIGNAL_FUNC(cb_itemsignal), "select");
8075 gtk_signal_connect (GTK_OBJECT(subitem), "deselect",
8076 GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
8077 gtk_signal_connect (GTK_OBJECT(subitem), "toggle",
8078 GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
8079 gtk_signal_connect (GTK_OBJECT(subitem), "expand",
8080 GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
8081 gtk_signal_connect (GTK_OBJECT(subitem), "collapse",
8082 GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
8083 g_print ("-> -> item %s->%p\n", itemnames[j], subitem);
8084 /* Add it to its parent tree */
8085 gtk_tree_append (GTK_TREE(subtree), subitem);
8087 gtk_widget_show (subitem);
8091 /* Show the window and loop endlessly */
8092 gtk_widget_show (window);
8099 <!-- ***************************************************************** -->
8101 <!-- ***************************************************************** -->
8103 There are two ways to create menus, there's the easy way, and there's the
8104 hard way. Both have their uses, but you can usually use the menufactory
8105 (the easy way). The "hard" way is to create all the menus using the calls
8106 directly. The easy way is to use the gtk_menu_factory calls. This is
8107 much simpler, but there are advantages and disadvantages to each approach.
8109 The menufactory is much easier to use, and to add new menus to, although
8110 writing a few wrapper functions to create menus using the manual method
8111 could go a long way towards usability. With the menufactory, it is not
8112 possible to add images or the character '/' to the menus.
8114 <!-- ----------------------------------------------------------------- -->
8115 <sect1>Manual Menu Creation
8117 In the true tradition of teaching, we'll show you the hard
8118 way first. <tt>:)</>
8120 There are three widgets that go into making a menubar and submenus:
8122 <item>a menu item, which is what the user wants to select, e.g. 'Save'
8123 <item>a menu, which acts as a container for the menu items, and
8124 <item>a menubar, which is a container for each of the individual menus,
8127 This is slightly complicated by the fact that menu item widgets are used
8128 for two different things. They are both the widgets that are packed into
8129 the menu, and the widget that is packed into the menubar, which,
8130 when selected, activates the menu.
8132 Let's look at the functions that are used to create menus and menubars.
8133 This first function is used to create a new menubar.
8136 GtkWidget *gtk_menu_bar_new( void );
8139 This rather self explanatory function creates a new menubar. You use
8140 gtk_container_add to pack this into a window, or the box_pack functions to
8141 pack it into a box - the same as buttons.
8144 GtkWidget *gtk_menu_new( void );
8147 This function returns a pointer to a new menu, it is never actually shown
8148 (with gtk_widget_show), it is just a container for the menu items. Hopefully this will
8149 become more clear when you look at the example below.
8151 The next two calls are used to create menu items that are packed into
8152 the menu (and menubar).
8155 GtkWidget *gtk_menu_item_new( void );
8161 GtkWidget *gtk_menu_item_new_with_label( const char *label );
8164 These calls are used to create the menu items that are to be displayed.
8165 Remember to differentiate between a "menu" as created with gtk_menu_new
8166 and a "menu item" as created by the gtk_menu_item_new functions. The
8167 menu item will be an actual button with an associated action,
8168 whereas a menu will be a container holding menu items.
8170 The gtk_menu_new_with_label and gtk_menu_new functions are just as you'd expect after
8171 reading about the buttons. One creates a new menu item with a label
8172 already packed into it, and the other just creates a blank menu item.
8174 Once you've created a menu item you have to put it into a menu. This is
8175 done using the function gtk_menu_append. In order to capture when the item
8176 is selected by the user, we need to connect to the <tt/activate/ signal in
8177 the usual way. So, if we wanted to create a standard <tt/File/ menu, with
8178 the options <tt/Open/, <tt/Save/ and <tt/Quit/ the code would look something like
8181 file_menu = gtk_menu_new(); /* Don't need to show menus */
8183 /* Create the menu items */
8184 open_item = gtk_menu_item_new_with_label("Open");
8185 save_item = gtk_menu_item_new_with_label("Save");
8186 quit_item = gtk_menu_item_new_with_label("Quit");
8188 /* Add them to the menu */
8189 gtk_menu_append( GTK_MENU(file_menu), open_item);
8190 gtk_menu_append( GTK_MENU(file_menu), save_item);
8191 gtk_menu_append( GTK_MENU(file_menu), quit_item);
8193 /* Attach the callback functions to the activate signal */
8194 gtk_signal_connect_object( GTK_OBJECT(open_items), "activate",
8195 GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.open");
8196 gtk_signal_connect_object( GTK_OBJECT(save_items), "activate",
8197 GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.save");
8199 /* We can attach the Quit menu item to our exit function */
8200 gtk_signal_connect_object( GTK_OBJECT(quit_items), "activate",
8201 GTK_SIGNAL_FUNC(destroy), (gpointer) "file.quit");
8203 /* We do need to show menu items */
8204 gtk_widget_show( open_item );
8205 gtk_widget_show( save_item );
8206 gtk_widget_show( quit_item );
8209 At this point we have our menu. Now we need to create a menubar and a menu
8210 item for the <tt/File/ entry, to which we add our menu. The code looks like this
8213 menu_bar = gtk_menu_bar_new();
8214 gtk_container_add( GTK_CONTAINER(window), menu_bar);
8215 gtk_widget_show( menu_bar );
8217 file_item = gtk_menu_item_new_with_label("File");
8218 gtk_widget_show(file_item);
8221 Now we need to associate the menu with <tt/file_item/. This is done with the
8225 void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
8226 GtkWidget *submenu );
8229 So, our example would continue with
8232 gtk_menu_item_set_submenu( GTK_MENU_ITEM(file_item), file_menu );
8235 All that is left to do is to add the menu to the menubar, which is accomplished
8239 void gtk_menu_bar_append( GtkMenuBar *menu_bar, GtkWidget *menu_item);
8242 which in our case looks like this:
8245 gtk_menu_bar_append( GTK_MENU_BAR (menu_bar), file_item );
8248 If we wanted the menu right justified on the menubar, such as help menus
8249 often are, we can use the following function (again on <tt/file_item/
8250 in the current example) before attaching it to the menubar.
8253 void gtk_menu_item_right_justify( GtkMenuItem *menu_item );
8256 Here is a summary of the steps needed to create a menu bar with menus attached:
8259 <item> Create a new menu using gtk_menu_new()
8260 <item> Use multiple calls to gtk_menu_item_new() for each item you wish to have
8261 on your menu. And use gtk_menu_append() to put each of these new items on
8263 <item> Create a menu item using gtk_menu_item_new(). This will be the root of
8264 the menu, the text appearing here will be on the menubar itself.
8265 <item>Use gtk_menu_item_set_submenu() to attach the menu to the root menu
8266 item (the one created in the above step).
8267 <item> Create a new menubar using gtk_menu_bar_new. This step only needs
8268 to be done once when creating a series of menus on one menu bar.
8269 <item> Use gtk_menu_bar_append to put the root menu onto the menubar.
8272 Creating a popup menu is nearly the same. The difference is that the
8273 menu is not posted `automatically' by a menubar, but explicitly by calling
8274 the function gtk_menu_popup() from a button-press event, for example.
8278 <item>Create an event handling function. It needs to have the prototype
8280 static gint handler( GtkWidget *widget,
8283 and it will use the event to find out where to pop up the menu.
8284 <item>In the event handler, if the event is a mouse button press, treat
8285 <tt>event</tt> as a button event (which it is) and use it as
8286 shown in the sample code to pass information to gtk_menu_popup().
8287 <item>Bind that event handler to a widget with
8289 gtk_signal_connect_object(GTK_OBJECT(widget), "event",
8290 GTK_SIGNAL_FUNC (handler), GTK_OBJECT(menu));
8292 where <tt>widget</tt> is the widget you are binding to, <tt>handler</tt>
8293 is the handling function, and <tt>menu</tt> is a menu created with
8294 gtk_menu_new(). This can be a menu which is also posted by a menu bar,
8295 as shown in the sample code.
8298 <!-- ----------------------------------------------------------------- -->
8299 <sect1>Manual Menu Example
8301 That should about do it. Let's take a look at an example to help clarify.
8304 /* example-start menu menu.c */
8306 #include <gtk/gtk.h>
8308 static gint button_press (GtkWidget *, GdkEvent *);
8309 static void menuitem_response (gchar *);
8311 int main (int argc, char *argv[])
8316 GtkWidget *menu_bar;
8317 GtkWidget *root_menu;
8318 GtkWidget *menu_items;
8324 gtk_init (&argc, &argv);
8326 /* create a new window */
8327 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
8328 gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
8329 gtk_window_set_title(GTK_WINDOW (window), "GTK Menu Test");
8330 gtk_signal_connect(GTK_OBJECT (window), "delete_event",
8331 (GtkSignalFunc) gtk_main_quit, NULL);
8333 /* Init the menu-widget, and remember -- never
8334 * gtk_show_widget() the menu widget!!
8335 * This is the menu that holds the menu items, the one that
8336 * will pop up when you click on the "Root Menu" in the app */
8337 menu = gtk_menu_new();
8339 /* Next we make a little loop that makes three menu-entries for "test-menu".
8340 * Notice the call to gtk_menu_append. Here we are adding a list of
8341 * menu items to our menu. Normally, we'd also catch the "clicked"
8342 * signal on each of the menu items and setup a callback for it,
8343 * but it's omitted here to save space. */
8345 for(i = 0; i < 3; i++)
8347 /* Copy the names to the buf. */
8348 sprintf(buf, "Test-undermenu - %d", i);
8350 /* Create a new menu-item with a name... */
8351 menu_items = gtk_menu_item_new_with_label(buf);
8353 /* ...and add it to the menu. */
8354 gtk_menu_append(GTK_MENU (menu), menu_items);
8356 /* Do something interesting when the menuitem is selected */
8357 gtk_signal_connect_object(GTK_OBJECT(menu_items), "activate",
8358 GTK_SIGNAL_FUNC(menuitem_response), (gpointer) g_strdup(buf));
8360 /* Show the widget */
8361 gtk_widget_show(menu_items);
8364 /* This is the root menu, and will be the label
8365 * displayed on the menu bar. There won't be a signal handler attached,
8366 * as it only pops up the rest of the menu when pressed. */
8367 root_menu = gtk_menu_item_new_with_label("Root Menu");
8369 gtk_widget_show(root_menu);
8371 /* Now we specify that we want our newly created "menu" to be the menu
8372 * for the "root menu" */
8373 gtk_menu_item_set_submenu(GTK_MENU_ITEM (root_menu), menu);
8375 /* A vbox to put a menu and a button in: */
8376 vbox = gtk_vbox_new(FALSE, 0);
8377 gtk_container_add(GTK_CONTAINER(window), vbox);
8378 gtk_widget_show(vbox);
8380 /* Create a menu-bar to hold the menus and add it to our main window */
8381 menu_bar = gtk_menu_bar_new();
8382 gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 2);
8383 gtk_widget_show(menu_bar);
8385 /* Create a button to which to attach menu as a popup */
8386 button = gtk_button_new_with_label("press me");
8387 gtk_signal_connect_object(GTK_OBJECT(button), "event",
8388 GTK_SIGNAL_FUNC (button_press), GTK_OBJECT(menu));
8389 gtk_box_pack_end(GTK_BOX(vbox), button, TRUE, TRUE, 2);
8390 gtk_widget_show(button);
8392 /* And finally we append the menu-item to the menu-bar -- this is the
8393 * "root" menu-item I have been raving about =) */
8394 gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), root_menu);
8396 /* always display the window as the last step so it all splashes on
8397 * the screen at once. */
8398 gtk_widget_show(window);
8405 /* Respond to a button-press by posting a menu passed in as widget.
8407 * Note that the "widget" argument is the menu being posted, NOT
8408 * the button that was pressed.
8411 static gint button_press (GtkWidget *widget, GdkEvent *event)
8414 if (event->type == GDK_BUTTON_PRESS) {
8415 GdkEventButton *bevent = (GdkEventButton *) event;
8416 gtk_menu_popup (GTK_MENU(widget), NULL, NULL, NULL, NULL,
8417 bevent->button, bevent->time);
8418 /* Tell calling code that we have handled this event; the buck
8423 /* Tell calling code that we have not handled this event; pass it on. */
8428 /* Print a string when a menu item is selected */
8430 static void menuitem_response (gchar *string)
8432 printf("%s\n", string);
8437 You may also set a menu item to be insensitive and, using an accelerator
8438 table, bind keys to menu functions.
8440 <!-- ----------------------------------------------------------------- -->
8441 <sect1>Using GtkMenuFactory
8443 Now that we've shown you the hard way, here's how you do it using the
8444 gtk_menu_factory calls.
8446 <!-- ----------------------------------------------------------------- -->
8447 <sect1>Menu Factory Example
8449 Here is an example using the GTK menu factory. This is the first file,
8450 menufactory.h. We keep a separate menufactory.c and mfmain.c because
8451 of the global variables used in the menufactory.c file.
8454 /* example-start menu menufactory.h */
8456 #ifndef __MENUFACTORY_H__
8457 #define __MENUFACTORY_H__
8461 #endif /* __cplusplus */
8463 void get_main_menu (GtkWidget *, GtkWidget **menubar);
8467 #endif /* __cplusplus */
8469 #endif /* __MENUFACTORY_H__ */
8474 And here is the menufactory.c file.
8477 /* example-start menu menufactory.c */
8479 #include <gtk/gtk.h>
8480 #include <strings.h>
8484 static void print_hello(GtkWidget *widget, gpointer data);
8487 /* this is the GtkMenuEntry structure used to create new menus. The
8488 * first member is the menu definition string. The second, the
8489 * default accelerator key used to access this menu function with
8490 * the keyboard. The third is the callback function to call when
8491 * this menu item is selected (by the accelerator key, or with the
8492 * mouse.) The last member is the data to pass to your callback function.
8495 static GtkMenuEntry menu_items[] =
8497 {"<Main>/File/New", "<control>N", print_hello, NULL},
8498 {"<Main>/File/Open", "<control>O", print_hello, NULL},
8499 {"<Main>/File/Save", "<control>S", print_hello, NULL},
8500 {"<Main>/File/Save as", NULL, NULL, NULL},
8501 {"<Main>/File/<separator>", NULL, NULL, NULL},
8502 {"<Main>/File/Quit", "<control>Q", file_quit_cmd_callback, "OK, I'll quit"},
8503 {"<Main>/Options/Test", NULL, NULL, NULL}
8508 print_hello(GtkWidget *widget, gpointer data)
8513 void get_main_menu(GtkWidget *window, GtkWidget ** menubar)
8515 int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
8516 GtkMenuFactory *factory;
8517 GtkMenuFactory *subfactory;
8519 factory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
8520 subfactory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
8522 gtk_menu_factory_add_subfactory(factory, subfactory, "<Main>");
8523 gtk_menu_factory_add_entries(factory, menu_items, nmenu_items);
8524 gtk_window_add_accelerator_table(GTK_WINDOW(window), subfactory->table);
8527 *menubar = subfactory->widget;
8533 And here's the mfmain.h
8536 /* example-start menu mfmain.h */
8538 #ifndef __MFMAIN_H__
8539 #define __MFMAIN_H__
8544 #endif /* __cplusplus */
8546 void file_quit_cmd_callback(GtkWidget *widget, gpointer data);
8550 #endif /* __cplusplus */
8552 #endif /* __MFMAIN_H__ */
8560 /* example-start menu mfmain.c */
8562 #include <gtk/gtk.h>
8565 #include "menufactory.h"
8567 int main(int argc, char *argv[])
8570 GtkWidget *main_vbox;
8573 gtk_init(&argc, &argv);
8575 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
8576 gtk_signal_connect(GTK_OBJECT(window), "destroy",
8577 GTK_SIGNAL_FUNC(file_quit_cmd_callback),
8579 gtk_window_set_title(GTK_WINDOW(window), "Menu Factory");
8580 gtk_widget_set_usize(GTK_WIDGET(window), 300, 200);
8582 main_vbox = gtk_vbox_new(FALSE, 1);
8583 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
8584 gtk_container_add(GTK_CONTAINER(window), main_vbox);
8585 gtk_widget_show(main_vbox);
8587 get_main_menu(window, &menubar);
8588 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
8589 gtk_widget_show(menubar);
8591 gtk_widget_show(window);
8597 /* This is just to demonstrate how callbacks work when using the
8598 * menufactory. Often, people put all the callbacks from the menus
8599 * in a separate file, and then have them call the appropriate functions
8600 * from there. Keeps it more organized. */
8601 void file_quit_cmd_callback (GtkWidget *widget, gpointer data)
8603 g_print ("%s\n", (char *) data);
8610 And a makefile so it'll be easier to compile it.
8617 C_FLAGS = -Wall $(PROF) -L/usr/local/include -DDEBUG
8618 L_FLAGS = $(PROF) -L/usr/X11R6/lib -L/usr/local/lib
8619 L_POSTFLAGS = -lgtk -lgdk -lglib -lXext -lX11 -lm
8620 PROGNAME = menufactory
8622 O_FILES = menufactory.o mfmain.o
8624 $(PROGNAME): $(O_FILES)
8626 $(CC) $(L_FLAGS) -o $(PROGNAME) $(O_FILES) $(L_POSTFLAGS)
8629 $(CC) -c $(C_FLAGS) $<
8632 rm -f core *.o $(PROGNAME) nohup.out
8637 For now, there's only this example. An explanation and lots 'o' comments
8640 <!-- ***************************************************************** -->
8642 <!-- ***************************************************************** -->
8644 The Text widget allows multiple lines of text to be displayed and edited.
8645 It supports both multi-colored and multi-font text, allowing them to be
8646 mixed in any way we wish. It also has a wide set of key based text editing
8647 commands, which are compatible with Emacs.
8649 The text widget supports full cut-and-paste facilities, including the use
8650 of double- and triple-click to select a word and a whole line, respectively.
8652 <!-- ----------------------------------------------------------------- -->
8653 <sect1>Creating and Configuring a Text box
8655 There is only one function for creating a new Text widget.
8657 GtkWidget *gtk_text_new( GtkAdjustment *hadj,
8658 GtkAdjustment *vadj );
8661 The arguments allow us to give the Text widget pointers to Adjustments
8662 that can be used to track the viewing position of the widget. Passing NULL
8663 values to either or both of these arguments will cause the gtk_text_new
8664 function to create its own.
8667 void gtk_text_set_adjustments( GtkText *text,
8668 GtkAdjustment *hadj,
8669 GtkAdjustment *vadj );
8672 The above function allows the horizontal and vertical adjustments of a
8673 Text widget to be changed at any time.
8675 The text widget will not automatically create its own scrollbars when
8676 the amount of text to be displayed is too long for the display window. We
8677 therefore have to create and add them to the display layout ourselves.
8680 vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
8681 gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, FALSE, 0);
8682 gtk_widget_show (vscrollbar);
8685 The above code snippet creates a new vertical scrollbar, and attaches
8686 it to the vertical adjustment of the text widget, <tt/text/. It then packs
8687 it into a box in the normal way.
8689 Note, currently the GtkText widget does not support horizontal scrollbars.
8691 There are two main ways in which a Text widget can be used: to allow the
8692 user to edit a body of text, or to allow us to display multiple lines of
8693 text to the user. In order for us to switch between these modes of
8694 operation, the text widget has the following function:
8697 void gtk_text_set_editable( GtkText *text,
8701 The <tt/editable/ argument is a TRUE or FALSE value that specifies whether
8702 the user is permitted to edit the contents of the Text widget. When the
8703 text widget is editable, it will display a cursor at the current insertion
8706 You are not, however, restricted to just using the text widget in these
8707 two modes. You can toggle the editable state of the text widget at any
8708 time, and can insert text at any time.
8710 The text widget wraps lines of text that are too long to
8711 fit onto a single line of the display window. Its default behaviour is
8712 to break words across line breaks. This can be changed using the next
8716 void gtk_text_set_word_wrap( GtkText *text,
8720 Using this function allows us to specify that the text widget should
8721 wrap long lines on word boundaries. The <tt/word_wrap/ argument is a
8722 TRUE or FALSE value.
8724 <!-- ----------------------------------------------------------------- -->
8725 <sect1>Text Manipulation
8727 The current insertion point of a Text widget can be set using
8729 void gtk_text_set_point( GtkText *text,
8733 where <tt/index/ is the position to set the insertion point.
8735 Analogous to this is the function for getting the current insertion point:
8738 guint gtk_text_get_point( GtkText *text );
8741 A function that is useful in combination with the above two functions is
8744 guint gtk_text_get_length( GtkText *text );
8747 which returns the current length of the Text widget. The length is the
8748 number of characters that are within the text block of the widget,
8749 including characters such as carriage-return, which marks the end of lines.
8751 In order to insert text at the current insertion point of a Text
8752 widget, the function gtk_text_insert is used, which also allows us to
8753 specify background and foreground colors and a font for the text.
8756 void gtk_text_insert( GtkText *text,
8764 Passing a value of <tt/NULL/ in as the value for the foreground color,
8765 background colour or font will result in the values set within the widget
8766 style to be used. Using a value of <tt/-1/ for the length parameter will
8767 result in the whole of the text string given being inserted.
8769 The text widget is one of the few within GTK that redraws itself
8770 dynamically, outside of the gtk_main function. This means that all changes
8771 to the contents of the text widget take effect immediately. This may be
8772 undesirable when performing multiple changes to the text widget. In order
8773 to allow us to perform multiple updates to the text widget without it
8774 continuously redrawing, we can freeze the widget, which temporarily stops
8775 it from automatically redrawing itself every time it is changed. We can
8776 then thaw the widget after our updates are complete.
8778 The following two functions perform this freeze and thaw action:
8781 void gtk_text_freeze( GtkText *text );
8783 void gtk_text_thaw( GtkText *text );
8786 Text is deleted from the text widget relative to the current insertion
8787 point by the following two functions. The return value is a TRUE or
8788 FALSE indicator of whether the operation was successful.
8791 gint gtk_text_backward_delete( GtkText *text,
8794 gint gtk_text_forward_delete ( GtkText *text,
8798 If you want to retrieve the contents of the text widget, then the macro
8799 <tt/GTK_TEXT_INDEX(t, index)/ allows you to retrieve the character at
8800 position <tt/index/ within the text widget <tt/t/.
8802 To retrieve larger blocks of text, we can use the function
8805 gchar *gtk_editable_get_chars( GtkEditable *editable,
8810 This is a function of the parent class of the text widget. A value of -1 as
8811 <tt/end_pos/ signifies the end of the text. The index of the text starts at 0.
8813 The function allocates a new chunk of memory for the text block, so don't forget
8814 to free it with a call to g_free when you have finished with it.
8816 <!-- ----------------------------------------------------------------- -->
8817 <sect1>Keyboard Shortcuts
8819 The text widget has a number of pre-installed keyboard shortcuts for common
8820 editing, motion and selection functions. These are accessed using Control
8821 and Alt key combinations.
8823 In addition to these, holding down the Control key whilst using cursor key
8824 movement will move the cursor by words rather than characters. Holding down
8825 Shift whilst using cursor movement will extend the selection.
8827 <sect2>Motion Shortcuts
8830 <item> Ctrl-A Beginning of line
8831 <item> Ctrl-E End of line
8832 <item> Ctrl-N Next Line
8833 <item> Ctrl-P Previous Line
8834 <item> Ctrl-B Backward one character
8835 <item> Ctrl-F Forward one character
8836 <item> Alt-B Backward one word
8837 <item> Alt-F Forward one word
8840 <sect2>Editing Shortcuts
8843 <item> Ctrl-H Delete Backward Character (Backspace)
8844 <item> Ctrl-D Delete Forward Character (Delete)
8845 <item> Ctrl-W Delete Backward Word
8846 <item> Alt-D Delete Forward Word
8847 <item> Ctrl-K Delete to end of line
8848 <item> Ctrl-U Delete line
8851 <sect2>Selection Shortcuts
8854 <item> Ctrl-X Cut to clipboard
8855 <item> Ctrl-C Copy to clipboard
8856 <item> Ctrl-V Paste from clipboard
8859 <!-- ----------------------------------------------------------------- -->
8860 <sect1>A GtkText Example
8863 /* example-start text text.c */
8868 #include <gtk/gtk.h>
8870 void text_toggle_editable (GtkWidget *checkbutton,
8873 gtk_text_set_editable(GTK_TEXT(text),
8874 GTK_TOGGLE_BUTTON(checkbutton)->active);
8877 void text_toggle_word_wrap (GtkWidget *checkbutton,
8880 gtk_text_set_word_wrap(GTK_TEXT(text),
8881 GTK_TOGGLE_BUTTON(checkbutton)->active);
8884 void close_application( GtkWidget *widget, gpointer data )
8889 int main (int argc, char *argv[])
8897 GtkWidget *separator;
8899 GtkWidget *vscrollbar;
8903 GdkFont *fixed_font;
8907 gtk_init (&argc, &argv);
8909 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
8910 gtk_widget_set_usize (window, 600, 500);
8911 gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, FALSE);
8912 gtk_signal_connect (GTK_OBJECT (window), "destroy",
8913 GTK_SIGNAL_FUNC(close_application),
8915 gtk_window_set_title (GTK_WINDOW (window), "Text Widget Example");
8916 gtk_container_border_width (GTK_CONTAINER (window), 0);
8919 box1 = gtk_vbox_new (FALSE, 0);
8920 gtk_container_add (GTK_CONTAINER (window), box1);
8921 gtk_widget_show (box1);
8924 box2 = gtk_vbox_new (FALSE, 10);
8925 gtk_container_border_width (GTK_CONTAINER (box2), 10);
8926 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
8927 gtk_widget_show (box2);
8930 table = gtk_table_new (2, 2, FALSE);
8931 gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
8932 gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
8933 gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
8934 gtk_widget_show (table);
8936 /* Create the GtkText widget */
8937 text = gtk_text_new (NULL, NULL);
8938 gtk_text_set_editable (GTK_TEXT (text), TRUE);
8939 gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
8940 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
8941 GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
8942 gtk_widget_show (text);
8944 /* Add a vertical scrollbar to the GtkText widget */
8945 vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
8946 gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
8947 GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
8948 gtk_widget_show (vscrollbar);
8950 /* Get the system colour map and allocate the colour red */
8951 cmap = gdk_colormap_get_system();
8952 colour.red = 0xffff;
8955 if (!gdk_color_alloc(cmap, &colour)) {
8956 g_error("couldn't allocate colour");
8959 /* Load a fixed font */
8960 fixed_font = gdk_font_load ("-misc-fixed-medium-r-*-*-*-140-*-*-*-*-*-*");
8962 /* Realizing a widget creates a window for it, ready for us to insert some text */
8963 gtk_widget_realize (text);
8965 /* Freeze the text widget, ready for multiple updates */
8966 gtk_text_freeze (GTK_TEXT (text));
8968 /* Insert some coloured text */
8969 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
8971 gtk_text_insert (GTK_TEXT (text), NULL, &colour, NULL,
8973 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
8974 "text and different ", -1);
8975 gtk_text_insert (GTK_TEXT (text), fixed_font, &text->style->black, NULL,
8978 /* Load the file text.c into the text window */
8980 infile = fopen("text.c", "r");
8988 nchars = fread(buffer, 1, 1024, infile);
8989 gtk_text_insert (GTK_TEXT (text), fixed_font, NULL,
8990 NULL, buffer, nchars);
8999 /* Thaw the text widget, allowing the updates to become visible */
9000 gtk_text_thaw (GTK_TEXT (text));
9002 hbox = gtk_hbutton_box_new ();
9003 gtk_box_pack_start (GTK_BOX (box2), hbox, FALSE, FALSE, 0);
9004 gtk_widget_show (hbox);
9006 check = gtk_check_button_new_with_label("Editable");
9007 gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, FALSE, 0);
9008 gtk_signal_connect (GTK_OBJECT(check), "toggled",
9009 GTK_SIGNAL_FUNC(text_toggle_editable), text);
9010 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
9011 gtk_widget_show (check);
9012 check = gtk_check_button_new_with_label("Wrap Words");
9013 gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, TRUE, 0);
9014 gtk_signal_connect (GTK_OBJECT(check), "toggled",
9015 GTK_SIGNAL_FUNC(text_toggle_word_wrap), text);
9016 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), FALSE);
9017 gtk_widget_show (check);
9019 separator = gtk_hseparator_new ();
9020 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
9021 gtk_widget_show (separator);
9023 box2 = gtk_vbox_new (FALSE, 10);
9024 gtk_container_border_width (GTK_CONTAINER (box2), 10);
9025 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
9026 gtk_widget_show (box2);
9028 button = gtk_button_new_with_label ("close");
9029 gtk_signal_connect (GTK_OBJECT (button), "clicked",
9030 GTK_SIGNAL_FUNC(close_application),
9032 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
9033 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
9034 gtk_widget_grab_default (button);
9035 gtk_widget_show (button);
9037 gtk_widget_show (window);
9047 <!-- ***************************************************************** -->
9048 <sect> Undocumented Widgets
9049 <!-- ***************************************************************** -->
9051 These all require authors! :) Please consider contributing to our tutorial.
9053 If you must use one of these widgets that are undocumented, I strongly
9054 suggest you take a look at their respective header files in the GTK
9055 distribution. GTK's function names are very descriptive. Once you have an
9056 understanding of how things work, it's not difficult to figure out how to
9057 use a widget simply by looking at its function declarations. This, along
9058 with a few examples from others' code, and it should be no problem.
9060 When you do come to understand all the functions of a new undocumented
9061 widget, please consider writing a tutorial on it so others may benefit
9064 <!-- ----------------------------------------------------------------- -->
9065 <sect1> Fixed Container
9067 <!-- ----------------------------------------------------------------- -->
9070 <!-- ----------------------------------------------------------------- -->
9074 (This may need to be rewritten to follow the style of the rest of the tutorial)
9078 Previews serve a number of purposes in GIMP/GTK. The most important one is
9079 this. High quality images may take up to tens of megabytes of memory - easy!
9080 Any operation on an image that big is bound to take a long time. If it takes
9081 you 5-10 trial-and-errors (i.e. 10-20 steps, since you have to revert after
9082 you make an error) to choose the desired modification, it make take you
9083 literally hours to make the right one - if you don't run out of memory
9084 first. People who have spent hours in color darkrooms know the feeling.
9085 Previews to the rescue!
9087 But the annoyance of the delay is not the only issue. Oftentimes it is
9088 helpful to compare the Before and After versions side-by-side or at least
9089 back-to-back. If you're working with big images and 10 second delays,
9090 obtaining the Before and After impressions is, to say the least, difficult.
9091 For 30M images (4"x6", 600dpi, 24 bit) the side-by-side comparison is right
9092 out for most people, while back-to-back is more like back-to-1001, 1002,
9093 ..., 1010-back! Previews to the rescue!
9095 But there's more. Previews allow for side-by-side pre-previews. In other
9096 words, you write a plug-in (e.g. the filterpack simulation) which would have
9097 a number of here's-what-it-would-look-like-if-you-were-to-do-this previews.
9098 An approach like this acts as a sort of a preview palette and is very
9099 effective for subtle changes. Let's go previews!
9101 There's more. For certain plug-ins real-time image-specific human
9102 intervention maybe necessary. In the SuperNova plug-in, for example, the
9103 user is asked to enter the coordinates of the center of the future
9104 supernova. The easiest way to do this, really, is to present the user with a
9105 preview and ask him to interactively select the spot. Let's go previews!
9107 Finally, a couple of misc uses. One can use previews even when not working
9108 with big images. For example, they are useful when rendering complicated
9109 patterns. (Just check out the venerable Diffraction plug-in + many other
9110 ones!) As another example, take a look at the colormap rotation plug-in
9111 (work in progress). You can also use previews for little logos inside you
9112 plug-ins and even for an image of yourself, The Author. Let's go previews!
9114 When Not to Use Previews
9116 Don't use previews for graphs, drawing etc. GDK is much faster for that. Use
9117 previews only for rendered images!
9121 You can stick a preview into just about anything. In a vbox, an hbox, a
9122 table, a button, etc. But they look their best in tight frames around them.
9123 Previews by themselves do not have borders and look flat without them. (Of
9124 course, if the flat look is what you want...) Tight frames provide the
9129 Previews in many ways are like any other widgets in GTK (whatever that
9130 means) except they possess an additional feature: they need to be filled with
9131 some sort of an image! First, we will deal exclusively with the GTK aspect
9132 of previews and then we'll discuss how to fill them.
9138 /* Create a preview widget,
9139 set its size, an show it */
9141 preview=gtk_preview_new(GTK_PREVIEW_COLOR)
9143 GTK_PREVIEW_GRAYSCALE);*/
9144 gtk_preview_size (GTK_PREVIEW (preview), WIDTH, HEIGHT);
9145 gtk_widget_show(preview);
9146 my_preview_rendering_function(preview);
9148 Oh yeah, like I said, previews look good inside frames, so how about:
9150 GtkWidget *create_a_preview(int Width,
9157 frame = gtk_frame_new(NULL);
9158 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
9159 gtk_container_border_width (GTK_CONTAINER(frame),0);
9160 gtk_widget_show(frame);
9162 preview=gtk_preview_new (Colorfulness?GTK_PREVIEW_COLOR
9163 :GTK_PREVIEW_GRAYSCALE);
9164 gtk_preview_size (GTK_PREVIEW (preview), Width, Height);
9165 gtk_container_add(GTK_CONTAINER(frame),preview);
9166 gtk_widget_show(preview);
9168 my_preview_rendering_function(preview);
9172 That's my basic preview. This routine returns the "parent" frame so you can
9173 place it somewhere else in your interface. Of course, you can pass the
9174 parent frame to this routine as a parameter. In many situations, however,
9175 the contents of the preview are changed continually by your application. In
9176 this case you may want to pass a pointer to the preview to a
9177 "create_a_preview()" and thus have control of it later.
9179 One more important note that may one day save you a lot of time. Sometimes
9180 it is desirable to label you preview. For example, you may label the preview
9181 containing the original image as "Original" and the one containing the
9182 modified image as "Less Original". It might occur to you to pack the
9183 preview along with the appropriate label into a vbox. The unexpected caveat
9184 is that if the label is wider than the preview (which may happen for a
9185 variety of reasons unforseeable to you, from the dynamic decision on the
9186 size of the preview to the size of the font) the frame expands and no longer
9187 fits tightly over the preview. The same problem can probably arise in other
9192 The solution is to place the preview and the label into a 2x1 table and by
9193 attaching them with the following parameters (this is one possible variations
9194 of course. The key is no GTK_FILL in the second attachment):
9196 gtk_table_attach(GTK_TABLE(table),label,0,1,0,1,
9198 GTK_EXPAND|GTK_FILL,
9200 gtk_table_attach(GTK_TABLE(table),frame,0,1,1,2,
9206 And here's the result:
9212 Making a preview clickable is achieved most easily by placing it in a
9213 button. It also adds a nice border around the preview and you may not even
9214 need to place it in a frame. See the Filter Pack Simulation plug-in for an
9217 This is pretty much it as far as GTK is concerned.
9219 Filling In a Preview
9221 In order to familiarize ourselves with the basics of filling in previews,
9222 let's create the following pattern (contrived by trial and error):
9227 my_preview_rendering_function(GtkWidget *preview)
9230 #define HALF (SIZE/2)
9232 guchar *row=(guchar *) malloc(3*SIZE); /* 3 bits per dot */
9233 gint i, j; /* Coordinates */
9234 double r, alpha, x, y;
9236 if (preview==NULL) return; /* I usually add this when I want */
9237 /* to avoid silly crashes. You */
9238 /* should probably make sure that */
9239 /* everything has been nicely */
9241 for (j=0; j < ABS(cos(2*alpha)) ) { /* Are we inside the shape? */
9242 /* glib.h contains ABS(x). */
9243 row[i*3+0] = sqrt(1-r)*255; /* Define Red */
9244 row[i*3+1] = 128; /* Define Green */
9245 row[i*3+2] = 224; /* Define Blue */
9246 } /* "+0" is for alignment! */
9249 row[i*3+1] = ABS(sin((float)i/SIZE*2*PI))*255;
9250 row[i*3+2] = ABS(sin((float)j/SIZE*2*PI))*255;
9253 gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,j,SIZE);
9254 /* Insert "row" into "preview" starting at the point with */
9255 /* coordinates (0,j) first column, j_th row extending SIZE */
9256 /* pixels to the right */
9259 free(row); /* save some space */
9260 gtk_widget_draw(preview,NULL); /* what does this do? */
9261 gdk_flush(); /* or this? */
9264 Non-GIMP users can have probably seen enough to do a lot of things already.
9265 For the GIMP users I have a few pointers to add.
9269 It is probably wise to keep a reduced version of the image around with just
9270 enough pixels to fill the preview. This is done by selecting every n'th
9271 pixel where n is the ratio of the size of the image to the size of the
9272 preview. All further operations (including filling in the previews) are then
9273 performed on the reduced number of pixels only. The following is my
9274 implementation of reducing the image. (Keep in mind that I've had only basic
9277 (UNTESTED CODE ALERT!!!)
9289 SELECTION_IN_CONTEXT,
9293 ReducedImage *Reduce_The_Image(GDrawable *drawable,
9298 /* This function reduced the image down to the the selected preview size */
9299 /* The preview size is determine by LongerSize, i.e. the greater of the */
9300 /* two dimensions. Works for RGB images only! */
9301 gint RH, RW; /* Reduced height and reduced width */
9302 gint width, height; /* Width and Height of the area being reduced */
9303 gint bytes=drawable->bpp;
9304 ReducedImage *temp=(ReducedImage *)malloc(sizeof(ReducedImage));
9306 guchar *tempRGB, *src_row, *tempmask, *src_mask_row,R,G,B;
9307 gint i, j, whichcol, whichrow, x1, x2, y1, y2;
9308 GPixelRgn srcPR, srcMask;
9309 gint NoSelectionMade=TRUE; /* Assume that we're dealing with the entire */
9312 gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
9315 /* If there's a SELECTION, we got its bounds!)
9317 if (width != drawable->width && height != drawable->height)
9318 NoSelectionMade=FALSE;
9319 /* Become aware of whether the user has made an active selection */
9320 /* This will become important later, when creating a reduced mask. */
9322 /* If we want to preview the entire image, overrule the above! */
9323 /* Of course, if no selection has been made, this does nothing! */
9324 if (Selection==ENTIRE_IMAGE) {
9328 y2=drawable->height;
9331 /* If we want to preview a selection with some surrounding area we */
9332 /* have to expand it a little bit. Consider it a bit of a riddle. */
9333 if (Selection==SELECTION_IN_CONTEXT) {
9334 x1=MAX(0, x1-width/2.0);
9335 x2=MIN(drawable->width, x2+width/2.0);
9336 y1=MAX(0, y1-height/2.0);
9337 y2=MIN(drawable->height, y2+height/2.0);
9340 /* How we can determine the width and the height of the area being */
9345 /* The lines below determine which dimension is to be the longer */
9346 /* side. The idea borrowed from the supernova plug-in. I suspect I */
9347 /* could've thought of it myself, but the truth must be told. */
9348 /* Plagiarism stinks! */
9351 RH=(float) height * (float) LongerSize/ (float) width;
9355 RW=(float)width * (float) LongerSize/ (float) height;
9358 /* The entire image is stretched into a string! */
9359 tempRGB = (guchar *) malloc(RW*RH*bytes);
9360 tempmask = (guchar *) malloc(RW*RH);
9362 gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height, FALSE, FALSE);
9363 gimp_pixel_rgn_init (&srcMask, mask, x1, y1, width, height, FALSE, FALSE);
9365 /* Grab enough to save a row of image and a row of mask. */
9366 src_row = (guchar *) malloc (width*bytes);
9367 src_mask_row = (guchar *) malloc (width);
9369 for (i=0; i < RH; i++) {
9370 whichrow=(float)i*(float)height/(float)RH;
9371 gimp_pixel_rgn_get_row (&srcPR, src_row, x1, y1+whichrow, width);
9372 gimp_pixel_rgn_get_row (&srcMask, src_mask_row, x1, y1+whichrow, width);
9374 for (j=0; j < RW; j++) {
9375 whichcol=(float)j*(float)width/(float)RW;
9377 /* No selection made = each point is completely selected! */
9378 if (NoSelectionMade)
9379 tempmask[i*RW+j]=255;
9381 tempmask[i*RW+j]=src_mask_row[whichcol];
9383 /* Add the row to the one long string which now contains the image! */
9384 tempRGB[i*RW*bytes+j*bytes+0]=src_row[whichcol*bytes+0];
9385 tempRGB[i*RW*bytes+j*bytes+1]=src_row[whichcol*bytes+1];
9386 tempRGB[i*RW*bytes+j*bytes+2]=src_row[whichcol*bytes+2];
9388 /* Hold on to the alpha as well */
9390 tempRGB[i*RW*bytes+j*bytes+3]=src_row[whichcol*bytes+3];
9397 temp->mask=tempmask;
9401 The following is a preview function which used the same ReducedImage type!
9402 Note that it uses fakes transparency (if one is present by means of
9403 fake_transparency which is defined as follows:
9405 gint fake_transparency(gint i, gint j)
9407 if ( ((i%20)- 10) * ((j%20)- 10)>0 )
9413 Now here's the preview function:
9416 my_preview_render_function(GtkWidget *preview,
9420 gint Inten, bytes=drawable->bpp;
9423 gint RW=reduced->width;
9424 gint RH=reduced->height;
9425 guchar *row=malloc(bytes*RW);;
9428 for (i=0; i < RH; i++) {
9429 for (j=0; j < RW; j++) {
9431 row[j*3+0] = reduced->rgb[i*RW*bytes + j*bytes + 0];
9432 row[j*3+1] = reduced->rgb[i*RW*bytes + j*bytes + 1];
9433 row[j*3+2] = reduced->rgb[i*RW*bytes + j*bytes + 2];
9436 for (k=0; k<3; k++) {
9437 float transp=reduced->rgb[i*RW*bytes+j*bytes+3]/255.0;
9438 row[3*j+k]=transp*a[3*j+k]+(1-transp)*fake_transparency(i,j);
9441 gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,i,RW);
9445 gtk_widget_draw(preview,NULL);
9451 guint gtk_preview_get_type (void);
9453 void gtk_preview_uninit (void);
9455 GtkWidget* gtk_preview_new (GtkPreviewType type);
9456 /* Described above */
9457 void gtk_preview_size (GtkPreview *preview,
9460 /* Allows you to resize an existing preview. */
9461 /* Apparently there's a bug in GTK which makes */
9462 /* this process messy. A way to clean up a mess */
9463 /* is to manually resize the window containing */
9464 /* the preview after resizing the preview. */
9466 void gtk_preview_put (GtkPreview *preview,
9477 void gtk_preview_put_row (GtkPreview *preview,
9485 void gtk_preview_draw_row (GtkPreview *preview,
9490 /* Described in the text */
9492 void gtk_preview_set_expand (GtkPreview *preview,
9496 /* No clue for any of the below but */
9497 /* should be standard for most widgets */
9498 void gtk_preview_set_gamma (double gamma);
9499 void gtk_preview_set_color_cube (guint nred_shades,
9500 guint ngreen_shades,
9502 guint ngray_shades);
9503 void gtk_preview_set_install_cmap (gint install_cmap);
9504 void gtk_preview_set_reserved (gint nreserved);
9505 GdkVisual* gtk_preview_get_visual (void);
9506 GdkColormap* gtk_preview_get_cmap (void);
9507 GtkPreviewInfo* gtk_preview_get_info (void);
9513 <!-- ***************************************************************** -->
9514 <sect>The EventBox Widget<label id="sec_EventBox">
9515 <!-- ***************************************************************** -->
9517 Some gtk widgets don't have associated X windows, so they just draw on
9518 their parents. Because of this, they cannot receive events
9519 and if they are incorrectly sized, they don't clip so you can get
9520 messy overwriting etc. If you require more from these widgets, the
9521 EventBox is for you.
9523 At first glance, the EventBox widget might appear to be totally
9524 useless. It draws nothing on the screen and responds to no
9525 events. However, it does serve a function - it provides an X window for
9526 its child widget. This is important as many GTK widgets do not
9527 have an associated X window. Not having an X window saves memory and
9528 improves performance, but also has some drawbacks. A widget without an
9529 X window cannot receive events, and does not perform any clipping on
9530 its contents. Although the name <em/EventBox/ emphasizes the
9531 event-handling function, the widget can also be used for clipping.
9532 (And more ... see the example below.)
9534 To create a new EventBox widget, use:
9537 GtkWidget *gtk_event_box_new( void );
9540 A child widget can then be added to this EventBox:
9543 gtk_container_add( GTK_CONTAINER(event_box), widget );
9546 The following example demonstrates both uses of an EventBox - a label
9547 is created that is clipped to a small box, and set up so that a
9548 mouse-click on the label causes the program to exit.
9551 /* example-start eventbox eventbox.c */
9553 #include <gtk/gtk.h>
9556 main (int argc, char *argv[])
9559 GtkWidget *event_box;
9562 gtk_init (&argc, &argv);
9564 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9566 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
9568 gtk_signal_connect (GTK_OBJECT (window), "destroy",
9569 GTK_SIGNAL_FUNC (gtk_exit), NULL);
9571 gtk_container_border_width (GTK_CONTAINER (window), 10);
9573 /* Create an EventBox and add it to our toplevel window */
9575 event_box = gtk_event_box_new ();
9576 gtk_container_add (GTK_CONTAINER(window), event_box);
9577 gtk_widget_show (event_box);
9579 /* Create a long label */
9581 label = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
9582 gtk_container_add (GTK_CONTAINER (event_box), label);
9583 gtk_widget_show (label);
9585 /* Clip it short. */
9586 gtk_widget_set_usize (label, 110, 20);
9588 /* And bind an action to it */
9589 gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
9590 gtk_signal_connect (GTK_OBJECT(event_box), "button_press_event",
9591 GTK_SIGNAL_FUNC (gtk_exit), NULL);
9593 /* Yet one more thing you need an X window for ... */
9595 gtk_widget_realize (event_box);
9596 gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1));
9598 gtk_widget_show (window);
9607 <!-- ***************************************************************** -->
9608 <sect>Setting Widget Attributes<label id="sec_setting_widget_attributes">
9609 <!-- ***************************************************************** -->
9611 This describes the functions used to operate on widgets. These can be used
9612 to set style, padding, size etc.
9614 (Maybe I should make a whole section on accelerators.)
9617 void gtk_widget_install_accelerator( GtkWidget *widget,
9618 GtkAcceleratorTable *table,
9623 void gtk_widget_remove_accelerator ( GtkWidget *widget,
9624 GtkAcceleratorTable *table,
9625 gchar *signal_name);
9627 void gtk_widget_activate( GtkWidget *widget );
9629 void gtk_widget_set_name( GtkWidget *widget,
9632 gchar *gtk_widget_get_name( GtkWidget *widget );
9634 void gtk_widget_set_sensitive( GtkWidget *widget,
9637 void gtk_widget_set_style( GtkWidget *widget,
9640 GtkStyle *gtk_widget_get_style( GtkWidget *widget );
9642 GtkStyle *gtk_widget_get_default_style( void );
9644 void gtk_widget_set_uposition( GtkWidget *widget,
9648 void gtk_widget_set_usize( GtkWidget *widget,
9652 void gtk_widget_grab_focus( GtkWidget *widget );
9654 void gtk_widget_show( GtkWidget *widget );
9656 void gtk_widget_hide( GtkWidget *widget );
9659 <!-- ***************************************************************** -->
9660 <sect>Timeouts, IO and Idle Functions<label id="sec_timeouts">
9661 <!-- ***************************************************************** -->
9663 <!-- ----------------------------------------------------------------- -->
9666 You may be wondering how you make GTK do useful work when in gtk_main.
9667 Well, you have several options. Using the following functions you can
9668 create a timeout function that will be called every "interval"
9672 gint gtk_timeout_add( guint32 interval,
9673 GtkFunction function,
9677 The first argument is the number of milliseconds between calls to your
9678 function. The second argument is the function you wish to have called, and
9679 the third, the data passed to this callback function. The return value is
9680 an integer "tag" which may be used to stop the timeout by calling:
9683 void gtk_timeout_remove( gint tag );
9686 You may also stop the timeout function by returning zero or FALSE from
9687 your callback function. Obviously this means if you want your function to
9688 continue to be called, it should return a non-zero value, i.e. TRUE.
9690 The declaration of your callback should look something like this:
9693 gint timeout_callback( gpointer data );
9696 <!-- ----------------------------------------------------------------- -->
9697 <sect1>Monitoring IO
9699 Another nifty feature of GTK, is the ability to have it check for data on a
9700 file descriptor for you (as returned by open(2) or socket(2)). This is
9701 especially useful for networking applications. The function:
9704 gint gdk_input_add( gint source,
9705 GdkInputCondition condition,
9706 GdkInputFunction function,
9710 Where the first argument is the file descriptor you wish to have watched,
9711 and the second specifies what you want GDK to look for. This may be one of:
9714 <item>GDK_INPUT_READ - Call your function when there is data ready for
9715 reading on your file descriptor.
9717 <item>GDK_INPUT_WRITE - Call your function when the file descriptor is
9721 As I'm sure you've figured out already, the third argument is the function
9722 you wish to have called when the above conditions are satisfied, and the
9723 fourth is the data to pass to this function.
9725 The return value is a tag that may be used to stop GDK from monitoring this
9726 file descriptor using the following function.
9729 void gdk_input_remove( gint tag );
9732 The callback function should be declared as:
9735 void input_callback( gpointer data,
9737 GdkInputCondition condition );
9740 Where <tt/source/ and <tt/condition/ are as specified above.
9742 <!-- ----------------------------------------------------------------- -->
9743 <sect1>Idle Functions
9745 <!-- Need to check on idle priorities - TRG -->
9746 What if you have a function you want called when nothing else is
9750 gint gtk_idle_add( GtkFunction function,
9754 This causes GTK to call the specified function whenever nothing else is
9758 void gtk_idle_remove( gint tag );
9761 I won't explain the meaning of the arguments as they follow very much like
9762 the ones above. The function pointed to by the first argument to
9763 gtk_idle_add will be called whenever the opportunity arises. As with the
9764 others, returning FALSE will stop the idle function from being called.
9766 <!-- ***************************************************************** -->
9767 <sect>Advanced Event and Signal Handling<label id="sec_Adv_Events_and_Signals">
9768 <!-- ***************************************************************** -->
9770 <!-- ----------------------------------------------------------------- -->
9771 <sect1>Signal Functions
9773 <!-- ----------------------------------------------------------------- -->
9774 <sect2>Connecting and Disconnecting Signal Handlers
9778 guint gtk_signal_connect( GtkObject *object,
9781 gpointer func_data );
9783 guint gtk_signal_connect_after( GtkObject *object,
9786 gpointer func_data );
9788 guint gtk_signal_connect_object( GtkObject *object,
9791 GtkObject *slot_object );
9793 guint gtk_signal_connect_object_after( GtkObject *object,
9796 GtkObject *slot_object );
9798 guint gtk_signal_connect_full( GtkObject *object,
9801 GtkCallbackMarshal marshal,
9803 GtkDestroyNotify destroy_func,
9807 guint gtk_signal_connect_interp( GtkObject *object,
9809 GtkCallbackMarshal func,
9811 GtkDestroyNotify destroy_func,
9814 void gtk_signal_connect_object_while_alive( GtkObject *object,
9815 const gchar *signal,
9817 GtkObject *alive_object );
9819 void gtk_signal_connect_while_alive( GtkObject *object,
9820 const gchar *signal,
9823 GtkObject *alive_object );
9825 void gtk_signal_disconnect( GtkObject *object,
9828 void gtk_signal_disconnect_by_func( GtkObject *object,
9833 <!-- ----------------------------------------------------------------- -->
9834 <sect2>Blocking and Unblocking Signal Handlers
9837 void gtk_signal_handler_block( GtkObject *object,
9840 void gtk_signal_handler_block_by_func( GtkObject *object,
9844 void gtk_signal_handler_block_by_data( GtkObject *object,
9847 void gtk_signal_handler_unblock( GtkObject *object,
9850 void gtk_signal_handler_unblock_by_func( GtkObject *object,
9854 void gtk_signal_handler_unblock_by_data( GtkObject *object,
9858 <!-- ----------------------------------------------------------------- -->
9859 <sect2>Emitting and Stopping Signals
9862 void gtk_signal_emit( GtkObject *object,
9866 void gtk_signal_emit_by_name( GtkObject *object,
9870 void gtk_signal_emitv( GtkObject *object,
9874 void gtk_signal_emitv_by_name( GtkObject *object,
9878 guint gtk_signal_n_emissions( GtkObject *object,
9881 guint gtk_signal_n_emissions_by_name( GtkObject *object,
9882 const gchar *name );
9884 void gtk_signal_emit_stop( GtkObject *object,
9887 void gtk_signal_emit_stop_by_name( GtkObject *object,
9888 const gchar *name );
9891 <!-- ----------------------------------------------------------------- -->
9892 <sect1>Signal Emission and Propagation
9894 Signal emission is the process wherby GTK+ runs all handlers for a
9895 specific object and signal.
9897 First, note that the return value from a signal emission is the
9898 return value of the <em>last</em> handler executed. Since event signals
9899 are all of type GTK_RUN_LAST, this will be the default (GTK+ supplied)
9900 default handler, unless you connect with gtk_signal_connect_after().
9902 The way an event (say GTK_BUTTON_PRESS) is handled, is:
9904 <item>Start with the widget where the event occured.
9906 <item>Emit the generic "event" signal. If that signal handler returns
9907 a value of TRUE, stop all processing.
9909 <item>Otherwise, emit a specific, "button_press_event" signal. If that
9910 returns TRUE, stop all processing.
9912 <item>Otherwise, go to the widget's parent, and repeat the above steps.
9914 <item>Contimue until some signal handler returns TRUE, or until the
9915 top-level widget is reached.
9918 Some consequences of the above are:
9920 <item>Your handler's return value will have no effect if there is a
9921 default handler, unless you connect with gtk_signal_connect_after().
9923 <item>To prevent the default handler from being run, you need to connect
9924 with gtk_signal_connect() and use gtk_signal_emit_stop_by_name() - the
9925 return value only affects whether the signal is propagated, not the
9929 <!-- ***************************************************************** -->
9930 <sect>Managing Selections
9931 <!-- ***************************************************************** -->
9933 <!-- ----------------------------------------------------------------- -->
9936 One type of interprocess communication supported by GTK is
9937 <em>selections</em>. A selection identifies a chunk of data, for
9938 instance, a portion of text, selected by the user in some fashion, for
9939 instance, by dragging with the mouse. Only one application on a
9940 display, (the <em>owner</em> can own a particular selection at one
9941 time, so when a selection is claimed by one application, the previous
9942 owner must indicate to the user that selection has been
9943 relinquished. Other applications can request the contents of a
9944 selection in different forms, called <em>targets</em>. There can be
9945 any number of selections, but most X applications only handle one, the
9946 <em>primary selection</em>.
9948 In most cases, it isn't necessary for a GTK application to deal with
9949 selections itself. The standard widgets, such as the Entry widget,
9950 already have the capability to claim the selection when appropriate
9951 (e.g., when the user drags over text), and to retrieve the contents of
9952 the selection owned by another widget, or another application (e.g.,
9953 when the user clicks the second mouse button). However, there may be
9954 cases in which you want to give other widgets the ability to supply
9955 the selection, or you wish to retrieve targets not supported by
9958 A fundamental concept needed to understand selection handling is that
9959 of the <em>atom</em>. An atom is an integer that uniquely identifies a
9960 string (on a certain display). Certain atoms are predefined by the X
9961 server, and in some cases there are constants in <tt>gtk.h</tt>
9962 corresponding to these atoms. For instance the constant
9963 <tt>GDK_PRIMARY_SELECTION</tt> corresponds to the string "PRIMARY".
9964 In other cases, you should use the functions
9965 <tt>gdk_atom_intern()</tt>, to get the atom corresponding to a string,
9966 and <tt>gdk_atom_name()</tt>, to get the name of an atom. Both
9967 selections and targets are identified by atoms.
9969 <!-- ----------------------------------------------------------------- -->
9970 <sect1> Retrieving the selection
9972 Retrieving the selection is an asynchronous process. To start the
9976 gint gtk_selection_convert( GtkWidget *widget,
9982 This <em>converts</em> the selection into the form specified by
9983 <tt/target/. If at all possible, the time field should be the time
9984 from the event that triggered the selection. This helps make sure that
9985 events occur in the order that the user requested them. However, if it
9986 is not available (for instance, if the conversion was triggered by
9987 a "clicked" signal), then you can use the constant
9988 <tt>GDK_CURRENT_TIME</tt>.
9990 When the selection owner responds to the request, a
9991 "selection_received" signal is sent to your application. The handler
9992 for this signal receives a pointer to a <tt>GtkSelectionData</tt>
9993 structure, which is defined as:
9996 struct _GtkSelectionData
10007 <tt>selection</tt> and <tt>target</tt> are the values you gave in your
10008 <tt>gtk_selection_convert()</tt> call. <tt>type</tt> is an atom that
10009 identifies the type of data returned by the selection owner. Some
10010 possible values are "STRING", a string of latin-1 characters, "ATOM",
10011 a series of atoms, "INTEGER", an integer, etc. Most targets can only
10012 return one type. <tt/format/ gives the length of the units (for
10013 instance characters) in bits. Usually, you don't care about this when
10014 receiving data. <tt>data</tt> is a pointer to the returned data, and
10015 <tt>length</tt> gives the length of the returned data, in bytes. If
10016 <tt>length</tt> is negative, then an error occurred and the selection
10017 could not be retrieved. This might happen if no application owned the
10018 selection, or if you requested a target that the application didn't
10019 support. The buffer is actually guaranteed to be one byte longer than
10020 <tt>length</tt>; the extra byte will always be zero, so it isn't
10021 necessary to make a copy of strings just to null terminate them.
10023 In the following example, we retrieve the special target "TARGETS",
10024 which is a list of all targets into which the selection can be
10028 /* example-start selection gettargets.c */
10030 #include <gtk/gtk.h>
10032 void selection_received (GtkWidget *widget,
10033 GtkSelectionData *selection_data,
10036 /* Signal handler invoked when user clicks on the "Get Targets" button */
10038 get_targets (GtkWidget *widget, gpointer data)
10040 static GdkAtom targets_atom = GDK_NONE;
10042 /* Get the atom corresponding to the string "TARGETS" */
10043 if (targets_atom == GDK_NONE)
10044 targets_atom = gdk_atom_intern ("TARGETS", FALSE);
10046 /* And request the "TARGETS" target for the primary selection */
10047 gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
10051 /* Signal handler called when the selections owner returns the data */
10053 selection_received (GtkWidget *widget, GtkSelectionData *selection_data,
10060 /* **** IMPORTANT **** Check to see if retrieval succeeded */
10061 if (selection_data->length < 0)
10063 g_print ("Selection retrieval failed\n");
10066 /* Make sure we got the data in the expected form */
10067 if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
10069 g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
10073 /* Print out the atoms we received */
10074 atoms = (GdkAtom *)selection_data->data;
10077 for (i=0; i<selection_data->length/sizeof(GdkAtom); i++)
10080 name = gdk_atom_name (atoms[i]);
10082 g_print ("%s\n",name);
10084 g_print ("(bad atom)\n");
10091 main (int argc, char *argv[])
10096 gtk_init (&argc, &argv);
10098 /* Create the toplevel window */
10100 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
10101 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
10102 gtk_container_border_width (GTK_CONTAINER (window), 10);
10104 gtk_signal_connect (GTK_OBJECT (window), "destroy",
10105 GTK_SIGNAL_FUNC (gtk_exit), NULL);
10107 /* Create a button the user can click to get targets */
10109 button = gtk_button_new_with_label ("Get Targets");
10110 gtk_container_add (GTK_CONTAINER (window), button);
10112 gtk_signal_connect (GTK_OBJECT(button), "clicked",
10113 GTK_SIGNAL_FUNC (get_targets), NULL);
10114 gtk_signal_connect (GTK_OBJECT(button), "selection_received",
10115 GTK_SIGNAL_FUNC (selection_received), NULL);
10117 gtk_widget_show (button);
10118 gtk_widget_show (window);
10127 <!-- ----------------------------------------------------------------- -->
10128 <sect1> Supplying the selection
10130 Supplying the selection is a bit more complicated. You must register
10131 handlers that will be called when your selection is requested. For
10132 each selection/target pair you will handle, you make a call to:
10135 void gtk_selection_add_handler( GtkWidget *widget,
10138 GtkSelectionFunction function,
10139 GtkRemoveFunction remove_func,
10143 <tt/widget/, <tt/selection/, and <tt/target/ identify the requests
10144 this handler will manage. <tt/remove_func/, if not
10145 NULL, will be called when the signal handler is removed. This is
10146 useful, for instance, for interpreted languages which need to
10147 keep track of a reference count for <tt/data/.
10149 The callback function has the signature:
10152 typedef void (*GtkSelectionFunction)( GtkWidget *widget,
10153 GtkSelectionData *selection_data,
10158 The GtkSelectionData is the same as above, but this time, we're
10159 responsible for filling in the fields <tt/type/, <tt/format/,
10160 <tt/data/, and <tt/length/. (The <tt/format/ field is actually
10161 important here - the X server uses it to figure out whether the data
10162 needs to be byte-swapped or not. Usually it will be 8 - <em/i.e./ a
10163 character - or 32 - <em/i.e./ a. integer.) This is done by calling the
10167 void gtk_selection_data_set( GtkSelectionData *selection_data,
10174 This function takes care of properly making a copy of the data so that
10175 you don't have to worry about keeping it around. (You should not fill
10176 in the fields of the GtkSelectionData structure by hand.)
10178 When prompted by the user, you claim ownership of the selection by
10182 gint gtk_selection_owner_set( GtkWidget *widget,
10187 If another application claims ownership of the selection, you will
10188 receive a "selection_clear_event".
10190 As an example of supplying the selection, the following program adds
10191 selection functionality to a toggle button. When the toggle button is
10192 depressed, the program claims the primary selection. The only target
10193 supported (aside from certain targets like "TARGETS" supplied by GTK
10194 itself), is the "STRING" target. When this target is requested, a
10195 string representation of the time is returned.
10198 /* example-start selection setselection.c */
10200 #include <gtk/gtk.h>
10203 /* Callback when the user toggles the selection */
10205 selection_toggled (GtkWidget *widget, gint *have_selection)
10207 if (GTK_TOGGLE_BUTTON(widget)->active)
10209 *have_selection = gtk_selection_owner_set (widget,
10210 GDK_SELECTION_PRIMARY,
10212 /* if claiming the selection failed, we return the button to
10214 if (!*have_selection)
10215 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
10219 if (*have_selection)
10221 /* Before clearing the selection by setting the owner to NULL,
10222 we check if we are the actual owner */
10223 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
10224 gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
10226 *have_selection = FALSE;
10231 /* Called when another application claims the selection */
10233 selection_clear (GtkWidget *widget, GdkEventSelection *event,
10234 gint *have_selection)
10236 *have_selection = FALSE;
10237 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
10242 /* Supplies the current time as the selection. */
10244 selection_handle (GtkWidget *widget,
10245 GtkSelectionData *selection_data,
10249 time_t current_time;
10251 current_time = time (NULL);
10252 timestr = asctime (localtime(&current_time));
10253 /* When we return a single string, it should not be null terminated.
10254 That will be done for us */
10256 gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
10257 8, timestr, strlen(timestr));
10261 main (int argc, char *argv[])
10265 GtkWidget *selection_button;
10267 static int have_selection = FALSE;
10269 gtk_init (&argc, &argv);
10271 /* Create the toplevel window */
10273 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
10274 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
10275 gtk_container_border_width (GTK_CONTAINER (window), 10);
10277 gtk_signal_connect (GTK_OBJECT (window), "destroy",
10278 GTK_SIGNAL_FUNC (gtk_exit), NULL);
10280 /* Create a toggle button to act as the selection */
10282 selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
10283 gtk_container_add (GTK_CONTAINER (window), selection_button);
10284 gtk_widget_show (selection_button);
10286 gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
10287 GTK_SIGNAL_FUNC (selection_toggled), &have_selection);
10288 gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
10289 GTK_SIGNAL_FUNC (selection_clear), &have_selection);
10291 gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
10292 GDK_SELECTION_TYPE_STRING,
10293 selection_handle, NULL);
10295 gtk_widget_show (selection_button);
10296 gtk_widget_show (window);
10306 <!-- ***************************************************************** -->
10307 <sect>glib<label id="sec_glib">
10308 <!-- ***************************************************************** -->
10310 glib provides many useful functions and definitions available for use
10311 when creating GDK and GTK applications. I will list them all here with
10312 a brief explanation. Many are duplicates of standard libc functions so
10313 I won't go into detail on those. This is mostly to be used as a reference,
10314 so you know what is available for use.
10316 <!-- ----------------------------------------------------------------- -->
10319 Definitions for the extremes of many of the standard types are:
10334 Also, the following typedefs. The ones left unspecified are dynamically set
10335 depending on the architecture. Remember to avoid counting on the size of a
10336 pointer if you want to be portable! E.g., a pointer on an Alpha is 8 bytes, but 4
10346 unsigned char guchar;
10347 unsigned short gushort;
10348 unsigned long gulong;
10349 unsigned int guint;
10353 long double gldouble;
10365 <!-- ----------------------------------------------------------------- -->
10366 <sect1>Doubly Linked Lists
10368 The following functions are used to create, manage, and destroy doubly
10369 linked lists. I assume you know what linked lists are, as it is beyond the scope
10370 of this document to explain them. Of course, it's not required that you
10371 know these for general use of GTK, but they are nice to know.
10374 GList *g_list_alloc( void );
10376 void g_list_free( GList *list );
10378 void g_list_free_1( GList *list );
10380 GList *g_list_append( GList *list,
10383 GList *g_list_prepend( GList *list,
10386 GList *g_list_insert( GList *list,
10390 GList *g_list_remove( GList *list,
10393 GList *g_list_remove_link( GList *list,
10396 GList *g_list_reverse( GList *list );
10398 GList *g_list_nth( GList *list,
10401 GList *g_list_find( GList *list,
10404 GList *g_list_last( GList *list );
10406 GList *g_list_first( GList *list );
10408 gint g_list_length( GList *list );
10410 void g_list_foreach( GList *list,
10412 gpointer user_data );
10415 <!-- ----------------------------------------------------------------- -->
10416 <sect1>Singly Linked Lists
10418 Many of the above functions for singly linked lists are identical to the
10419 above. Here is a complete list:
10421 GSList *g_slist_alloc( void );
10423 void g_slist_free( GSList *list );
10425 void g_slist_free_1( GSList *list );
10427 GSList *g_slist_append( GSList *list,
10430 GSList *g_slist_prepend( GSList *list,
10433 GSList *g_slist_insert( GSList *list,
10437 GSList *g_slist_remove( GSList *list,
10440 GSList *g_slist_remove_link( GSList *list,
10443 GSList *g_slist_reverse( GSList *list );
10445 GSList *g_slist_nth( GSList *list,
10448 GSList *g_slist_find( GSList *list,
10451 GSList *g_slist_last( GSList *list );
10453 gint g_slist_length( GSList *list );
10455 void g_slist_foreach( GSList *list,
10457 gpointer user_data );
10461 <!-- ----------------------------------------------------------------- -->
10462 <sect1>Memory Management
10465 gpointer g_malloc( gulong size );
10468 This is a replacement for malloc(). You do not need to check the return
10469 value as it is done for you in this function.
10472 gpointer g_malloc0( gulong size );
10475 Same as above, but zeroes the memory before returning a pointer to it.
10478 gpointer g_realloc( gpointer mem,
10482 Relocates "size" bytes of memory starting at "mem". Obviously, the
10483 memory should have been previously allocated.
10486 void g_free( gpointer mem );
10489 Frees memory. Easy one.
10492 void g_mem_profile( void );
10495 Dumps a profile of used memory, but requires that you add #define
10496 MEM_PROFILE to the top of glib/gmem.c and re-make and make install.
10499 void g_mem_check( gpointer mem );
10502 Checks that a memory location is valid. Requires you add #define
10503 MEM_CHECK to the top of gmem.c and re-make and make install.
10505 <!-- ----------------------------------------------------------------- -->
10511 GTimer *g_timer_new( void );
10513 void g_timer_destroy( GTimer *timer );
10515 void g_timer_start( GTimer *timer );
10517 void g_timer_stop( GTimer *timer );
10519 void g_timer_reset( GTimer *timer );
10521 gdouble g_timer_elapsed( GTimer *timer,
10522 gulong *microseconds );
10525 <!-- ----------------------------------------------------------------- -->
10526 <sect1>String Handling
10528 A whole mess of string handling functions. They all look very interesting, and
10529 probably better for many purposes than the standard C string functions, but
10530 require documentation.
10533 GString *g_string_new( gchar *init );
10535 void g_string_free( GString *string,
10536 gint free_segment );
10538 GString *g_string_assign( GString *lval,
10541 GString *g_string_truncate( GString *string,
10544 GString *g_string_append( GString *string,
10547 GString *g_string_append_c( GString *string,
10550 GString *g_string_prepend( GString *string,
10553 GString *g_string_prepend_c( GString *string,
10556 void g_string_sprintf( GString *string,
10560 void g_string_sprintfa ( GString *string,
10565 <!-- ----------------------------------------------------------------- -->
10566 <sect1>Utility and Error Functions
10569 gchar *g_strdup( const gchar *str );
10572 Replacement strdup function. Copies the original strings contents to
10573 newly allocated memory, and returns a pointer to it.
10576 gchar *g_strerror( gint errnum );
10579 I recommend using this for all error messages. It's much nicer, and more
10580 portable than perror() or others. The output is usually of the form:
10583 program name:function that failed:file or further description:strerror
10586 Here's an example of one such call used in our hello_world program:
10589 g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
10593 void g_error( gchar *format, ... );
10596 Prints an error message. The format is just like printf, but it
10597 prepends "** ERROR **: " to your message, and exits the program.
10598 Use only for fatal errors.
10601 void g_warning( gchar *format, ... );
10604 Same as above, but prepends "** WARNING **: ", and does not exit the
10608 void g_message( gchar *format, ... );
10611 Prints "message: " prepended to the string you pass in.
10614 void g_print( gchar *format, ... );
10617 Replacement for printf().
10619 And our last function:
10622 gchar *g_strsignal( gint signum );
10625 Prints out the name of the Unix system signal given the signal number.
10626 Useful in generic signal handling functions.
10628 All of the above are more or less just stolen from glib.h. If anyone cares
10629 to document any function, just send me an email!
10631 <!-- ***************************************************************** -->
10632 <sect>GTK's rc Files
10633 <!-- ***************************************************************** -->
10635 GTK has its own way of dealing with application defaults, by using rc
10636 files. These can be used to set the colors of just about any widget, and
10637 can also be used to tile pixmaps onto the background of some widgets.
10639 <!-- ----------------------------------------------------------------- -->
10640 <sect1>Functions For rc Files
10642 When your application starts, you should include a call to:
10645 void gtk_rc_parse( char *filename );
10648 Passing in the filename of your rc file. This will cause GTK to parse this
10649 file, and use the style settings for the widget types defined there.
10651 If you wish to have a special set of widgets that can take on a different
10652 style from others, or any other logical division of widgets, use a call to:
10655 void gtk_widget_set_name( GtkWidget *widget,
10659 Passing your newly created widget as the first argument, and the name
10660 you wish to give it as the second. This will allow you to change the
10661 attributes of this widget by name through the rc file.
10663 If we use a call something like this:
10666 button = gtk_button_new_with_label ("Special Button");
10667 gtk_widget_set_name (button, "special button");
10670 Then this button is given the name "special button" and may be addressed by
10671 name in the rc file as "special button.GtkButton". [<--- Verify ME!]
10673 The example rc file below, sets the properties of the main window, and lets
10674 all children of that main window inherit the style described by the "main
10675 button" style. The code used in the application is:
10678 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
10679 gtk_widget_set_name (window, "main window");
10682 And then the style is defined in the rc file using:
10685 widget "main window.*GtkButton*" style "main_button"
10688 Which sets all the GtkButton widgets in the "main window" to the
10689 "main_buttons" style as defined in the rc file.
10691 As you can see, this is a fairly powerful and flexible system. Use your
10692 imagination as to how best to take advantage of this.
10694 <!-- ----------------------------------------------------------------- -->
10695 <sect1>GTK's rc File Format
10697 The format of the GTK file is illustrated in the example below. This is
10698 the testgtkrc file from the GTK distribution, but I've added a
10699 few comments and things. You may wish to include this explanation
10700 your application to allow the user to fine tune his application.
10702 There are several directives to change the attributes of a widget.
10705 <item>fg - Sets the foreground color of a widget.
10706 <item>bg - Sets the background color of a widget.
10707 <item>bg_pixmap - Sets the background of a widget to a tiled pixmap.
10708 <item>font - Sets the font to be used with the given widget.
10711 In addition to this, there are several states a widget can be in, and you
10712 can set different colors, pixmaps and fonts for each state. These states are:
10715 <item>NORMAL - The normal state of a widget, without the mouse over top of
10716 it, and not being pressed etc.
10717 <item>PRELIGHT - When the mouse is over top of the widget, colors defined
10718 using this state will be in effect.
10719 <item>ACTIVE - When the widget is pressed or clicked it will be active, and
10720 the attributes assigned by this tag will be in effect.
10721 <item>INSENSITIVE - When a widget is set insensitive, and cannot be
10722 activated, it will take these attributes.
10723 <item>SELECTED - When an object is selected, it takes these attributes.
10726 When using the "fg" and "bg" keywords to set the colors of widgets, the
10730 fg[<STATE>] = { Red, Green, Blue }
10733 Where STATE is one of the above states (PRELIGHT, ACTIVE etc), and the Red,
10734 Green and Blue are values in the range of 0 - 1.0, { 1.0, 1.0, 1.0 } being
10735 white. They must be in float form, or they will register as 0, so a straight
10736 "1" will not work, it must be "1.0". A straight "0" is fine because it
10737 doesn't matter if it's not recognized. Unrecognized values are set to 0.
10739 bg_pixmap is very similar to the above, except the colors are replaced by a
10742 pixmap_path is a list of paths separated by ":"'s. These paths will be
10743 searched for any pixmap you specify.
10745 The font directive is simply:
10747 font = "<font name>"
10750 Where the only hard part is figuring out the font string. Using xfontsel or
10751 similar utility should help.
10753 The "widget_class" sets the style of a class of widgets. These classes are
10754 listed in the widget overview on the class hierarchy.
10756 The "widget" directive sets a specifically named set of widgets to a
10757 given style, overriding any style set for the given widget class.
10758 These widgets are registered inside the application using the
10759 gtk_widget_set_name() call. This allows you to specify the attributes of a
10760 widget on a per widget basis, rather than setting the attributes of an
10761 entire widget class. I urge you to document any of these special widgets so
10762 users may customize them.
10764 When the keyword <tt>parent</> is used as an attribute, the widget will take on
10765 the attributes of its parent in the application.
10767 When defining a style, you may assign the attributes of a previously defined
10768 style to this new one.
10771 style "main_button" = "button"
10773 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
10774 bg[PRELIGHT] = { 0.75, 0, 0 }
10778 This example takes the "button" style, and creates a new "main_button" style
10779 simply by changing the font and prelight background color of the "button"
10782 Of course, many of these attributes don't apply to all widgets. It's a
10783 simple matter of common sense really. Anything that could apply, should.
10785 <!-- ----------------------------------------------------------------- -->
10786 <sect1>Example rc file
10790 # pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
10792 pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
10794 # style <name> [= <name>]
10799 # widget <widget_set> style <style_name>
10800 # widget_class <widget_class_set> style <style_name>
10803 # Here is a list of all the possible states. Note that some do not apply to
10806 # NORMAL - The normal state of a widget, without the mouse over top of
10807 # it, and not being pressed etc.
10809 # PRELIGHT - When the mouse is over top of the widget, colors defined
10810 # using this state will be in effect.
10812 # ACTIVE - When the widget is pressed or clicked it will be active, and
10813 # the attributes assigned by this tag will be in effect.
10815 # INSENSITIVE - When a widget is set insensitive, and cannot be
10816 # activated, it will take these attributes.
10818 # SELECTED - When an object is selected, it takes these attributes.
10820 # Given these states, we can set the attributes of the widgets in each of
10821 # these states using the following directives.
10823 # fg - Sets the foreground color of a widget.
10824 # fg - Sets the background color of a widget.
10825 # bg_pixmap - Sets the background of a widget to a tiled pixmap.
10826 # font - Sets the font to be used with the given widget.
10829 # This sets a style called "button". The name is not really important, as
10830 # it is assigned to the actual widgets at the bottom of the file.
10834 #This sets the padding around the window to the pixmap specified.
10835 #bg_pixmap[<STATE>] = "<pixmap filename>"
10836 bg_pixmap[NORMAL] = "warning.xpm"
10841 #Sets the foreground color (font color) to red when in the "NORMAL"
10844 fg[NORMAL] = { 1.0, 0, 0 }
10846 #Sets the background pixmap of this widget to that of its parent.
10847 bg_pixmap[NORMAL] = "<parent>"
10852 # This shows all the possible states for a button. The only one that
10853 # doesn't apply is the SELECTED state.
10855 fg[PRELIGHT] = { 0, 1.0, 1.0 }
10856 bg[PRELIGHT] = { 0, 0, 1.0 }
10857 bg[ACTIVE] = { 1.0, 0, 0 }
10858 fg[ACTIVE] = { 0, 1.0, 0 }
10859 bg[NORMAL] = { 1.0, 1.0, 0 }
10860 fg[NORMAL] = { .99, 0, .99 }
10861 bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
10862 fg[INSENSITIVE] = { 1.0, 0, 1.0 }
10865 # In this example, we inherit the attributes of the "button" style and then
10866 # override the font and background color when prelit to create a new
10867 # "main_button" style.
10869 style "main_button" = "button"
10871 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
10872 bg[PRELIGHT] = { 0.75, 0, 0 }
10875 style "toggle_button" = "button"
10877 fg[NORMAL] = { 1.0, 0, 0 }
10878 fg[ACTIVE] = { 1.0, 0, 0 }
10880 # This sets the background pixmap of the toggle_button to that of its
10881 # parent widget (as defined in the application).
10882 bg_pixmap[NORMAL] = "<parent>"
10887 bg_pixmap[NORMAL] = "marble.xpm"
10888 fg[NORMAL] = { 1.0, 1.0, 1.0 }
10893 font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
10896 # pixmap_path "~/.pixmaps"
10898 # These set the widget types to use the styles defined above.
10899 # The widget types are listed in the class hierarchy, but could probably be
10900 # just listed in this document for the users reference.
10902 widget_class "GtkWindow" style "window"
10903 widget_class "GtkDialog" style "window"
10904 widget_class "GtkFileSelection" style "window"
10905 widget_class "*Gtk*Scale" style "scale"
10906 widget_class "*GtkCheckButton*" style "toggle_button"
10907 widget_class "*GtkRadioButton*" style "toggle_button"
10908 widget_class "*GtkButton*" style "button"
10909 widget_class "*Ruler" style "ruler"
10910 widget_class "*GtkText" style "text"
10912 # This sets all the buttons that are children of the "main window" to
10913 # the main_button style. These must be documented to be taken advantage of.
10914 widget "main window.*GtkButton*" style "main_button"
10917 <!-- ***************************************************************** -->
10918 <sect>Writing Your Own Widgets
10919 <!-- ***************************************************************** -->
10921 <!-- ----------------------------------------------------------------- -->
10924 Although the GTK distribution comes with many types of widgets that
10925 should cover most basic needs, there may come a time when you need to
10926 create your own new widget type. Since GTK uses widget inheritance
10927 extensively, and there is already a widget that is close to what you want,
10928 it is often possible to make a useful new widget type in
10929 just a few lines of code. But before starting work on a new widget, check
10930 around first to make sure that someone has not already written
10931 it. This will prevent duplication of effort and keep the number of
10932 GTK widgets out there to a minimum, which will help keep both the code
10933 and the interface of different applications consistent. As a flip side
10934 to this, once you finish your widget, announce it to the world so
10935 other people can benefit. The best place to do this is probably the
10938 Complete sources for the example widgets are available at the place you
10939 got this tutorial, or from:
10941 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
10942 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
10945 <!-- ----------------------------------------------------------------- -->
10946 <sect1> The Anatomy Of A Widget
10948 In order to create a new widget, it is important to have an
10949 understanding of how GTK objects work. This section is just meant as a
10950 brief overview. See the reference documentation for the details.
10952 GTK widgets are implemented in an object oriented fashion. However,
10953 they are implemented in standard C. This greatly improves portability
10954 and stability over using current generation C++ compilers; however,
10955 it does mean that the widget writer has to pay attention to some of
10956 the implementation details. The information common to all instances of
10957 one class of widgets (e.g., to all Button widgets) is stored in the
10958 <em>class structure</em>. There is only one copy of this in
10959 which is stored information about the class's signals
10960 (which act like virtual functions in C). To support inheritance, the
10961 first field in the class structure must be a copy of the parent's
10962 class structure. The declaration of the class structure of GtkButtton
10966 struct _GtkButtonClass
10968 GtkContainerClass parent_class;
10970 void (* pressed) (GtkButton *button);
10971 void (* released) (GtkButton *button);
10972 void (* clicked) (GtkButton *button);
10973 void (* enter) (GtkButton *button);
10974 void (* leave) (GtkButton *button);
10978 When a button is treated as a container (for instance, when it is
10979 resized), its class structure can be cast to GtkContainerClass, and
10980 the relevant fields used to handle the signals.
10982 There is also a structure for each widget that is created on a
10983 per-instance basis. This structure has fields to store information that
10984 is different for each instance of the widget. We'll call this
10985 structure the <em>object structure</em>. For the Button class, it looks
10991 GtkContainer container;
10995 guint in_button : 1;
10996 guint button_down : 1;
11000 Note that, similar to the class structure, the first field is the
11001 object structure of the parent class, so that this structure can be
11002 cast to the parent class's object structure as needed.
11004 <!-- ----------------------------------------------------------------- -->
11005 <sect1> Creating a Composite widget
11007 <!-- ----------------------------------------------------------------- -->
11008 <sect2> Introduction
11010 One type of widget that you may be interested in creating is a
11011 widget that is merely an aggregate of other GTK widgets. This type of
11012 widget does nothing that couldn't be done without creating new
11013 widgets, but provides a convenient way of packaging user interface
11014 elements for reuse. The FileSelection and ColorSelection widgets in
11015 the standard distribution are examples of this type of widget.
11017 The example widget that we'll create in this section is the Tictactoe
11018 widget, a 3x3 array of toggle buttons which triggers a signal when all
11019 three buttons in a row, column, or on one of the diagonals are
11022 <!-- ----------------------------------------------------------------- -->
11023 <sect2> Choosing a parent class
11025 The parent class for a composite widget is typically the container
11026 class that holds all of the elements of the composite widget. For
11027 example, the parent class of the FileSelection widget is the
11028 Dialog class. Since our buttons will be arranged in a table, it
11029 might seem natural to make our parent class the GtkTable
11030 class. Unfortunately, this turns out not to work. The creation of a
11031 widget is divided among two functions - a <tt/WIDGETNAME_new()/
11032 function that the user calls, and a <tt/WIDGETNAME_init()/ function
11033 which does the basic work of initializing the widget which is
11034 independent of the arguments passed to the <tt/_new()/
11035 function. Descendent widgets only call the <tt/_init/ function of
11036 their parent widget. But this division of labor doesn't work well for
11037 tables, which when created, need to know the number of rows and
11038 columns in the table. Unless we want to duplicate most of the
11039 functionality of <tt/gtk_table_new()/ in our Tictactoe widget, we had
11040 best avoid deriving it from GtkTable. For that reason, we derive it
11041 from GtkVBox instead, and stick our table inside the VBox.
11043 <!-- ----------------------------------------------------------------- -->
11044 <sect2> The header file
11046 Each widget class has a header file which declares the object and
11047 class structures for that widget, along with public functions.
11048 A couple of features are worth pointing out. To prevent duplicate
11049 definitions, we wrap the entire header file in:
11052 #ifndef __TICTACTOE_H__
11053 #define __TICTACTOE_H__
11057 #endif /* __TICTACTOE_H__ */
11060 And to keep C++ programs that include the header file happy, in:
11065 #endif /* __cplusplus */
11071 #endif /* __cplusplus */
11074 Along with the functions and structures, we declare three standard
11075 macros in our header file, <tt/TICTACTOE(obj)/,
11076 <tt/TICTACTOE_CLASS(klass)/, and <tt/IS_TICTACTOE(obj)/, which cast a
11077 pointer into a pointer to the object or class structure, and check
11078 if an object is a Tictactoe widget respectively.
11080 Here is the complete header file:
11085 #ifndef __TICTACTOE_H__
11086 #define __TICTACTOE_H__
11088 #include <gdk/gdk.h>
11089 #include <gtk/gtkvbox.h>
11093 #endif /* __cplusplus */
11095 #define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
11096 #define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
11097 #define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
11100 typedef struct _Tictactoe Tictactoe;
11101 typedef struct _TictactoeClass TictactoeClass;
11107 GtkWidget *buttons[3][3];
11110 struct _TictactoeClass
11112 GtkVBoxClass parent_class;
11114 void (* tictactoe) (Tictactoe *ttt);
11117 guint tictactoe_get_type (void);
11118 GtkWidget* tictactoe_new (void);
11119 void tictactoe_clear (Tictactoe *ttt);
11123 #endif /* __cplusplus */
11125 #endif /* __TICTACTOE_H__ */
11129 <!-- ----------------------------------------------------------------- -->
11130 <sect2> The <tt/_get_type()/ function.
11132 We now continue on to the implementation of our widget. A core
11133 function for every widget is the function
11134 <tt/WIDGETNAME_get_type()/. This function, when first called, tells
11135 GTK about the widget class, and gets an ID that uniquely identifies
11136 the widget class. Upon subsequent calls, it just returns the ID.
11140 tictactoe_get_type ()
11142 static guint ttt_type = 0;
11146 GtkTypeInfo ttt_info =
11149 sizeof (Tictactoe),
11150 sizeof (TictactoeClass),
11151 (GtkClassInitFunc) tictactoe_class_init,
11152 (GtkObjectInitFunc) tictactoe_init,
11153 (GtkArgSetFunc) NULL,
11154 (GtkArgGetFunc) NULL
11157 ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
11164 The GtkTypeInfo structure has the following definition:
11167 struct _GtkTypeInfo
11172 GtkClassInitFunc class_init_func;
11173 GtkObjectInitFunc object_init_func;
11174 GtkArgSetFunc arg_set_func;
11175 GtkArgGetFunc arg_get_func;
11179 The fields of this structure are pretty self-explanatory. We'll ignore
11180 the <tt/arg_set_func/ and <tt/arg_get_func/ fields here: they have an important,
11182 unimplemented, role in allowing widget options to be conveniently set
11183 from interpreted languages. Once GTK has a correctly filled in copy of
11184 this structure, it knows how to create objects of a particular widget
11187 <!-- ----------------------------------------------------------------- -->
11188 <sect2> The <tt/_class_init()/ function
11190 The <tt/WIDGETNAME_class_init()/ function initializes the fields of
11191 the widget's class structure, and sets up any signals for the
11192 class. For our Tictactoe widget it looks like:
11201 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
11204 tictactoe_class_init (TictactoeClass *class)
11206 GtkObjectClass *object_class;
11208 object_class = (GtkObjectClass*) class;
11210 tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
11212 object_class->type,
11213 GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
11214 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
11217 gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
11219 class->tictactoe = NULL;
11223 Our widget has just one signal, the <tt/tictactoe/ signal that is
11224 invoked when a row, column, or diagonal is completely filled in. Not
11225 every composite widget needs signals, so if you are reading this for
11226 the first time, you may want to skip to the next section now, as
11227 things are going to get a bit complicated.
11232 gint gtk_signal_new( const gchar *name,
11233 GtkSignalRunType run_type,
11234 GtkType object_type,
11235 gint function_offset,
11236 GtkSignalMarshaller marshaller,
11237 GtkType return_val,
11242 Creates a new signal. The parameters are:
11245 <item> <tt/name/: The name of the signal.
11246 <item> <tt/run_type/: Whether the default handler runs before or after
11247 user handlers. Usually this will be <tt/GTK_RUN_FIRST/, or <tt/GTK_RUN_LAST/,
11248 although there are other possibilities.
11249 <item> <tt/object_type/: The ID of the object that this signal applies
11250 to. (It will also apply to that objects descendents)
11251 <item> <tt/function_offset/: The offset within the class structure of
11252 a pointer to the default handler.
11253 <item> <tt/marshaller/: A function that is used to invoke the signal
11254 handler. For signal handlers that have no arguments other than the
11255 object that emitted the signal and user data, we can use the
11256 pre-supplied marshaller function <tt/gtk_signal_default_marshaller/.
11257 <item> <tt/return_val/: The type of the return val.
11258 <item> <tt/nparams/: The number of parameters of the signal handler
11259 (other than the two default ones mentioned above)
11260 <item> <tt/.../: The types of the parameters.
11263 When specifying types, the <tt/GtkType/ enumeration is used:
11288 /* it'd be great if the next two could be removed eventually */
11290 GTK_TYPE_C_CALLBACK,
11294 } GtkFundamentalType;
11297 <tt/gtk_signal_new()/ returns a unique integer identifier for the
11298 signal, that we store in the <tt/tictactoe_signals/ array, which we
11299 index using an enumeration. (Conventionally, the enumeration elements
11300 are the signal name, uppercased, but here there would be a conflict
11301 with the <tt/TICTACTOE()/ macro, so we called it <tt/TICTACTOE_SIGNAL/
11304 After creating our signals, we need to tell GTK to associate our
11305 signals with the Tictactoe class. We do that by calling
11306 <tt/gtk_object_class_add_signals()/. We then set the pointer which
11307 points to the default handler for the `tictactoe' signal to NULL,
11308 indicating that there is no default action.
11310 <!-- ----------------------------------------------------------------- -->
11311 <sect2> The <tt/_init()/ function.
11313 Each widget class also needs a function to initialize the object
11314 structure. Usually, this function has the fairly limited role of
11315 setting the fields of the structure to default values. For composite
11316 widgets, however, this function also creates the component widgets.
11320 tictactoe_init (Tictactoe *ttt)
11325 table = gtk_table_new (3, 3, TRUE);
11326 gtk_container_add (GTK_CONTAINER(ttt), table);
11327 gtk_widget_show (table);
11332 ttt->buttons[i][j] = gtk_toggle_button_new ();
11333 gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
11335 gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
11336 GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
11337 gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
11338 gtk_widget_show (ttt->buttons[i][j]);
11343 <!-- ----------------------------------------------------------------- -->
11344 <sect2> And the rest...
11346 There is one more function that every widget (except for base widget
11347 types like GtkBin that cannot be instantiated) needs to have - the
11348 function that the user calls to create an object of that type. This is
11349 conventionally called <tt/WIDGETNAME_new()/. In some
11350 widgets, though not for the Tictactoe widgets, this function takes
11351 arguments, and does some setup based on the arguments. The other two
11352 functions are specific to the Tictactoe widget.
11354 <tt/tictactoe_clear()/ is a public function that resets all the
11355 buttons in the widget to the up position. Note the use of
11356 <tt/gtk_signal_handler_block_by_data()/ to keep our signal handler for
11357 button toggles from being triggered unnecessarily.
11359 <tt/tictactoe_toggle()/ is the signal handler that is invoked when the
11360 user clicks on a button. It checks to see if there are any winning
11361 combinations that involve the toggled button, and if so, emits
11362 the "tictactoe" signal.
11368 return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
11372 tictactoe_clear (Tictactoe *ttt)
11379 gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
11380 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
11382 gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
11387 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
11391 static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
11392 { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
11393 { 0, 1, 2 }, { 0, 1, 2 } };
11394 static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
11395 { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
11396 { 0, 1, 2 }, { 2, 1, 0 } };
11398 int success, found;
11400 for (k=0; k<8; k++)
11407 success = success &&
11408 GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
11410 ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
11413 if (success && found)
11415 gtk_signal_emit (GTK_OBJECT (ttt),
11416 tictactoe_signals[TICTACTOE_SIGNAL]);
11423 And finally, an example program using our Tictactoe widget:
11426 #include <gtk/gtk.h>
11427 #include "tictactoe.h"
11429 /* Invoked when a row, column or diagonal is completed */
11431 win (GtkWidget *widget, gpointer data)
11433 g_print ("Yay!\n");
11434 tictactoe_clear (TICTACTOE (widget));
11438 main (int argc, char *argv[])
11443 gtk_init (&argc, &argv);
11445 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11447 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
11449 gtk_signal_connect (GTK_OBJECT (window), "destroy",
11450 GTK_SIGNAL_FUNC (gtk_exit), NULL);
11452 gtk_container_border_width (GTK_CONTAINER (window), 10);
11454 /* Create a new Tictactoe widget */
11455 ttt = tictactoe_new ();
11456 gtk_container_add (GTK_CONTAINER (window), ttt);
11457 gtk_widget_show (ttt);
11459 /* And attach to its "tictactoe" signal */
11460 gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
11461 GTK_SIGNAL_FUNC (win), NULL);
11463 gtk_widget_show (window);
11472 <!-- ----------------------------------------------------------------- -->
11473 <sect1> Creating a widget from scratch.
11475 <!-- ----------------------------------------------------------------- -->
11476 <sect2> Introduction
11478 In this section, we'll learn more about how widgets display themselves
11479 on the screen and interact with events. As an example of this, we'll
11480 create an analog dial widget with a pointer that the user can drag to
11483 <!-- ----------------------------------------------------------------- -->
11484 <sect2> Displaying a widget on the screen
11486 There are several steps that are involved in displaying on the screen.
11487 After the widget is created with a call to <tt/WIDGETNAME_new()/,
11488 several more functions are needed:
11491 <item> <tt/WIDGETNAME_realize()/ is responsible for creating an X
11492 window for the widget if it has one.
11493 <item> <tt/WIDGETNAME_map()/ is invoked after the user calls
11494 <tt/gtk_widget_show()/. It is responsible for making sure the widget
11495 is actually drawn on the screen (<em/mapped/). For a container class,
11496 it must also make calls to <tt/map()/> functions of any child widgets.
11497 <item> <tt/WIDGETNAME_draw()/ is invoked when <tt/gtk_widget_draw()/
11498 is called for the widget or one of its ancestors. It makes the actual
11499 calls to the drawing functions to draw the widget on the screen. For
11500 container widgets, this function must make calls to
11501 <tt/gtk_widget_draw()/ for its child widgets.
11502 <item> <tt/WIDGETNAME_expose()/ is a handler for expose events for the
11503 widget. It makes the necessary calls to the drawing functions to draw
11504 the exposed portion on the screen. For container widgets, this
11505 function must generate expose events for its child widgets which don't
11506 have their own windows. (If they have their own windows, then X will
11507 generate the necessary expose events)
11510 You might notice that the last two functions are quite similar - each
11511 is responsible for drawing the widget on the screen. In fact many
11512 types of widgets don't really care about the difference between the
11513 two. The default <tt/draw()/ function in the widget class simply
11514 generates a synthetic expose event for the redrawn area. However, some
11515 types of widgets can save work by distinguishing between the two
11516 functions. For instance, if a widget has multiple X windows, then
11517 since expose events identify the exposed window, it can redraw only
11518 the affected window, which is not possible for calls to <tt/draw()/.
11520 Container widgets, even if they don't care about the difference for
11521 themselves, can't simply use the default <tt/draw()/ function because
11522 their child widgets might care about the difference. However,
11523 it would be wasteful to duplicate the drawing code between the two
11524 functions. The convention is that such widgets have a function called
11525 <tt/WIDGETNAME_paint()/ that does the actual work of drawing the
11526 widget, that is then called by the <tt/draw()/ and <tt/expose()/
11529 In our example approach, since the dial widget is not a container
11530 widget, and only has a single window, we can take the simplest
11531 approach and use the default <tt/draw()/ function and only implement
11532 an <tt/expose()/ function.
11534 <!-- ----------------------------------------------------------------- -->
11535 <sect2> The origins of the Dial Widget
11537 Just as all land animals are just variants on the first amphibian that
11538 crawled up out of the mud, Gtk widgets tend to start off as variants
11539 of some other, previously written widget. Thus, although this section
11540 is entitled `Creating a Widget from Scratch', the Dial widget really
11541 began with the source code for the Range widget. This was picked as a
11542 starting point because it would be nice if our Dial had the same
11543 interface as the Scale widgets which are just specialized descendents
11544 of the Range widget. So, though the source code is presented below in
11545 finished form, it should not be implied that it was written, <em>deus
11546 ex machina</em> in this fashion. Also, if you aren't yet familiar with
11547 how scale widgets work from the application writer's point of view, it
11548 would be a good idea to look them over before continuing.
11550 <!-- ----------------------------------------------------------------- -->
11553 Quite a bit of our widget should look pretty familiar from the
11554 Tictactoe widget. First, we have a header file:
11557 /* GTK - The GIMP Toolkit
11558 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
11560 * This library is free software; you can redistribute it and/or
11561 * modify it under the terms of the GNU Library General Public
11562 * License as published by the Free Software Foundation; either
11563 * version 2 of the License, or (at your option) any later version.
11565 * This library is distributed in the hope that it will be useful,
11566 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11567 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11568 * Library General Public License for more details.
11570 * You should have received a copy of the GNU Library General Public
11571 * License along with this library; if not, write to the Free
11572 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
11575 #ifndef __GTK_DIAL_H__
11576 #define __GTK_DIAL_H__
11578 #include <gdk/gdk.h>
11579 #include <gtk/gtkadjustment.h>
11580 #include <gtk/gtkwidget.h>
11585 #endif /* __cplusplus */
11588 #define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
11589 #define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
11590 #define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
11593 typedef struct _GtkDial GtkDial;
11594 typedef struct _GtkDialClass GtkDialClass;
11600 /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
11603 /* Button currently pressed or 0 if none */
11606 /* Dimensions of dial components */
11608 gint pointer_width;
11610 /* ID of update timer, or 0 if none */
11613 /* Current angle */
11616 /* Old values from adjustment stored so we know when something changes */
11621 /* The adjustment object that stores the data for this dial */
11622 GtkAdjustment *adjustment;
11625 struct _GtkDialClass
11627 GtkWidgetClass parent_class;
11631 GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
11632 guint gtk_dial_get_type (void);
11633 GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
11634 void gtk_dial_set_update_policy (GtkDial *dial,
11635 GtkUpdateType policy);
11637 void gtk_dial_set_adjustment (GtkDial *dial,
11638 GtkAdjustment *adjustment);
11641 #endif /* __cplusplus */
11644 #endif /* __GTK_DIAL_H__ */
11647 Since there is quite a bit more going on in this widget, than the last
11648 one, we have more fields in the data structure, but otherwise things
11649 are pretty similar.
11651 Next, after including header files, and declaring a few constants,
11652 we have some functions to provide information about the widget
11658 #include <gtk/gtkmain.h>
11659 #include <gtk/gtksignal.h>
11661 #include "gtkdial.h"
11663 #define SCROLL_DELAY_LENGTH 300
11664 #define DIAL_DEFAULT_SIZE 100
11666 /* Forward declarations */
11668 [ omitted to save space ]
11672 static GtkWidgetClass *parent_class = NULL;
11675 gtk_dial_get_type ()
11677 static guint dial_type = 0;
11681 GtkTypeInfo dial_info =
11685 sizeof (GtkDialClass),
11686 (GtkClassInitFunc) gtk_dial_class_init,
11687 (GtkObjectInitFunc) gtk_dial_init,
11688 (GtkArgSetFunc) NULL,
11689 (GtkArgGetFunc) NULL,
11692 dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info);
11699 gtk_dial_class_init (GtkDialClass *class)
11701 GtkObjectClass *object_class;
11702 GtkWidgetClass *widget_class;
11704 object_class = (GtkObjectClass*) class;
11705 widget_class = (GtkWidgetClass*) class;
11707 parent_class = gtk_type_class (gtk_widget_get_type ());
11709 object_class->destroy = gtk_dial_destroy;
11711 widget_class->realize = gtk_dial_realize;
11712 widget_class->expose_event = gtk_dial_expose;
11713 widget_class->size_request = gtk_dial_size_request;
11714 widget_class->size_allocate = gtk_dial_size_allocate;
11715 widget_class->button_press_event = gtk_dial_button_press;
11716 widget_class->button_release_event = gtk_dial_button_release;
11717 widget_class->motion_notify_event = gtk_dial_motion_notify;
11721 gtk_dial_init (GtkDial *dial)
11724 dial->policy = GTK_UPDATE_CONTINUOUS;
11727 dial->pointer_width = 0;
11729 dial->old_value = 0.0;
11730 dial->old_lower = 0.0;
11731 dial->old_upper = 0.0;
11732 dial->adjustment = NULL;
11736 gtk_dial_new (GtkAdjustment *adjustment)
11740 dial = gtk_type_new (gtk_dial_get_type ());
11743 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
11745 gtk_dial_set_adjustment (dial, adjustment);
11747 return GTK_WIDGET (dial);
11751 gtk_dial_destroy (GtkObject *object)
11755 g_return_if_fail (object != NULL);
11756 g_return_if_fail (GTK_IS_DIAL (object));
11758 dial = GTK_DIAL (object);
11760 if (dial->adjustment)
11761 gtk_object_unref (GTK_OBJECT (dial->adjustment));
11763 if (GTK_OBJECT_CLASS (parent_class)->destroy)
11764 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
11768 Note that this <tt/init()/ function does less than for the Tictactoe
11769 widget, since this is not a composite widget, and the <tt/new()/
11770 function does more, since it now has an argument. Also, note that when
11771 we store a pointer to the Adjustment object, we increment its
11772 reference count, (and correspondingly decrement when we no longer use
11773 it) so that GTK can keep track of when it can be safely destroyed.
11776 Also, there are a few function to manipulate the widget's options:
11780 gtk_dial_get_adjustment (GtkDial *dial)
11782 g_return_val_if_fail (dial != NULL, NULL);
11783 g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
11785 return dial->adjustment;
11789 gtk_dial_set_update_policy (GtkDial *dial,
11790 GtkUpdateType policy)
11792 g_return_if_fail (dial != NULL);
11793 g_return_if_fail (GTK_IS_DIAL (dial));
11795 dial->policy = policy;
11799 gtk_dial_set_adjustment (GtkDial *dial,
11800 GtkAdjustment *adjustment)
11802 g_return_if_fail (dial != NULL);
11803 g_return_if_fail (GTK_IS_DIAL (dial));
11805 if (dial->adjustment)
11807 gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
11808 gtk_object_unref (GTK_OBJECT (dial->adjustment));
11811 dial->adjustment = adjustment;
11812 gtk_object_ref (GTK_OBJECT (dial->adjustment));
11814 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
11815 (GtkSignalFunc) gtk_dial_adjustment_changed,
11817 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
11818 (GtkSignalFunc) gtk_dial_adjustment_value_changed,
11821 dial->old_value = adjustment->value;
11822 dial->old_lower = adjustment->lower;
11823 dial->old_upper = adjustment->upper;
11825 gtk_dial_update (dial);
11829 <sect2> <tt/gtk_dial_realize()/
11832 Now we come to some new types of functions. First, we have a function
11833 that does the work of creating the X window. Notice that a mask is
11834 passed to the function <tt/gdk_window_new()/ which specifies which fields of
11835 the GdkWindowAttr structure actually have data in them (the remaining
11836 fields will be given default values). Also worth noting is the way the
11837 event mask of the widget is created. We call
11838 <tt/gtk_widget_get_events()/ to retrieve the event mask that the user
11839 has specified for this widget (with <tt/gtk_widget_set_events()/, and
11840 add the events that we are interested in ourselves.
11843 After creating the window, we set its style and background, and put a
11844 pointer to the widget in the user data field of the GdkWindow. This
11845 last step allows GTK to dispatch events for this window to the correct
11850 gtk_dial_realize (GtkWidget *widget)
11853 GdkWindowAttr attributes;
11854 gint attributes_mask;
11856 g_return_if_fail (widget != NULL);
11857 g_return_if_fail (GTK_IS_DIAL (widget));
11859 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
11860 dial = GTK_DIAL (widget);
11862 attributes.x = widget->allocation.x;
11863 attributes.y = widget->allocation.y;
11864 attributes.width = widget->allocation.width;
11865 attributes.height = widget->allocation.height;
11866 attributes.wclass = GDK_INPUT_OUTPUT;
11867 attributes.window_type = GDK_WINDOW_CHILD;
11868 attributes.event_mask = gtk_widget_get_events (widget) |
11869 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
11870 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
11871 GDK_POINTER_MOTION_HINT_MASK;
11872 attributes.visual = gtk_widget_get_visual (widget);
11873 attributes.colormap = gtk_widget_get_colormap (widget);
11875 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
11876 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
11878 widget->style = gtk_style_attach (widget->style, widget->window);
11880 gdk_window_set_user_data (widget->window, widget);
11882 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
11886 <sect2> Size negotiation
11889 Before the first time that the window containing a widget is
11890 displayed, and whenever the layout of the window changes, GTK asks
11891 each child widget for its desired size. This request is handled by the
11892 function, <tt/gtk_dial_size_request()/. Since our widget isn't a
11893 container widget, and has no real constraints on its size, we just
11894 return a reasonable default value.
11898 gtk_dial_size_request (GtkWidget *widget,
11899 GtkRequisition *requisition)
11901 requisition->width = DIAL_DEFAULT_SIZE;
11902 requisition->height = DIAL_DEFAULT_SIZE;
11907 After all the widgets have requested an ideal size, the layout of the
11908 window is computed and each child widget is notified of its actual
11909 size. Usually, this will at least as large as the requested size, but
11910 if for instance, the user has resized the window, it may occasionally
11911 be smaller than the requested size. The size notification is handled
11912 by the function <tt/gtk_dial_size_allocate()/. Notice that as well as
11913 computing the sizes of some component pieces for future use, this
11914 routine also does the grunt work of moving the widgets X window into
11915 the new position and size.
11919 gtk_dial_size_allocate (GtkWidget *widget,
11920 GtkAllocation *allocation)
11924 g_return_if_fail (widget != NULL);
11925 g_return_if_fail (GTK_IS_DIAL (widget));
11926 g_return_if_fail (allocation != NULL);
11928 widget->allocation = *allocation;
11929 if (GTK_WIDGET_REALIZED (widget))
11931 dial = GTK_DIAL (widget);
11933 gdk_window_move_resize (widget->window,
11934 allocation->x, allocation->y,
11935 allocation->width, allocation->height);
11937 dial->radius = MAX(allocation->width,allocation->height) * 0.45;
11938 dial->pointer_width = dial->radius / 5;
11943 <!-- ----------------------------------------------------------------- -->
11944 <sect2> <tt/gtk_dial_expose()/
11947 As mentioned above, all the drawing of this widget is done in the
11948 handler for expose events. There's not much to remark on here except
11949 the use of the function <tt/gtk_draw_polygon/ to draw the pointer with
11950 three dimensional shading according to the colors stored in the
11955 gtk_dial_expose (GtkWidget *widget,
11956 GdkEventExpose *event)
11959 GdkPoint points[3];
11966 g_return_val_if_fail (widget != NULL, FALSE);
11967 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
11968 g_return_val_if_fail (event != NULL, FALSE);
11970 if (event->count > 0)
11973 dial = GTK_DIAL (widget);
11975 gdk_window_clear_area (widget->window,
11977 widget->allocation.width,
11978 widget->allocation.height);
11980 xc = widget->allocation.width/2;
11981 yc = widget->allocation.height/2;
11985 for (i=0; i<25; i++)
11987 theta = (i*M_PI/18. - M_PI/6.);
11991 tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
11993 gdk_draw_line (widget->window,
11994 widget->style->fg_gc[widget->state],
11995 xc + c*(dial->radius - tick_length),
11996 yc - s*(dial->radius - tick_length),
11997 xc + c*dial->radius,
11998 yc - s*dial->radius);
12003 s = sin(dial->angle);
12004 c = cos(dial->angle);
12007 points[0].x = xc + s*dial->pointer_width/2;
12008 points[0].y = yc + c*dial->pointer_width/2;
12009 points[1].x = xc + c*dial->radius;
12010 points[1].y = yc - s*dial->radius;
12011 points[2].x = xc - s*dial->pointer_width/2;
12012 points[2].y = yc - c*dial->pointer_width/2;
12014 gtk_draw_polygon (widget->style,
12025 <!-- ----------------------------------------------------------------- -->
12026 <sect2> Event handling
12030 The rest of the widget's code handles various types of events, and
12031 isn't too different from what would be found in many GTK
12032 applications. Two types of events can occur - either the user can
12033 click on the widget with the mouse and drag to move the pointer, or
12034 the value of the Adjustment object can change due to some external
12038 When the user clicks on the widget, we check to see if the click was
12039 appropriately near the pointer, and if so, store then button that the
12040 user clicked with in the <tt/button/ field of the widget
12041 structure, and grab all mouse events with a call to
12042 <tt/gtk_grab_add()/. Subsequent motion of the mouse causes the
12043 value of the control to be recomputed (by the function
12044 <tt/gtk_dial_update_mouse/). Depending on the policy that has been
12045 set, "value_changed" events are either generated instantly
12046 (<tt/GTK_UPDATE_CONTINUOUS/), after a delay in a timer added with
12047 <tt/gtk_timeout_add()/ (<tt/GTK_UPDATE_DELAYED/), or only when the
12048 button is released (<tt/GTK_UPDATE_DISCONTINUOUS/).
12052 gtk_dial_button_press (GtkWidget *widget,
12053 GdkEventButton *event)
12059 double d_perpendicular;
12061 g_return_val_if_fail (widget != NULL, FALSE);
12062 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
12063 g_return_val_if_fail (event != NULL, FALSE);
12065 dial = GTK_DIAL (widget);
12067 /* Determine if button press was within pointer region - we
12068 do this by computing the parallel and perpendicular distance of
12069 the point where the mouse was pressed from the line passing through
12072 dx = event->x - widget->allocation.width / 2;
12073 dy = widget->allocation.height / 2 - event->y;
12075 s = sin(dial->angle);
12076 c = cos(dial->angle);
12078 d_parallel = s*dy + c*dx;
12079 d_perpendicular = fabs(s*dx - c*dy);
12081 if (!dial->button &&
12082 (d_perpendicular < dial->pointer_width/2) &&
12083 (d_parallel > - dial->pointer_width))
12085 gtk_grab_add (widget);
12087 dial->button = event->button;
12089 gtk_dial_update_mouse (dial, event->x, event->y);
12096 gtk_dial_button_release (GtkWidget *widget,
12097 GdkEventButton *event)
12101 g_return_val_if_fail (widget != NULL, FALSE);
12102 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
12103 g_return_val_if_fail (event != NULL, FALSE);
12105 dial = GTK_DIAL (widget);
12107 if (dial->button == event->button)
12109 gtk_grab_remove (widget);
12113 if (dial->policy == GTK_UPDATE_DELAYED)
12114 gtk_timeout_remove (dial->timer);
12116 if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
12117 (dial->old_value != dial->adjustment->value))
12118 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
12125 gtk_dial_motion_notify (GtkWidget *widget,
12126 GdkEventMotion *event)
12129 GdkModifierType mods;
12132 g_return_val_if_fail (widget != NULL, FALSE);
12133 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
12134 g_return_val_if_fail (event != NULL, FALSE);
12136 dial = GTK_DIAL (widget);
12138 if (dial->button != 0)
12143 if (event->is_hint || (event->window != widget->window))
12144 gdk_window_get_pointer (widget->window, &x, &y, &mods);
12146 switch (dial->button)
12149 mask = GDK_BUTTON1_MASK;
12152 mask = GDK_BUTTON2_MASK;
12155 mask = GDK_BUTTON3_MASK;
12163 gtk_dial_update_mouse (dial, x,y);
12170 gtk_dial_timer (GtkDial *dial)
12172 g_return_val_if_fail (dial != NULL, FALSE);
12173 g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
12175 if (dial->policy == GTK_UPDATE_DELAYED)
12176 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
12182 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
12187 g_return_if_fail (dial != NULL);
12188 g_return_if_fail (GTK_IS_DIAL (dial));
12190 xc = GTK_WIDGET(dial)->allocation.width / 2;
12191 yc = GTK_WIDGET(dial)->allocation.height / 2;
12193 old_value = dial->adjustment->value;
12194 dial->angle = atan2(yc-y, x-xc);
12196 if (dial->angle < -M_PI/2.)
12197 dial->angle += 2*M_PI;
12199 if (dial->angle < -M_PI/6)
12200 dial->angle = -M_PI/6;
12202 if (dial->angle > 7.*M_PI/6.)
12203 dial->angle = 7.*M_PI/6.;
12205 dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
12206 (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
12208 if (dial->adjustment->value != old_value)
12210 if (dial->policy == GTK_UPDATE_CONTINUOUS)
12212 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
12216 gtk_widget_draw (GTK_WIDGET(dial), NULL);
12218 if (dial->policy == GTK_UPDATE_DELAYED)
12221 gtk_timeout_remove (dial->timer);
12223 dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
12224 (GtkFunction) gtk_dial_timer,
12233 Changes to the Adjustment by external means are communicated to our
12234 widget by the `changed' and `value_changed' signals. The handlers
12235 for these functions call <tt/gtk_dial_update()/ to validate the
12236 arguments, compute the new pointer angle, and redraw the widget (by
12237 calling <tt/gtk_widget_draw()/).
12241 gtk_dial_update (GtkDial *dial)
12245 g_return_if_fail (dial != NULL);
12246 g_return_if_fail (GTK_IS_DIAL (dial));
12248 new_value = dial->adjustment->value;
12250 if (new_value < dial->adjustment->lower)
12251 new_value = dial->adjustment->lower;
12253 if (new_value > dial->adjustment->upper)
12254 new_value = dial->adjustment->upper;
12256 if (new_value != dial->adjustment->value)
12258 dial->adjustment->value = new_value;
12259 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
12262 dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
12263 (dial->adjustment->upper - dial->adjustment->lower);
12265 gtk_widget_draw (GTK_WIDGET(dial), NULL);
12269 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
12274 g_return_if_fail (adjustment != NULL);
12275 g_return_if_fail (data != NULL);
12277 dial = GTK_DIAL (data);
12279 if ((dial->old_value != adjustment->value) ||
12280 (dial->old_lower != adjustment->lower) ||
12281 (dial->old_upper != adjustment->upper))
12283 gtk_dial_update (dial);
12285 dial->old_value = adjustment->value;
12286 dial->old_lower = adjustment->lower;
12287 dial->old_upper = adjustment->upper;
12292 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
12297 g_return_if_fail (adjustment != NULL);
12298 g_return_if_fail (data != NULL);
12300 dial = GTK_DIAL (data);
12302 if (dial->old_value != adjustment->value)
12304 gtk_dial_update (dial);
12306 dial->old_value = adjustment->value;
12311 <!-- ----------------------------------------------------------------- -->
12312 <sect2> Possible Enhancements
12315 The Dial widget as we've described it so far runs about 670 lines of
12316 code. Although that might sound like a fair bit, we've really
12317 accomplished quite a bit with that much code, especially since much of
12318 that length is headers and boilerplate. However, there are quite a few
12319 more enhancements that could be made to this widget:
12322 <item> If you try this widget out, you'll find that there is some
12323 flashing as the pointer is dragged around. This is because the entire
12324 widget is erased every time the pointer is moved before being
12325 redrawn. Often, the best way to handle this problem is to draw to an
12326 offscreen pixmap, then copy the final results onto the screen in one
12327 step. (The ProgressBar widget draws itself in this fashion.)
12329 <item> The user should be able to use the up and down arrow keys to
12330 increase and decrease the value.
12332 <item> It would be nice if the widget had buttons to increase and
12333 decrease the value in small or large steps. Although it would be
12334 possible to use embedded Button widgets for this, we would also like
12335 the buttons to auto-repeat when held down, as the arrows on a
12336 scrollbar do. Most of the code to implement this type of behavior can
12337 be found in the GtkRange widget.
12339 <item> The Dial widget could be made into a container widget with a
12340 single child widget positioned at the bottom between the buttons
12341 mentioned above. The user could then add their choice of a label or
12342 entry widget to display the current value of the dial.
12346 <!-- ----------------------------------------------------------------- -->
12347 <sect1> Learning More
12350 Only a small part of the many details involved in creating widgets
12351 could be described above. If you want to write your own widgets, the
12352 best source of examples is the GTK source itself. Ask yourself some
12353 questions about the widget you want to write: is it a Container
12354 widget? does it have its own window? is it a modification of an
12355 existing widget? Then find a similar widget, and start making changes.
12358 <!-- ***************************************************************** -->
12359 <sect>Scribble, A Simple Example Drawing Program
12360 <!-- ***************************************************************** -->
12362 <!-- ----------------------------------------------------------------- -->
12366 In this section, we will build a simple drawing program. In the
12367 process, we will examine how to handle mouse events, how to draw in a
12368 window, and how to do drawing better by using a backing pixmap. After
12369 creating the simple drawing program, we will extend it by adding
12370 support for XInput devices, such as drawing tablets. GTK provides
12371 support routines which makes getting extended information, such as
12372 pressure and tilt, from such devices quite easy.
12374 <!-- ----------------------------------------------------------------- -->
12375 <sect1> Event Handling
12378 The GTK signals we have already discussed are for high-level actions,
12379 such as a menu item being selected. However, sometimes it is useful to
12380 learn about lower-level occurrences, such as the mouse being moved, or
12381 a key being pressed. There are also GTK signals corresponding to these
12382 low-level <em>events</em>. The handlers for these signals have an
12383 extra parameter which is a pointer to a structure containing
12384 information about the event. For instance, motion events handlers are
12385 passed a pointer to a GdkEventMotion structure which looks (in part)
12389 struct _GdkEventMotion
12402 <tt/type/ will be set to the event type, in this case
12403 <tt/GDK_MOTION_NOTIFY/, window is the window in which the event
12404 occurred. <tt/x/ and <tt/y/ give the coordinates of the event,
12405 and <tt/state/ specifies the modifier state when the event
12406 occurred (that is, it specifies which modifier keys and mouse buttons
12407 were pressed.) It is the bitwise OR of some of the following:
12426 As for other signals, to determine what happens when an event occurs
12427 we call <tt>gtk_signal_connect()</tt>. But we also need let GTK
12428 know which events we want to be notified about. To do this, we call
12432 void gtk_widget_set_events (GtkWidget *widget,
12436 The second field specifies the events we are interested in. It
12437 is the bitwise OR of constants that specify different types
12438 of events. For future reference the event types are:
12442 GDK_POINTER_MOTION_MASK
12443 GDK_POINTER_MOTION_HINT_MASK
12444 GDK_BUTTON_MOTION_MASK
12445 GDK_BUTTON1_MOTION_MASK
12446 GDK_BUTTON2_MOTION_MASK
12447 GDK_BUTTON3_MOTION_MASK
12448 GDK_BUTTON_PRESS_MASK
12449 GDK_BUTTON_RELEASE_MASK
12451 GDK_KEY_RELEASE_MASK
12452 GDK_ENTER_NOTIFY_MASK
12453 GDK_LEAVE_NOTIFY_MASK
12454 GDK_FOCUS_CHANGE_MASK
12456 GDK_PROPERTY_CHANGE_MASK
12457 GDK_PROXIMITY_IN_MASK
12458 GDK_PROXIMITY_OUT_MASK
12461 There are a few subtle points that have to be observed when calling
12462 <tt/gtk_widget_set_events()/. First, it must be called before the X window
12463 for a GTK widget is created. In practical terms, this means you
12464 should call it immediately after creating the widget. Second, the
12465 widget must have an associated X window. For efficiency, many widget
12466 types do not have their own window, but draw in their parent's window.
12489 To capture events for these widgets, you need to use an EventBox
12490 widget. See the section on the <ref id="sec_EventBox"
12491 name="EventBox"> widget for details.
12494 For our drawing program, we want to know when the mouse button is
12495 pressed and when the mouse is moved, so we specify
12496 <tt/GDK_POINTER_MOTION_MASK/ and <tt/GDK_BUTTON_PRESS_MASK/. We also
12497 want to know when we need to redraw our window, so we specify
12498 <tt/GDK_EXPOSURE_MASK/. Although we want to be notified via a
12499 Configure event when our window size changes, we don't have to specify
12500 the corresponding <tt/GDK_STRUCTURE_MASK/ flag, because it is
12501 automatically specified for all windows.
12504 It turns out, however, that there is a problem with just specifying
12505 <tt/GDK_POINTER_MOTION_MASK/. This will cause the server to add a new
12506 motion event to the event queue every time the user moves the mouse.
12507 Imagine that it takes us 0.1 seconds to handle a motion event, but the
12508 X server queues a new motion event every 0.05 seconds. We will soon
12509 get way behind the users drawing. If the user draws for 5 seconds,
12510 it will take us another 5 seconds to catch up after they release
12511 the mouse button! What we would like is to only get one motion
12512 event for each event we process. The way to do this is to
12513 specify <tt/GDK_POINTER_MOTION_HINT_MASK/.
12516 When we specify <tt/GDK_POINTER_MOTION_HINT_MASK/, the server sends
12517 us a motion event the first time the pointer moves after entering
12518 our window, or after a button press or release event. Subsequent
12519 motion events will be suppressed until we explicitly ask for
12520 the position of the pointer using the function:
12523 GdkWindow* gdk_window_get_pointer (GdkWindow *window,
12526 GdkModifierType *mask);
12529 (There is another function, <tt>gtk_widget_get_pointer()</tt> which
12530 has a simpler interface, but turns out not to be very useful, since
12531 it only retrieves the position of the mouse, not whether the buttons
12535 The code to set the events for our window then looks like:
12538 gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
12539 (GtkSignalFunc) expose_event, NULL);
12540 gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
12541 (GtkSignalFunc) configure_event, NULL);
12542 gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
12543 (GtkSignalFunc) motion_notify_event, NULL);
12544 gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
12545 (GtkSignalFunc) button_press_event, NULL);
12547 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
12548 | GDK_LEAVE_NOTIFY_MASK
12549 | GDK_BUTTON_PRESS_MASK
12550 | GDK_POINTER_MOTION_MASK
12551 | GDK_POINTER_MOTION_HINT_MASK);
12554 We'll save the "expose_event" and "configure_event" handlers for
12555 later. The "motion_notify_event" and "button_press_event" handlers
12560 button_press_event (GtkWidget *widget, GdkEventButton *event)
12562 if (event->button == 1 && pixmap != NULL)
12563 draw_brush (widget, event->x, event->y);
12569 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
12572 GdkModifierType state;
12574 if (event->is_hint)
12575 gdk_window_get_pointer (event->window, &x, &y, &state);
12580 state = event->state;
12583 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
12584 draw_brush (widget, x, y);
12590 <!-- ----------------------------------------------------------------- -->
12591 <sect1> The DrawingArea Widget, And Drawing
12594 We know turn to the process of drawing on the screen. The
12595 widget we use for this is the DrawingArea widget. A drawing area
12596 widget is essentially an X window and nothing more. It is a blank
12597 canvas in which we can draw whatever we like. A drawing area
12598 is created using the call:
12601 GtkWidget* gtk_drawing_area_new (void);
12604 A default size for the widget can be specified by calling:
12607 void gtk_drawing_area_size (GtkDrawingArea *darea,
12612 This default size can be overridden, as is true for all widgets,
12613 by calling <tt>gtk_widget_set_usize()</tt>, and that, in turn, can
12614 be overridden if the user manually resizes the the window containing
12618 It should be noted that when we create a DrawingArea widget, we are,
12619 <em>completely</em> responsible for drawing the contents. If our
12620 window is obscured then uncovered, we get an exposure event and must
12621 redraw what was previously hidden.
12624 Having to remember everything that was drawn on the screen so we
12625 can properly redraw it can, to say the least, be a nuisance. In
12626 addition, it can be visually distracting if portions of the
12627 window are cleared, then redrawn step by step. The solution to
12628 this problem is to use an offscreen <em>backing pixmap</em>.
12629 Instead of drawing directly to the screen, we draw to an image
12630 stored in server memory but not displayed, then when the image
12631 changes or new portions of the image are displayed, we copy the
12632 relevant portions onto the screen.
12635 To create an offscreen pixmap, we call the function:
12638 GdkPixmap* gdk_pixmap_new (GdkWindow *window,
12644 The <tt>window</tt> parameter specifies a GDK window that this pixmap
12645 takes some of its properties from. <tt>width</tt> and <tt>height</tt>
12646 specify the size of the pixmap. <tt>depth</tt> specifies the <em>color
12647 depth</em>, that is the number of bits per pixel, for the new window.
12648 If the depth is specified as <tt>-1</tt>, it will match the depth
12649 of <tt>window</tt>.
12652 We create the pixmap in our "configure_event" handler. This event
12653 is generated whenever the window changes size, including when it
12654 is originally created.
12657 /* Backing pixmap for drawing area */
12658 static GdkPixmap *pixmap = NULL;
12660 /* Create a new backing pixmap of the appropriate size */
12662 configure_event (GtkWidget *widget, GdkEventConfigure *event)
12665 gdk_pixmap_unref(pixmap);
12667 pixmap = gdk_pixmap_new(widget->window,
12668 widget->allocation.width,
12669 widget->allocation.height,
12671 gdk_draw_rectangle (pixmap,
12672 widget->style->white_gc,
12675 widget->allocation.width,
12676 widget->allocation.height);
12682 The call to <tt>gdk_draw_rectangle()</tt> clears the pixmap
12683 initially to white. We'll say more about that in a moment.
12686 Our exposure event handler then simply copies the relevant portion
12687 of the pixmap onto the screen (we determine the area we need
12688 to redraw by using the event->area field of the exposure event):
12691 /* Redraw the screen from the backing pixmap */
12693 expose_event (GtkWidget *widget, GdkEventExpose *event)
12695 gdk_draw_pixmap(widget->window,
12696 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
12698 event->area.x, event->area.y,
12699 event->area.x, event->area.y,
12700 event->area.width, event->area.height);
12706 We've now seen how to keep the screen up to date with our pixmap, but
12707 how do we actually draw interesting stuff on our pixmap? There are a
12708 large number of calls in GTK's GDK library for drawing on
12709 <em>drawables</em>. A drawable is simply something that can be drawn
12710 upon. It can be a window, a pixmap, or a bitmap (a black and white
12711 image). We've already seen two such calls above,
12712 <tt>gdk_draw_rectangle()</tt> and <tt>gdk_draw_pixmap()</tt>. The
12717 gdk_draw_rectangle ()
12719 gdk_draw_polygon ()
12726 gdk_draw_segments ()
12729 See the reference documentation or the header file
12730 <tt><gdk/gdk.h></tt> for further details on these functions.
12731 These functions all share the same first two arguments. The first
12732 argument is the drawable to draw upon, the second argument is a
12733 <em>graphics context</em> (GC).
12736 A graphics context encapsulates information about things such as
12737 foreground and background color and line width. GDK has a full set of
12738 functions for creating and modifying graphics contexts, but to keep
12739 things simple we'll just use predefined graphics contexts. Each widget
12740 has an associated style. (Which can be modified in a gtkrc file, see
12741 the section GTK's rc file.) This, among other things, stores a number
12742 of graphics contexts. Some examples of accessing these graphics
12746 widget->style->white_gc
12747 widget->style->black_gc
12748 widget->style->fg_gc[GTK_STATE_NORMAL]
12749 widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
12752 The fields <tt>fg_gc</tt>, <tt>bg_gc</tt>, <tt>dark_gc</tt>, and
12753 <tt>light_gc</tt> are indexed by a parameter of type
12754 <tt>GtkStateType</tt> which can take on the values:
12759 GTK_STATE_PRELIGHT,
12760 GTK_STATE_SELECTED,
12761 GTK_STATE_INSENSITIVE
12764 For instance, the for <tt/GTK_STATE_SELECTED/ the default foreground
12765 color is white and the default background color, dark blue.
12768 Our function <tt>draw_brush()</tt>, which does the actual drawing
12769 on the screen, is then:
12772 /* Draw a rectangle on the screen */
12774 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
12776 GdkRectangle update_rect;
12778 update_rect.x = x - 5;
12779 update_rect.y = y - 5;
12780 update_rect.width = 10;
12781 update_rect.height = 10;
12782 gdk_draw_rectangle (pixmap,
12783 widget->style->black_gc,
12785 update_rect.x, update_rect.y,
12786 update_rect.width, update_rect.height);
12787 gtk_widget_draw (widget, &update_rect);
12791 After we draw the rectangle representing the brush onto the pixmap,
12792 we call the function:
12795 void gtk_widget_draw (GtkWidget *widget,
12796 GdkRectangle *area);
12799 which notifies X that the area given by the <tt>area</tt> parameter
12800 needs to be updated. X will eventually generate an expose event
12801 (possibly combining the areas passed in several calls to
12802 <tt>gtk_widget_draw()</tt>) which will cause our expose event handler
12803 to copy the relevant portions to the screen.
12806 We have now covered the entire drawing program except for a few
12807 mundane details like creating the main window. The complete
12808 source code is available from the location from which you got
12809 this tutorial, or from:
12811 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
12812 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
12815 <!-- ----------------------------------------------------------------- -->
12816 <sect1> Adding XInput support
12820 It is now possible to buy quite inexpensive input devices such
12821 as drawing tablets, which allow drawing with a much greater
12822 ease of artistic expression than does a mouse. The simplest way
12823 to use such devices is simply as a replacement for the mouse,
12824 but that misses out many of the advantages of these devices,
12828 <item> Pressure sensitivity
12829 <item> Tilt reporting
12830 <item> Sub-pixel positioning
12831 <item> Multiple inputs (for example, a stylus with a point and eraser)
12834 For information about the XInput extension, see the <htmlurl
12835 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
12836 name="XInput-HOWTO">.
12839 If we examine the full definition of, for example, the GdkEventMotion
12840 structure, we see that it has fields to support extended device
12844 struct _GdkEventMotion
12856 GdkInputSource source;
12861 <tt/pressure/ gives the pressure as a floating point number between
12862 0 and 1. <tt/xtilt/ and <tt/ytilt/ can take on values between
12863 -1 and 1, corresponding to the degree of tilt in each direction.
12864 <tt/source/ and <tt/deviceid/ specify the device for which the
12865 event occurred in two different ways. <tt/source/ gives some simple
12866 information about the type of device. It can take the enumeration
12876 <tt/deviceid/ specifies a unique numeric ID for the device. This can
12877 be used to find out further information about the device using the
12878 <tt/gdk_input_list_devices()/ call (see below). The special value
12879 <tt/GDK_CORE_POINTER/ is used for the core pointer device. (Usually
12882 <sect2> Enabling extended device information
12885 To let GTK know about our interest in the extended device information,
12886 we merely have to add a single line to our program:
12889 gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
12892 By giving the value <tt/GDK_EXTENSION_EVENTS_CURSOR/ we say that
12893 we are interested in extension events, but only if we don't have
12894 to draw our own cursor. See the section <ref
12895 id="sec_Further_Sophistications" name="Further Sophistications"> below
12896 for more information about drawing the cursor. We could also
12897 give the values <tt/GDK_EXTENSION_EVENTS_ALL/ if we were willing
12898 to draw our own cursor, or <tt/GDK_EXTENSION_EVENTS_NONE/ to revert
12899 back to the default condition.
12902 This is not completely the end of the story however. By default,
12903 no extension devices are enabled. We need a mechanism to allow
12904 users to enable and configure their extension devices. GTK provides
12905 the InputDialog widget to automate this process. The following
12906 procedure manages an InputDialog widget. It creates the dialog if
12907 it isn't present, and raises it to the top otherwise.
12911 input_dialog_destroy (GtkWidget *w, gpointer data)
12913 *((GtkWidget **)data) = NULL;
12917 create_input_dialog ()
12919 static GtkWidget *inputd = NULL;
12923 inputd = gtk_input_dialog_new();
12925 gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
12926 (GtkSignalFunc)input_dialog_destroy, &inputd);
12927 gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
12929 (GtkSignalFunc)gtk_widget_hide,
12930 GTK_OBJECT(inputd));
12931 gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
12933 gtk_widget_show (inputd);
12937 if (!GTK_WIDGET_MAPPED(inputd))
12938 gtk_widget_show(inputd);
12940 gdk_window_raise(inputd->window);
12945 (You might want to take note of the way we handle this dialog. By
12946 connecting to the "destroy" signal, we make sure that we don't keep a
12947 pointer to dialog around after it is destroyed - that could lead to a
12951 The InputDialog has two buttons "Close" and "Save", which by default
12952 have no actions assigned to them. In the above function we make
12953 "Close" hide the dialog, hide the "Save" button, since we don't
12954 implement saving of XInput options in this program.
12956 <sect2> Using extended device information
12959 Once we've enabled the device, we can just use the extended
12960 device information in the extra fields of the event structures.
12961 In fact, it is always safe to use this information since these
12962 fields will have reasonable default values even when extended
12963 events are not enabled.
12966 Once change we do have to make is to call
12967 <tt/gdk_input_window_get_pointer()/ instead of
12968 <tt/gdk_window_get_pointer/. This is necessary because
12969 <tt/gdk_window_get_pointer/ doesn't return the extended device
12973 void gdk_input_window_get_pointer (GdkWindow *window,
12980 GdkModifierType *mask);
12983 When calling this function, we need to specify the device ID as
12984 well as the window. Usually, we'll get the device ID from the
12985 <tt/deviceid/ field of an event structure. Again, this function
12986 will return reasonable values when extension events are not
12987 enabled. (In this case, <tt/event->deviceid/ will have the value
12988 <tt/GDK_CORE_POINTER/).
12990 So the basic structure of our button-press and motion event handlers,
12991 doesn't change much - we just need to add code to deal with the
12992 extended information.
12996 button_press_event (GtkWidget *widget, GdkEventButton *event)
12998 print_button_press (event->deviceid);
13000 if (event->button == 1 && pixmap != NULL)
13001 draw_brush (widget, event->source, event->x, event->y, event->pressure);
13007 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
13011 GdkModifierType state;
13013 if (event->is_hint)
13014 gdk_input_window_get_pointer (event->window, event->deviceid,
13015 &x, &y, &pressure, NULL, NULL, &state);
13020 pressure = event->pressure;
13021 state = event->state;
13024 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
13025 draw_brush (widget, event->source, x, y, pressure);
13031 We also need to do something with the new information. Our new
13032 <tt/draw_brush()/ function draws with a different color for
13033 each <tt/event->source/ and changes the brush size depending
13037 /* Draw a rectangle on the screen, size depending on pressure,
13038 and color on the type of device */
13040 draw_brush (GtkWidget *widget, GdkInputSource source,
13041 gdouble x, gdouble y, gdouble pressure)
13044 GdkRectangle update_rect;
13048 case GDK_SOURCE_MOUSE:
13049 gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
13051 case GDK_SOURCE_PEN:
13052 gc = widget->style->black_gc;
13054 case GDK_SOURCE_ERASER:
13055 gc = widget->style->white_gc;
13058 gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
13061 update_rect.x = x - 10 * pressure;
13062 update_rect.y = y - 10 * pressure;
13063 update_rect.width = 20 * pressure;
13064 update_rect.height = 20 * pressure;
13065 gdk_draw_rectangle (pixmap, gc, TRUE,
13066 update_rect.x, update_rect.y,
13067 update_rect.width, update_rect.height);
13068 gtk_widget_draw (widget, &update_rect);
13072 <sect2> Finding out more about a device
13075 As an example of how to find out more about a device, our program
13076 will print the name of the device that generates each button
13077 press. To find out the name of a device, we call the function:
13080 GList *gdk_input_list_devices (void);
13083 which returns a GList (a linked list type from the glib library)
13084 of GdkDeviceInfo structures. The GdkDeviceInfo structure is defined
13088 struct _GdkDeviceInfo
13092 GdkInputSource source;
13098 GdkDeviceKey *keys;
13102 Most of these fields are configuration information that you
13103 can ignore unless you are implemented XInput configuration
13104 saving. The we are interested in here is <tt/name/ which is
13105 simply the name that X assigns to the device. The other field
13106 that isn't configuration information is <tt/has_cursor/. If
13107 <tt/has_cursor/ is false, then we we need to draw our own
13108 cursor. But since we've specified <tt/GDK_EXTENSION_EVENTS_CURSOR/,
13109 we don't have to worry about this.
13112 Our <tt/print_button_press()/ function simply iterates through
13113 the returned list until it finds a match, then prints out
13114 the name of the device.
13118 print_button_press (guint32 deviceid)
13122 /* gdk_input_list_devices returns an internal list, so we shouldn't
13123 free it afterwards */
13124 tmp_list = gdk_input_list_devices();
13128 GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
13130 if (info->deviceid == deviceid)
13132 printf("Button press on device '%s'\n", info->name);
13136 tmp_list = tmp_list->next;
13141 That completes the changes to `XInputize' our program. As with
13142 the first version, the complete source is available at the location
13143 from which you got this tutorial, or from:
13145 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
13146 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
13149 <sect2> Further sophistications <label id="sec_Further_Sophistications">
13152 Although our program now supports XInput quite well, it lacks some
13153 features we would want in a full-featured application. First, the user
13154 probably doesn't want to have to configure their device each time they
13155 run the program, so we should allow them to save the device
13156 configuration. This is done by iterating through the return of
13157 <tt/gdk_input_list_devices()/ and writing out the configuration to a
13161 To restore the state next time the program is run, GDK provides
13162 functions to change device configuration:
13165 gdk_input_set_extension_events()
13166 gdk_input_set_source()
13167 gdk_input_set_mode()
13168 gdk_input_set_axes()
13169 gdk_input_set_key()
13172 (The list returned from <tt/gdk_input_list_devices()/ should not be
13173 modified directly.) An example of doing this can be found in the
13174 drawing program gsumi. (Available from <htmlurl
13175 url="http://www.msc.cornell.edu/~otaylor/gsumi/"
13176 name="http://www.msc.cornell.edu/~otaylor/gsumi/">) Eventually, it
13177 would be nice to have a standard way of doing this for all
13178 applications. This probably belongs at a slightly higher level than
13179 GTK, perhaps in the GNOME library.
13182 Another major omission that we have mentioned above is the lack of
13183 cursor drawing. Platforms other than XFree86 currently do not allow
13184 simultaneously using a device as both the core pointer and directly by
13185 an application. See the <url
13186 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
13187 name="XInput-HOWTO"> for more information about this. This means that
13188 applications that want to support the widest audience need to draw
13192 An application that draws its own cursor needs to do two things:
13193 determine if the current device needs a cursor drawn or not, and
13194 determine if the current device is in proximity. (If the current
13195 device is a drawing tablet, it's a nice touch to make the cursor
13196 disappear when the stylus is lifted from the tablet. When the
13197 device is touching the stylus, that is called "in proximity.")
13198 The first is done by searching the device list, as we did
13199 to find out the device name. The second is achieved by selecting
13200 "proximity_out" events. An example of drawing one's own cursor is
13201 found in the 'testinput' program found in the GTK distribution.
13203 <!-- ***************************************************************** -->
13204 <sect>Tips For Writing GTK Applications
13205 <!-- ***************************************************************** -->
13208 This section is simply a gathering of wisdom, general style guidelines and hints to
13209 creating good GTK applications. It is totally useless right now cause its
13210 only a topic sentence :)
13212 Use GNU autoconf and automake! They are your friends :) I am planning to
13213 make a quick intro on them here.
13215 <!-- ***************************************************************** -->
13216 <sect>Contributing <label id="sec_Contributing">
13217 <!-- ***************************************************************** -->
13220 This document, like so much other great software out there, was created for
13221 free by volunteers. If you are at all knowledgeable about any aspect of GTK
13222 that does not already have documentation, please consider contributing to
13225 If you do decide to contribute, please mail your text to Tony Gale,
13226 <tt><htmlurl url="mailto:gale@gtk.org"
13227 name="gale@gtk.org"></tt>. Also, be aware that the entirety of this
13228 document is free, and any addition by you provide must also be free. That is,
13229 people may use any portion of your examples in their programs, and copies
13230 of this document may be distributed at will etc.
13234 <!-- ***************************************************************** -->
13236 <!-- ***************************************************************** -->
13238 I would like to thank the following for their contributions to this text.
13241 <item>Bawer Dagdeviren, <tt><htmlurl url="mailto:chamele0n@geocities.com"
13242 name="chamele0n@geocities.com"></tt> for the menus tutorial.
13244 <item>Raph Levien, <tt><htmlurl url="mailto:raph@acm.org"
13245 name="raph@acm.org"></tt>
13246 for hello world ala GTK, widget packing, and general all around wisdom.
13247 He's also generously donated a home for this tutorial.
13249 <item>Peter Mattis, <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
13250 name="petm@xcf.berkeley.edu"></tt> for the simplest GTK program..
13251 and the ability to make it :)
13253 <item>Werner Koch <tt><htmlurl url="mailto:werner.koch@guug.de"
13254 name="werner.koch@guug.de"></tt> for converting the original plain text to
13255 SGML, and the widget class hierarchy.
13257 <item>Mark Crichton <tt><htmlurl url="mailto:crichton@expert.cc.purdue.edu"
13258 name="crichton@expert.cc.purdue.edu"></tt> for the menu factory code, and
13259 the table packing tutorial.
13261 <item>Owen Taylor <tt><htmlurl url="mailto:owt1@cornell.edu"
13262 name="owt1@cornell.edu"></tt> for the EventBox widget section (and
13263 the patch to the distro). He's also responsible for the selections code and
13264 tutorial, as well as the sections on writing your own GTK widgets, and the
13265 example application. Thanks a lot Owen for all you help!
13267 <item>Mark VanderBoom <tt><htmlurl url="mailto:mvboom42@calvin.edu"
13268 name="mvboom42@calvin.edu"></tt> for his wonderful work on the Notebook,
13269 Progress Bar, Dialogs, and File selection widgets. Thanks a lot Mark!
13270 You've been a great help.
13272 <item>Tim Janik <tt><htmlurl url="mailto:timj@gtk.org"
13273 name="timj@psynet.net"></tt> for his great job on the Lists
13274 Widget. His excellent work on automatically extracting the widget tree
13275 and signal information from GTK.
13278 <item>Rajat Datta <tt><htmlurl url="mailto:rajat@ix.netcom.com"
13279 name="rajat@ix.netcom.com"</tt> for the excellent job on the Pixmap tutorial.
13281 <item>Michael K. Johnson <tt><htmlurl url="mailto:johnsonm@redhat.com"
13282 name="johnsonm@redhat.com"></tt> for info and code for popup menus.
13284 <item>David Huggins-Daines <tt><htmlurl url="mailto:bn711@freenet.carleton.ca"
13285 name="bn711@freenet.carleton.ca"></tt> for the Range Widgets and Tree Widget
13288 <item>Stefan Mars <tt><htmlurl url="mailto:mars@lysator.liu.se"
13289 name="mars@lysator.liu.se"></tt> for the GtkCList section
13292 And to all of you who commented and helped refine this document.
13296 <!-- ***************************************************************** -->
13297 <sect> Tutorial Copyright and Permissions Notice
13298 <!-- ***************************************************************** -->
13301 The GTK Tutorial is Copyright (C) 1997 Ian Main.
13303 Copyright (C) 1998 Tony Gale.
13305 Permission is granted to make and distribute verbatim copies of this
13306 manual provided the copyright notice and this permission notice are
13307 preserved on all copies.
13308 <P>Permission is granted to copy and distribute modified versions of
13309 this document under the conditions for verbatim copying, provided that
13310 this copyright notice is included exactly as in the original,
13311 and that the entire resulting derived work is distributed under
13312 the terms of a permission notice identical to this one.
13313 <P>Permission is granted to copy and distribute translations of this
13314 document into another language, under the above conditions for modified
13316 <P>If you are intending to incorporate this document into a published
13317 work, please contact the maintainer, and we will make an effort
13318 to ensure that you have the most up to date information available.
13319 <P>There is no guarantee that this document lives up to its intended
13320 purpose. This is simply provided as a free resource. As such,
13321 the authors and maintainers of the information provided within can
13322 not make any guarantee that the information is even accurate.
13324 <!-- ***************************************************************** -->
13326 <!-- ***************************************************************** -->
13328 <!-- ***************************************************************** -->
13329 <sect> GTK Signals <label id="sec_GTK_Signals">
13330 <!-- ***************************************************************** -->
13332 As GTK is an object oriented widget set, it has a hierarchy of
13333 inheritance. This inheritance mechanism applies for
13334 signals. Therefore, you should refer to the widget hierarchy tree when
13335 using the signals listed in this section.
13337 <!-- ----------------------------------------------------------------- -->
13339 <!-- ----------------------------------------------------------------- -->
13342 void GtkObject::destroy (GtkObject *,
13346 <!-- ----------------------------------------------------------------- -->
13348 <!-- ----------------------------------------------------------------- -->
13352 void GtkWidget::show (GtkWidget *,
13354 void GtkWidget::hide (GtkWidget *,
13356 void GtkWidget::map (GtkWidget *,
13358 void GtkWidget::unmap (GtkWidget *,
13360 void GtkWidget::realize (GtkWidget *,
13362 void GtkWidget::unrealize (GtkWidget *,
13364 void GtkWidget::draw (GtkWidget *,
13367 void GtkWidget::draw-focus (GtkWidget *,
13369 void GtkWidget::draw-default (GtkWidget *,
13371 void GtkWidget::size-request (GtkWidget *,
13374 void GtkWidget::size-allocate (GtkWidget *,
13377 void GtkWidget::state-changed (GtkWidget *,
13380 void GtkWidget::parent-set (GtkWidget *,
13383 void GtkWidget::style-set (GtkWidget *,
13386 void GtkWidget::add-accelerator (GtkWidget *,
13393 void GtkWidget::remove-accelerator (GtkWidget *,
13398 gboolean GtkWidget::event (GtkWidget *,
13401 gboolean GtkWidget::button-press-event (GtkWidget *,
13404 gboolean GtkWidget::button-release-event (GtkWidget *,
13407 gboolean GtkWidget::motion-notify-event (GtkWidget *,
13410 gboolean GtkWidget::delete-event (GtkWidget *,
13413 gboolean GtkWidget::destroy-event (GtkWidget *,
13416 gboolean GtkWidget::expose-event (GtkWidget *,
13419 gboolean GtkWidget::key-press-event (GtkWidget *,
13422 gboolean GtkWidget::key-release-event (GtkWidget *,
13425 gboolean GtkWidget::enter-notify-event (GtkWidget *,
13428 gboolean GtkWidget::leave-notify-event (GtkWidget *,
13431 gboolean GtkWidget::configure-event (GtkWidget *,
13434 gboolean GtkWidget::focus-in-event (GtkWidget *,
13437 gboolean GtkWidget::focus-out-event (GtkWidget *,
13440 gboolean GtkWidget::map-event (GtkWidget *,
13443 gboolean GtkWidget::unmap-event (GtkWidget *,
13446 gboolean GtkWidget::property-notify-event (GtkWidget *,
13449 gboolean GtkWidget::selection-clear-event (GtkWidget *,
13452 gboolean GtkWidget::selection-request-event (GtkWidget *,
13455 gboolean GtkWidget::selection-notify-event (GtkWidget *,
13458 void GtkWidget::selection-get (GtkWidget *,
13459 GtkSelectionData *,
13462 void GtkWidget::selection-received (GtkWidget *,
13463 GtkSelectionData *,
13466 gboolean GtkWidget::proximity-in-event (GtkWidget *,
13469 gboolean GtkWidget::proximity-out-event (GtkWidget *,
13472 void GtkWidget::drag-begin (GtkWidget *,
13475 void GtkWidget::drag-end (GtkWidget *,
13478 void GtkWidget::drag-data-delete (GtkWidget *,
13481 void GtkWidget::drag-leave (GtkWidget *,
13485 gboolean GtkWidget::drag-motion (GtkWidget *,
13491 gboolean GtkWidget::drag-drop (GtkWidget *,
13497 void GtkWidget::drag-data-get (GtkWidget *,
13499 GtkSelectionData *,
13503 void GtkWidget::drag-data-received (GtkWidget *,
13507 GtkSelectionData *,
13511 gboolean GtkWidget::client-event (GtkWidget *,
13514 gboolean GtkWidget::no-expose-event (GtkWidget *,
13517 gboolean GtkWidget::visibility-notify-event (GtkWidget *,
13520 void GtkWidget::debug-msg (GtkWidget *,
13525 <!-- ----------------------------------------------------------------- -->
13527 <!-- ----------------------------------------------------------------- -->
13530 void GtkData::disconnect (GtkData *,
13534 <!-- ----------------------------------------------------------------- -->
13535 <sect1>GtkContainer
13536 <!-- ----------------------------------------------------------------- -->
13539 void GtkContainer::add (GtkContainer *,
13542 void GtkContainer::remove (GtkContainer *,
13545 void GtkContainer::check-resize (GtkContainer *,
13547 GtkDirectionType GtkContainer::focus (GtkContainer *,
13550 void GtkContainer::set-focus-child (GtkContainer *,
13555 <!-- ----------------------------------------------------------------- -->
13557 <!-- ----------------------------------------------------------------- -->
13560 void GtkCalendar::month-changed (GtkCalendar *,
13562 void GtkCalendar::day-selected (GtkCalendar *,
13564 void GtkCalendar::day-selected-double-click (GtkCalendar *,
13566 void GtkCalendar::prev-month (GtkCalendar *,
13568 void GtkCalendar::next-month (GtkCalendar *,
13570 void GtkCalendar::prev-year (GtkCalendar *,
13572 void GtkCalendar::next-year (GtkCalendar *,
13576 <!-- ----------------------------------------------------------------- -->
13578 <!-- ----------------------------------------------------------------- -->
13581 void GtkEditable::changed (GtkEditable *,
13583 void GtkEditable::insert-text (GtkEditable *,
13588 void GtkEditable::delete-text (GtkEditable *,
13592 void GtkEditable::activate (GtkEditable *,
13594 void GtkEditable::set-editable (GtkEditable *,
13597 void GtkEditable::move-cursor (GtkEditable *,
13601 void GtkEditable::move-word (GtkEditable *,
13604 void GtkEditable::move-page (GtkEditable *,
13608 void GtkEditable::move-to-row (GtkEditable *,
13611 void GtkEditable::move-to-column (GtkEditable *,
13614 void GtkEditable::kill-char (GtkEditable *,
13617 void GtkEditable::kill-word (GtkEditable *,
13620 void GtkEditable::kill-line (GtkEditable *,
13623 void GtkEditable::cut-clipboard (GtkEditable *,
13625 void GtkEditable::copy-clipboard (GtkEditable *,
13627 void GtkEditable::paste-clipboard (GtkEditable *,
13631 <!-- ----------------------------------------------------------------- -->
13632 <sect1>GtkTipsQuery
13633 <!-- ----------------------------------------------------------------- -->
13636 void GtkTipsQuery::start-query (GtkTipsQuery *,
13638 void GtkTipsQuery::stop-query (GtkTipsQuery *,
13640 void GtkTipsQuery::widget-entered (GtkTipsQuery *,
13645 gboolean GtkTipsQuery::widget-selected (GtkTipsQuery *,
13653 <!-- ----------------------------------------------------------------- -->
13655 <!-- ----------------------------------------------------------------- -->
13658 void GtkCList::select-row (GtkCList *,
13663 void GtkCList::unselect-row (GtkCList *,
13668 void GtkCList::row-move (GtkCList *,
13672 void GtkCList::click-column (GtkCList *,
13675 void GtkCList::resize-column (GtkCList *,
13679 void GtkCList::toggle-focus-row (GtkCList *,
13681 void GtkCList::select-all (GtkCList *,
13683 void GtkCList::unselect-all (GtkCList *,
13685 void GtkCList::undo-selection (GtkCList *,
13687 void GtkCList::start-selection (GtkCList *,
13689 void GtkCList::end-selection (GtkCList *,
13691 void GtkCList::toggle-add-mode (GtkCList *,
13693 void GtkCList::extend-selection (GtkCList *,
13698 void GtkCList::scroll-vertical (GtkCList *,
13702 void GtkCList::scroll-horizontal (GtkCList *,
13706 void GtkCList::abort-column-resize (GtkCList *,
13710 <!-- ----------------------------------------------------------------- -->
13712 <!-- ----------------------------------------------------------------- -->
13715 void GtkNotebook::switch-page (GtkNotebook *,
13722 <!-- ----------------------------------------------------------------- -->
13724 <!-- ----------------------------------------------------------------- -->
13727 void GtkList::selection-changed (GtkList *,
13729 void GtkList::select-child (GtkList *,
13732 void GtkList::unselect-child (GtkList *,
13737 <!-- ----------------------------------------------------------------- -->
13738 <sect1>GtkMenuShell
13739 <!-- ----------------------------------------------------------------- -->
13742 void GtkMenuShell::deactivate (GtkMenuShell *,
13744 void GtkMenuShell::selection-done (GtkMenuShell *,
13746 void GtkMenuShell::move-current (GtkMenuShell *,
13747 GtkMenuDirectionType,
13749 void GtkMenuShell::activate-current (GtkMenuShell *,
13752 void GtkMenuShell::cancel (GtkMenuShell *,
13756 <!-- ----------------------------------------------------------------- -->
13758 <!-- ----------------------------------------------------------------- -->
13761 void GtkToolbar::orientation-changed (GtkToolbar *,
13764 void GtkToolbar::style-changed (GtkToolbar *,
13769 <!-- ----------------------------------------------------------------- -->
13771 <!-- ----------------------------------------------------------------- -->
13774 void GtkTree::selection-changed (GtkTree *,
13776 void GtkTree::select-child (GtkTree *,
13779 void GtkTree::unselect-child (GtkTree *,
13784 <!-- ----------------------------------------------------------------- -->
13786 <!-- ----------------------------------------------------------------- -->
13789 void GtkButton::pressed (GtkButton *,
13791 void GtkButton::released (GtkButton *,
13793 void GtkButton::clicked (GtkButton *,
13795 void GtkButton::enter (GtkButton *,
13797 void GtkButton::leave (GtkButton *,
13801 <!-- ----------------------------------------------------------------- -->
13803 <!-- ----------------------------------------------------------------- -->
13806 void GtkItem::select (GtkItem *,
13808 void GtkItem::deselect (GtkItem *,
13810 void GtkItem::toggle (GtkItem *,
13814 <!-- ----------------------------------------------------------------- -->
13816 <!-- ----------------------------------------------------------------- -->
13819 void GtkWindow::set-focus (GtkWindow *,
13824 <!-- ----------------------------------------------------------------- -->
13825 <sect1>GtkHandleBox
13826 <!-- ----------------------------------------------------------------- -->
13829 void GtkHandleBox::child-attached (GtkHandleBox *,
13832 void GtkHandleBox::child-detached (GtkHandleBox *,
13837 <!-- ----------------------------------------------------------------- -->
13838 <sect1>GtkToggleButton
13839 <!-- ----------------------------------------------------------------- -->
13842 void GtkToggleButton::toggled (GtkToggleButton *,
13847 <!-- ----------------------------------------------------------------- -->
13849 <!-- ----------------------------------------------------------------- -->
13852 void GtkMenuItem::activate (GtkMenuItem *,
13854 void GtkMenuItem::activate-item (GtkMenuItem *,
13858 <!-- ----------------------------------------------------------------- -->
13860 <!-- ----------------------------------------------------------------- -->
13863 void GtkListItem::toggle-focus-row (GtkListItem *,
13865 void GtkListItem::select-all (GtkListItem *,
13867 void GtkListItem::unselect-all (GtkListItem *,
13869 void GtkListItem::undo-selection (GtkListItem *,
13871 void GtkListItem::start-selection (GtkListItem *,
13873 void GtkListItem::end-selection (GtkListItem *,
13875 void GtkListItem::toggle-add-mode (GtkListItem *,
13877 void GtkListItem::extend-selection (GtkListItem *,
13882 void GtkListItem::scroll-vertical (GtkListItem *,
13886 void GtkListItem::scroll-horizontal (GtkListItem *,
13892 <!-- ----------------------------------------------------------------- -->
13894 <!-- ----------------------------------------------------------------- -->
13897 void GtkTreeItem::collapse (GtkTreeItem *,
13899 void GtkTreeItem::expand (GtkTreeItem *,
13903 <!-- ----------------------------------------------------------------- -->
13904 <sect1>GtkCheckMenuItem
13905 <!-- ----------------------------------------------------------------- -->
13908 void GtkCheckMenuItem::toggled (GtkCheckMenuItem *,
13912 <!-- ----------------------------------------------------------------- -->
13913 <sect1>GtkInputDialog
13914 <!-- ----------------------------------------------------------------- -->
13917 void GtkInputDialog::enable-device (GtkInputDialog *,
13920 void GtkInputDialog::disable-device (GtkInputDialog *,
13925 <!-- ----------------------------------------------------------------- -->
13926 <sect1>GtkColorSelection
13927 <!-- ----------------------------------------------------------------- -->
13930 void GtkColorSelection::color-changed (GtkColorSelection *,
13934 <!-- ----------------------------------------------------------------- -->
13935 <sect1>GtkStatusBar
13936 <!-- ----------------------------------------------------------------- -->
13939 void GtkStatusbar::text-pushed (GtkStatusbar *,
13943 void GtkStatusbar::text-popped (GtkStatusbar *,
13949 <!-- ----------------------------------------------------------------- -->
13951 <!-- ----------------------------------------------------------------- -->
13954 void GtkCTree::tree-select-row (GtkCTree *,
13958 void GtkCTree::tree-unselect-row (GtkCTree *,
13962 void GtkCTree::tree-expand (GtkCTree *,
13965 void GtkCTree::tree-collapse (GtkCTree *,
13968 void GtkCTree::tree-move (GtkCTree *,
13973 void GtkCTree::change-focus-row-expansion (GtkCTree *,
13974 GtkCTreeExpansionType,
13978 <!-- ----------------------------------------------------------------- -->
13980 <!-- ----------------------------------------------------------------- -->
13983 void GtkCurve::curve-type-changed (GtkCurve *,
13987 <!-- ----------------------------------------------------------------- -->
13988 <sect1>GtkAdjustment
13989 <!-- ----------------------------------------------------------------- -->
13992 void GtkAdjustment::changed (GtkAdjustment *,
13994 void GtkAdjustment::value-changed (GtkAdjustment *,
13998 <!-- ***************************************************************** -->
13999 <sect> GDK Event Types<label id="sec_GDK_Event_Types">
14000 <!-- ***************************************************************** -->
14002 The follwing data types are passed into event handlers by GTK+. For
14003 each data type listed, the signals that use this data type are listed.
14008 <item>drag_end_event
14011 <item> GdkEventType
14016 <item>destroy_event
14019 <item>no_expose_event
14022 <item> GdkEventExpose
14027 <item> GdkEventNoExpose
14029 <item> GdkEventVisibility
14031 <item> GdkEventMotion
14033 <item>motion_notify_event
14036 <item> GdkEventButton
14038 <item>button_press_event
14039 <item>button_release_event
14044 <item>key_press_event
14045 <item>key_release_event
14048 <item> GdkEventCrossing
14050 <item>enter_notify_event
14051 <item>leave_notify_event
14054 <item> GdkEventFocus
14056 <item>focus_in_event
14057 <item>focus_out_event
14060 <item> GdkEventConfigure
14062 <item>configure_event
14065 <item> GdkEventProperty
14067 <item>property_notify_event
14070 <item> GdkEventSelection
14072 <item>selection_clear_event
14073 <item>selection_request_event
14074 <item>selection_notify_event
14077 <item> GdkEventProximity
14079 <item>proximity_in_event
14080 <item>proximity_out_event
14083 <item> GdkEventDragBegin
14085 <item>drag_begin_event
14088 <item> GdkEventDragRequest
14090 <item>drag_request_event
14093 <item> GdkEventDropEnter
14095 <item>drop_enter_event
14098 <item> GdkEventDropLeave
14100 <item>drop_leave_event
14103 <item> GdkEventDropDataAvailable
14105 <item>drop_data_available_event
14108 <item> GdkEventClient
14113 <item> GdkEventOther
14119 The data type <tt/GdkEventType/ is a special data type that is used by
14120 all the other data types as an indicator of the data type being passed
14121 to the signal handler. As you will see below, each of the event data
14122 structures has a member of this type. It is defined as an enumeration
14132 GDK_MOTION_NOTIFY = 3,
14133 GDK_BUTTON_PRESS = 4,
14134 GDK_2BUTTON_PRESS = 5,
14135 GDK_3BUTTON_PRESS = 6,
14136 GDK_BUTTON_RELEASE = 7,
14138 GDK_KEY_RELEASE = 9,
14139 GDK_ENTER_NOTIFY = 10,
14140 GDK_LEAVE_NOTIFY = 11,
14141 GDK_FOCUS_CHANGE = 12,
14142 GDK_CONFIGURE = 13,
14145 GDK_PROPERTY_NOTIFY = 16,
14146 GDK_SELECTION_CLEAR = 17,
14147 GDK_SELECTION_REQUEST = 18,
14148 GDK_SELECTION_NOTIFY = 19,
14149 GDK_PROXIMITY_IN = 20,
14150 GDK_PROXIMITY_OUT = 21,
14151 GDK_DRAG_BEGIN = 22,
14152 GDK_DRAG_REQUEST = 23,
14153 GDK_DROP_ENTER = 24,
14154 GDK_DROP_LEAVE = 25,
14155 GDK_DROP_DATA_AVAIL = 26,
14156 GDK_CLIENT_EVENT = 27,
14157 GDK_VISIBILITY_NOTIFY = 28,
14158 GDK_NO_EXPOSE = 29,
14159 GDK_OTHER_EVENT = 9999 /* Deprecated, use filters instead */
14163 The other event type that is different from the others is
14164 <tt/GdkEvent/ itself. This is a union of all the other
14165 data types, which allows it to be cast to a specific
14166 event data type within a signal handler.
14168 <!-- Just a big list for now, needs expanding upon - TRG -->
14169 So, the event data types are defined as follows:
14172 struct _GdkEventAny
14179 struct _GdkEventExpose
14185 gint count; /* If non-zero, how many more events follow. */
14188 struct _GdkEventNoExpose
14193 /* XXX: does anyone need the X major_code or minor_code fields? */
14196 struct _GdkEventVisibility
14201 GdkVisibilityState state;
14204 struct _GdkEventMotion
14217 GdkInputSource source;
14219 gdouble x_root, y_root;
14222 struct _GdkEventButton
14235 GdkInputSource source;
14237 gdouble x_root, y_root;
14240 struct _GdkEventKey
14252 struct _GdkEventCrossing
14257 GdkWindow *subwindow;
14258 GdkNotifyType detail;
14261 struct _GdkEventFocus
14269 struct _GdkEventConfigure
14279 struct _GdkEventProperty
14289 struct _GdkEventSelection
14301 /* This event type will be used pretty rarely. It only is important
14302 for XInput aware programs that are drawing their own cursor */
14304 struct _GdkEventProximity
14310 GdkInputSource source;
14314 struct _GdkEventDragRequest
14322 guint protocol_version:4;
14324 guint willaccept:1;
14325 guint delete_data:1; /* Do *not* delete if link is sent, only
14332 guint8 isdrop; /* This gdk event can be generated by a couple of
14333 X events - this lets the app know whether the
14334 drop really occurred or we just set the data */
14336 GdkPoint drop_coords;
14341 struct _GdkEventDragBegin
14348 guint protocol_version:4;
14355 struct _GdkEventDropEnter
14363 guint protocol_version:4;
14365 guint extended_typelist:1;
14372 struct _GdkEventDropLeave
14380 guint protocol_version:4;
14387 struct _GdkEventDropDataAvailable
14395 guint protocol_version:4;
14401 gchar *data_type; /* MIME type */
14402 gulong data_numbytes;
14408 struct _GdkEventClient
14413 GdkAtom message_type;
14414 gushort data_format;
14422 struct _GdkEventOther
14431 <!-- ***************************************************************** -->
14432 <sect> Code Examples
14433 <!-- ***************************************************************** -->
14435 Below are the code examples that are used in the above text
14436 which are not included in complete form elsewhere.
14438 <!-- ----------------------------------------------------------------- -->
14440 <!-- ----------------------------------------------------------------- -->
14444 /* example-start tictactoe tictactoe.h */
14446 /* GTK - The GIMP Toolkit
14447 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
14449 * This library is free software; you can redistribute it and/or
14450 * modify it under the terms of the GNU Library General Public
14451 * License as published by the Free Software Foundation; either
14452 * version 2 of the License, or (at your option) any later version.
14454 * This library is distributed in the hope that it will be useful,
14455 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14456 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14457 * Library General Public License for more details.
14459 * You should have received a copy of the GNU Library General Public
14460 * License along with this library; if not, write to the
14461 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14462 * Boston, MA 02111-1307, USA.
14464 #ifndef __TICTACTOE_H__
14465 #define __TICTACTOE_H__
14468 #include <gdk/gdk.h>
14469 #include <gtk/gtkvbox.h>
14474 #endif /* __cplusplus */
14476 #define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
14477 #define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
14478 #define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
14481 typedef struct _Tictactoe Tictactoe;
14482 typedef struct _TictactoeClass TictactoeClass;
14488 GtkWidget *buttons[3][3];
14491 struct _TictactoeClass
14493 GtkVBoxClass parent_class;
14495 void (* tictactoe) (Tictactoe *ttt);
14498 guint tictactoe_get_type (void);
14499 GtkWidget* tictactoe_new (void);
14500 void tictactoe_clear (Tictactoe *ttt);
14504 #endif /* __cplusplus */
14506 #endif /* __TICTACTOE_H__ */
14511 <!-- ----------------------------------------------------------------- -->
14515 /* example-start tictactoe tictactoe.c */
14517 /* GTK - The GIMP Toolkit
14518 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
14520 * This library is free software; you can redistribute it and/or
14521 * modify it under the terms of the GNU Library General Public
14522 * License as published by the Free Software Foundation; either
14523 * version 2 of the License, or (at your option) any later version.
14525 * This library is distributed in the hope that it will be useful,
14526 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14527 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14528 * Library General Public License for more details.
14530 * You should have received a copy of the GNU Library General Public
14531 * License along with this library; if not, write to the
14532 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14533 * Boston, MA 02111-1307, USA.
14535 #include "gtk/gtksignal.h"
14536 #include "gtk/gtktable.h"
14537 #include "gtk/gtktogglebutton.h"
14538 #include "tictactoe.h"
14545 static void tictactoe_class_init (TictactoeClass *klass);
14546 static void tictactoe_init (Tictactoe *ttt);
14547 static void tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt);
14549 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
14552 tictactoe_get_type ()
14554 static guint ttt_type = 0;
14558 GtkTypeInfo ttt_info =
14561 sizeof (Tictactoe),
14562 sizeof (TictactoeClass),
14563 (GtkClassInitFunc) tictactoe_class_init,
14564 (GtkObjectInitFunc) tictactoe_init,
14565 (GtkArgSetFunc) NULL,
14566 (GtkArgGetFunc) NULL
14569 ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
14576 tictactoe_class_init (TictactoeClass *class)
14578 GtkObjectClass *object_class;
14580 object_class = (GtkObjectClass*) class;
14582 tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
14584 object_class->type,
14585 GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
14586 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
14589 gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
14591 class->tictactoe = NULL;
14595 tictactoe_init (Tictactoe *ttt)
14600 table = gtk_table_new (3, 3, TRUE);
14601 gtk_container_add (GTK_CONTAINER(ttt), table);
14602 gtk_widget_show (table);
14607 ttt->buttons[i][j] = gtk_toggle_button_new ();
14608 gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
14610 gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
14611 GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
14612 gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
14613 gtk_widget_show (ttt->buttons[i][j]);
14620 return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
14624 tictactoe_clear (Tictactoe *ttt)
14631 gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
14632 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
14634 gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
14639 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
14643 static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
14644 { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
14645 { 0, 1, 2 }, { 0, 1, 2 } };
14646 static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
14647 { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
14648 { 0, 1, 2 }, { 2, 1, 0 } };
14650 int success, found;
14652 for (k=0; k<8; k++)
14659 success = success &&
14660 GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
14662 ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
14665 if (success && found)
14667 gtk_signal_emit (GTK_OBJECT (ttt),
14668 tictactoe_signals[TICTACTOE_SIGNAL]);
14677 <!-- ----------------------------------------------------------------- -->
14681 /* example-start tictactoe ttt_test.c */
14683 #include <gtk/gtk.h>
14684 #include "tictactoe.h"
14687 win (GtkWidget *widget, gpointer data)
14689 g_print ("Yay!\n");
14690 tictactoe_clear (TICTACTOE (widget));
14694 main (int argc, char *argv[])
14699 gtk_init (&argc, &argv);
14701 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
14703 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
14705 gtk_signal_connect (GTK_OBJECT (window), "destroy",
14706 GTK_SIGNAL_FUNC (gtk_exit), NULL);
14708 gtk_container_border_width (GTK_CONTAINER (window), 10);
14710 ttt = tictactoe_new ();
14712 gtk_container_add (GTK_CONTAINER (window), ttt);
14713 gtk_widget_show (ttt);
14715 gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
14716 GTK_SIGNAL_FUNC (win), NULL);
14718 gtk_widget_show (window);
14728 <!-- ----------------------------------------------------------------- -->
14731 <!-- ----------------------------------------------------------------- -->
14735 /* example-start gtkdial gtkdial.h */
14737 /* GTK - The GIMP Toolkit
14738 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
14740 * This library is free software; you can redistribute it and/or
14741 * modify it under the terms of the GNU Library General Public
14742 * License as published by the Free Software Foundation; either
14743 * version 2 of the License, or (at your option) any later version.
14745 * This library is distributed in the hope that it will be useful,
14746 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14747 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14748 * Library General Public License for more details.
14750 * You should have received a copy of the GNU Library General Public
14751 * License along with this library; if not, write to the
14752 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14753 * Boston, MA 02111-1307, USA.
14755 #ifndef __GTK_DIAL_H__
14756 #define __GTK_DIAL_H__
14759 #include <gdk/gdk.h>
14760 #include <gtk/gtkadjustment.h>
14761 #include <gtk/gtkwidget.h>
14766 #endif /* __cplusplus */
14769 #define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
14770 #define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
14771 #define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
14774 typedef struct _GtkDial GtkDial;
14775 typedef struct _GtkDialClass GtkDialClass;
14781 /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
14784 /* Button currently pressed or 0 if none */
14787 /* Dimensions of dial components */
14789 gint pointer_width;
14791 /* ID of update timer, or 0 if none */
14794 /* Current angle */
14797 /* Old values from adjustment stored so we know when something changes */
14802 /* The adjustment object that stores the data for this dial */
14803 GtkAdjustment *adjustment;
14806 struct _GtkDialClass
14808 GtkWidgetClass parent_class;
14812 GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
14813 guint gtk_dial_get_type (void);
14814 GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
14815 void gtk_dial_set_update_policy (GtkDial *dial,
14816 GtkUpdateType policy);
14818 void gtk_dial_set_adjustment (GtkDial *dial,
14819 GtkAdjustment *adjustment);
14822 #endif /* __cplusplus */
14825 #endif /* __GTK_DIAL_H__ */
14829 <!-- ----------------------------------------------------------------- -->
14833 /* example-start gtkdial gtkdial.c */
14835 /* GTK - The GIMP Toolkit
14836 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
14838 * This library is free software; you can redistribute it and/or
14839 * modify it under the terms of the GNU Library General Public
14840 * License as published by the Free Software Foundation; either
14841 * version 2 of the License, or (at your option) any later version.
14843 * This library is distributed in the hope that it will be useful,
14844 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14845 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14846 * Library General Public License for more details.
14848 * You should have received a copy of the GNU Library General Public
14849 * License along with this library; if not, write to the
14850 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14851 * Boston, MA 02111-1307, USA.
14855 #include <gtk/gtkmain.h>
14856 #include <gtk/gtksignal.h>
14858 #include "gtkdial.h"
14860 #define SCROLL_DELAY_LENGTH 300
14861 #define DIAL_DEFAULT_SIZE 100
14863 /* Forward declarations */
14865 static void gtk_dial_class_init (GtkDialClass *klass);
14866 static void gtk_dial_init (GtkDial *dial);
14867 static void gtk_dial_destroy (GtkObject *object);
14868 static void gtk_dial_realize (GtkWidget *widget);
14869 static void gtk_dial_size_request (GtkWidget *widget,
14870 GtkRequisition *requisition);
14871 static void gtk_dial_size_allocate (GtkWidget *widget,
14872 GtkAllocation *allocation);
14873 static gint gtk_dial_expose (GtkWidget *widget,
14874 GdkEventExpose *event);
14875 static gint gtk_dial_button_press (GtkWidget *widget,
14876 GdkEventButton *event);
14877 static gint gtk_dial_button_release (GtkWidget *widget,
14878 GdkEventButton *event);
14879 static gint gtk_dial_motion_notify (GtkWidget *widget,
14880 GdkEventMotion *event);
14881 static gint gtk_dial_timer (GtkDial *dial);
14883 static void gtk_dial_update_mouse (GtkDial *dial, gint x, gint y);
14884 static void gtk_dial_update (GtkDial *dial);
14885 static void gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
14887 static void gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
14892 static GtkWidgetClass *parent_class = NULL;
14895 gtk_dial_get_type ()
14897 static guint dial_type = 0;
14901 GtkTypeInfo dial_info =
14905 sizeof (GtkDialClass),
14906 (GtkClassInitFunc) gtk_dial_class_init,
14907 (GtkObjectInitFunc) gtk_dial_init,
14908 (GtkArgSetFunc) NULL,
14909 (GtkArgGetFunc) NULL,
14912 dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info);
14919 gtk_dial_class_init (GtkDialClass *class)
14921 GtkObjectClass *object_class;
14922 GtkWidgetClass *widget_class;
14924 object_class = (GtkObjectClass*) class;
14925 widget_class = (GtkWidgetClass*) class;
14927 parent_class = gtk_type_class (gtk_widget_get_type ());
14929 object_class->destroy = gtk_dial_destroy;
14931 widget_class->realize = gtk_dial_realize;
14932 widget_class->expose_event = gtk_dial_expose;
14933 widget_class->size_request = gtk_dial_size_request;
14934 widget_class->size_allocate = gtk_dial_size_allocate;
14935 widget_class->button_press_event = gtk_dial_button_press;
14936 widget_class->button_release_event = gtk_dial_button_release;
14937 widget_class->motion_notify_event = gtk_dial_motion_notify;
14941 gtk_dial_init (GtkDial *dial)
14944 dial->policy = GTK_UPDATE_CONTINUOUS;
14947 dial->pointer_width = 0;
14949 dial->old_value = 0.0;
14950 dial->old_lower = 0.0;
14951 dial->old_upper = 0.0;
14952 dial->adjustment = NULL;
14956 gtk_dial_new (GtkAdjustment *adjustment)
14960 dial = gtk_type_new (gtk_dial_get_type ());
14963 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
14965 gtk_dial_set_adjustment (dial, adjustment);
14967 return GTK_WIDGET (dial);
14971 gtk_dial_destroy (GtkObject *object)
14975 g_return_if_fail (object != NULL);
14976 g_return_if_fail (GTK_IS_DIAL (object));
14978 dial = GTK_DIAL (object);
14980 if (dial->adjustment)
14981 gtk_object_unref (GTK_OBJECT (dial->adjustment));
14983 if (GTK_OBJECT_CLASS (parent_class)->destroy)
14984 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
14988 gtk_dial_get_adjustment (GtkDial *dial)
14990 g_return_val_if_fail (dial != NULL, NULL);
14991 g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
14993 return dial->adjustment;
14997 gtk_dial_set_update_policy (GtkDial *dial,
14998 GtkUpdateType policy)
15000 g_return_if_fail (dial != NULL);
15001 g_return_if_fail (GTK_IS_DIAL (dial));
15003 dial->policy = policy;
15007 gtk_dial_set_adjustment (GtkDial *dial,
15008 GtkAdjustment *adjustment)
15010 g_return_if_fail (dial != NULL);
15011 g_return_if_fail (GTK_IS_DIAL (dial));
15013 if (dial->adjustment)
15015 gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
15016 gtk_object_unref (GTK_OBJECT (dial->adjustment));
15019 dial->adjustment = adjustment;
15020 gtk_object_ref (GTK_OBJECT (dial->adjustment));
15022 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
15023 (GtkSignalFunc) gtk_dial_adjustment_changed,
15025 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
15026 (GtkSignalFunc) gtk_dial_adjustment_value_changed,
15029 dial->old_value = adjustment->value;
15030 dial->old_lower = adjustment->lower;
15031 dial->old_upper = adjustment->upper;
15033 gtk_dial_update (dial);
15037 gtk_dial_realize (GtkWidget *widget)
15040 GdkWindowAttr attributes;
15041 gint attributes_mask;
15043 g_return_if_fail (widget != NULL);
15044 g_return_if_fail (GTK_IS_DIAL (widget));
15046 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
15047 dial = GTK_DIAL (widget);
15049 attributes.x = widget->allocation.x;
15050 attributes.y = widget->allocation.y;
15051 attributes.width = widget->allocation.width;
15052 attributes.height = widget->allocation.height;
15053 attributes.wclass = GDK_INPUT_OUTPUT;
15054 attributes.window_type = GDK_WINDOW_CHILD;
15055 attributes.event_mask = gtk_widget_get_events (widget) |
15056 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
15057 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
15058 GDK_POINTER_MOTION_HINT_MASK;
15059 attributes.visual = gtk_widget_get_visual (widget);
15060 attributes.colormap = gtk_widget_get_colormap (widget);
15062 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
15063 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
15065 widget->style = gtk_style_attach (widget->style, widget->window);
15067 gdk_window_set_user_data (widget->window, widget);
15069 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
15073 gtk_dial_size_request (GtkWidget *widget,
15074 GtkRequisition *requisition)
15076 requisition->width = DIAL_DEFAULT_SIZE;
15077 requisition->height = DIAL_DEFAULT_SIZE;
15081 gtk_dial_size_allocate (GtkWidget *widget,
15082 GtkAllocation *allocation)
15086 g_return_if_fail (widget != NULL);
15087 g_return_if_fail (GTK_IS_DIAL (widget));
15088 g_return_if_fail (allocation != NULL);
15090 widget->allocation = *allocation;
15091 dial = GTK_DIAL (widget);
15093 if (GTK_WIDGET_REALIZED (widget))
15096 gdk_window_move_resize (widget->window,
15097 allocation->x, allocation->y,
15098 allocation->width, allocation->height);
15101 dial->radius = MIN(allocation->width,allocation->height) * 0.45;
15102 dial->pointer_width = dial->radius / 5;
15106 gtk_dial_expose (GtkWidget *widget,
15107 GdkEventExpose *event)
15110 GdkPoint points[3];
15117 g_return_val_if_fail (widget != NULL, FALSE);
15118 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
15119 g_return_val_if_fail (event != NULL, FALSE);
15121 if (event->count > 0)
15124 dial = GTK_DIAL (widget);
15126 gdk_window_clear_area (widget->window,
15128 widget->allocation.width,
15129 widget->allocation.height);
15131 xc = widget->allocation.width/2;
15132 yc = widget->allocation.height/2;
15136 for (i=0; i<25; i++)
15138 theta = (i*M_PI/18. - M_PI/6.);
15142 tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
15144 gdk_draw_line (widget->window,
15145 widget->style->fg_gc[widget->state],
15146 xc + c*(dial->radius - tick_length),
15147 yc - s*(dial->radius - tick_length),
15148 xc + c*dial->radius,
15149 yc - s*dial->radius);
15154 s = sin(dial->angle);
15155 c = cos(dial->angle);
15158 points[0].x = xc + s*dial->pointer_width/2;
15159 points[0].y = yc + c*dial->pointer_width/2;
15160 points[1].x = xc + c*dial->radius;
15161 points[1].y = yc - s*dial->radius;
15162 points[2].x = xc - s*dial->pointer_width/2;
15163 points[2].y = yc - c*dial->pointer_width/2;
15165 gtk_draw_polygon (widget->style,
15176 gtk_dial_button_press (GtkWidget *widget,
15177 GdkEventButton *event)
15183 double d_perpendicular;
15185 g_return_val_if_fail (widget != NULL, FALSE);
15186 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
15187 g_return_val_if_fail (event != NULL, FALSE);
15189 dial = GTK_DIAL (widget);
15191 /* Determine if button press was within pointer region - we
15192 do this by computing the parallel and perpendicular distance of
15193 the point where the mouse was pressed from the line passing through
15196 dx = event->x - widget->allocation.width / 2;
15197 dy = widget->allocation.height / 2 - event->y;
15199 s = sin(dial->angle);
15200 c = cos(dial->angle);
15202 d_parallel = s*dy + c*dx;
15203 d_perpendicular = fabs(s*dx - c*dy);
15205 if (!dial->button &&
15206 (d_perpendicular < dial->pointer_width/2) &&
15207 (d_parallel > - dial->pointer_width))
15209 gtk_grab_add (widget);
15211 dial->button = event->button;
15213 gtk_dial_update_mouse (dial, event->x, event->y);
15220 gtk_dial_button_release (GtkWidget *widget,
15221 GdkEventButton *event)
15225 g_return_val_if_fail (widget != NULL, FALSE);
15226 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
15227 g_return_val_if_fail (event != NULL, FALSE);
15229 dial = GTK_DIAL (widget);
15231 if (dial->button == event->button)
15233 gtk_grab_remove (widget);
15237 if (dial->policy == GTK_UPDATE_DELAYED)
15238 gtk_timeout_remove (dial->timer);
15240 if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
15241 (dial->old_value != dial->adjustment->value))
15242 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
15249 gtk_dial_motion_notify (GtkWidget *widget,
15250 GdkEventMotion *event)
15253 GdkModifierType mods;
15256 g_return_val_if_fail (widget != NULL, FALSE);
15257 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
15258 g_return_val_if_fail (event != NULL, FALSE);
15260 dial = GTK_DIAL (widget);
15262 if (dial->button != 0)
15267 if (event->is_hint || (event->window != widget->window))
15268 gdk_window_get_pointer (widget->window, &x, &y, &mods);
15270 switch (dial->button)
15273 mask = GDK_BUTTON1_MASK;
15276 mask = GDK_BUTTON2_MASK;
15279 mask = GDK_BUTTON3_MASK;
15286 if (mods & mask)
15287 gtk_dial_update_mouse (dial, x,y);
15294 gtk_dial_timer (GtkDial *dial)
15296 g_return_val_if_fail (dial != NULL, FALSE);
15297 g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
15299 if (dial->policy == GTK_UPDATE_DELAYED)
15300 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
15306 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
15311 g_return_if_fail (dial != NULL);
15312 g_return_if_fail (GTK_IS_DIAL (dial));
15314 xc = GTK_WIDGET(dial)->allocation.width / 2;
15315 yc = GTK_WIDGET(dial)->allocation.height / 2;
15317 old_value = dial->adjustment->value;
15318 dial->angle = atan2(yc-y, x-xc);
15320 if (dial->angle < -M_PI/2.)
15321 dial->angle += 2*M_PI;
15323 if (dial->angle < -M_PI/6)
15324 dial->angle = -M_PI/6;
15326 if (dial->angle > 7.*M_PI/6.)
15327 dial->angle = 7.*M_PI/6.;
15329 dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
15330 (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
15332 if (dial->adjustment->value != old_value)
15334 if (dial->policy == GTK_UPDATE_CONTINUOUS)
15336 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
15340 gtk_widget_draw (GTK_WIDGET(dial), NULL);
15342 if (dial->policy == GTK_UPDATE_DELAYED)
15345 gtk_timeout_remove (dial->timer);
15347 dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
15348 (GtkFunction) gtk_dial_timer,
15356 gtk_dial_update (GtkDial *dial)
15360 g_return_if_fail (dial != NULL);
15361 g_return_if_fail (GTK_IS_DIAL (dial));
15363 new_value = dial->adjustment->value;
15365 if (new_value < dial->adjustment->lower)
15366 new_value = dial->adjustment->lower;
15368 if (new_value > dial->adjustment->upper)
15369 new_value = dial->adjustment->upper;
15371 if (new_value != dial->adjustment->value)
15373 dial->adjustment->value = new_value;
15374 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
15377 dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
15378 (dial->adjustment->upper - dial->adjustment->lower);
15380 gtk_widget_draw (GTK_WIDGET(dial), NULL);
15384 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
15389 g_return_if_fail (adjustment != NULL);
15390 g_return_if_fail (data != NULL);
15392 dial = GTK_DIAL (data);
15394 if ((dial->old_value != adjustment->value) ||
15395 (dial->old_lower != adjustment->lower) ||
15396 (dial->old_upper != adjustment->upper))
15398 gtk_dial_update (dial);
15400 dial->old_value = adjustment->value;
15401 dial->old_lower = adjustment->lower;
15402 dial->old_upper = adjustment->upper;
15407 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
15412 g_return_if_fail (adjustment != NULL);
15413 g_return_if_fail (data != NULL);
15415 dial = GTK_DIAL (data);
15417 if (dial->old_value != adjustment->value)
15419 gtk_dial_update (dial);
15421 dial->old_value = adjustment->value;
15427 <!-- ----------------------------------------------------------------- -->
15431 /* example-start scribble-simple scribble-simple.c */
15433 /* GTK - The GIMP Toolkit
15434 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15436 * This library is free software; you can redistribute it and/or
15437 * modify it under the terms of the GNU Library General Public
15438 * License as published by the Free Software Foundation; either
15439 * version 2 of the License, or (at your option) any later version.
15441 * This library is distributed in the hope that it will be useful,
15442 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15443 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15444 * Library General Public License for more details.
15446 * You should have received a copy of the GNU Library General Public
15447 * License along with this library; if not, write to the
15448 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15449 * Boston, MA 02111-1307, USA.
15452 #include <gtk/gtk.h>
15454 /* Backing pixmap for drawing area */
15455 static GdkPixmap *pixmap = NULL;
15457 /* Create a new backing pixmap of the appropriate size */
15459 configure_event (GtkWidget *widget, GdkEventConfigure *event)
15462 gdk_pixmap_unref(pixmap);
15464 pixmap = gdk_pixmap_new(widget->window,
15465 widget->allocation.width,
15466 widget->allocation.height,
15468 gdk_draw_rectangle (pixmap,
15469 widget->style->white_gc,
15472 widget->allocation.width,
15473 widget->allocation.height);
15478 /* Redraw the screen from the backing pixmap */
15480 expose_event (GtkWidget *widget, GdkEventExpose *event)
15482 gdk_draw_pixmap(widget->window,
15483 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
15485 event->area.x, event->area.y,
15486 event->area.x, event->area.y,
15487 event->area.width, event->area.height);
15492 /* Draw a rectangle on the screen */
15494 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
15496 GdkRectangle update_rect;
15498 update_rect.x = x - 5;
15499 update_rect.y = y - 5;
15500 update_rect.width = 10;
15501 update_rect.height = 10;
15502 gdk_draw_rectangle (pixmap,
15503 widget->style->black_gc,
15505 update_rect.x, update_rect.y,
15506 update_rect.width, update_rect.height);
15507 gtk_widget_draw (widget, &update_rect);
15511 button_press_event (GtkWidget *widget, GdkEventButton *event)
15513 if (event->button == 1 && pixmap != NULL)
15514 draw_brush (widget, event->x, event->y);
15520 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
15523 GdkModifierType state;
15525 if (event->is_hint)
15526 gdk_window_get_pointer (event->window, &x, &y, &state);
15531 state = event->state;
15534 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
15535 draw_brush (widget, x, y);
15547 main (int argc, char *argv[])
15550 GtkWidget *drawing_area;
15555 gtk_init (&argc, &argv);
15557 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
15558 gtk_widget_set_name (window, "Test Input");
15560 vbox = gtk_vbox_new (FALSE, 0);
15561 gtk_container_add (GTK_CONTAINER (window), vbox);
15562 gtk_widget_show (vbox);
15564 gtk_signal_connect (GTK_OBJECT (window), "destroy",
15565 GTK_SIGNAL_FUNC (quit), NULL);
15567 /* Create the drawing area */
15569 drawing_area = gtk_drawing_area_new ();
15570 gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200);
15571 gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
15573 gtk_widget_show (drawing_area);
15575 /* Signals used to handle backing pixmap */
15577 gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
15578 (GtkSignalFunc) expose_event, NULL);
15579 gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
15580 (GtkSignalFunc) configure_event, NULL);
15582 /* Event signals */
15584 gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
15585 (GtkSignalFunc) motion_notify_event, NULL);
15586 gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
15587 (GtkSignalFunc) button_press_event, NULL);
15589 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
15590 | GDK_LEAVE_NOTIFY_MASK
15591 | GDK_BUTTON_PRESS_MASK
15592 | GDK_POINTER_MOTION_MASK
15593 | GDK_POINTER_MOTION_HINT_MASK);
15595 /* .. And a quit button */
15596 button = gtk_button_new_with_label ("Quit");
15597 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
15599 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
15600 GTK_SIGNAL_FUNC (gtk_widget_destroy),
15601 GTK_OBJECT (window));
15602 gtk_widget_show (button);
15604 gtk_widget_show (window);