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 6th, 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
43 are 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
50 of C, and how to create C programs. It would be a great benefit for
51 the reader to have previous X programming experience, but it shouldn't
52 be necessary. If you are learning GTK as your first widget set,
53 please comment on how you found this tutorial, and what you had
54 trouble with. Note that there is also a C++ API for GTK (GTK--) in
55 the works, 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 I would very much like to hear of any problems you have learning GTK
60 from this document, and would appreciate input as to how it may be
61 improved. Please see the section on <ref id="sec_Contributing"
62 name="Contributing"> for further information.
64 <!-- ***************************************************************** -->
66 <!-- ***************************************************************** -->
69 The first thing to do of course, is download the GTK source and
70 install it. You can always get the latest version from ftp.gtk.org in
71 /pub/gtk. You can also view other sources of GTK information on
72 http://www.gtk.org/ <htmlurl url="http://www.gtk.org/"
73 name="http://www.gtk.org/">. GTK uses GNU autoconf for configuration.
74 Once untar'd, type ./configure --help to see a list of options.
76 Th GTK source distribution also contains the complete source to all of
77 the examples used in this tutorial, along with Makefiles to aid
80 To begin our introduction to GTK, we'll start with the simplest
81 program possible. This program will create a 200x200 pixel window and
82 has no way of exiting except to be killed using the shell.
85 /* example-start base base.c */
94 gtk_init (&argc, &argv);
96 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
97 gtk_widget_show (window);
106 You can compile the above program with gcc using:
108 gcc base.c -o base `gtk-config --cflags --libs`
111 The meaning of the unusual compilation options is explained below.
113 All programs will of course include gtk/gtk.h which declares the
114 variables, functions, structures etc. that will be used in your GTK
120 gtk_init (&argc, &argv);
123 calls the function gtk_init(gint *argc, gchar ***argv) which will be
124 called in all GTK applications. This sets up a few things for us such
125 as the default visual and color map and then proceeds to call
126 gdk_init(gint *argc, gchar ***argv). This function initializes the
127 library for use, sets up default signal handlers, and checks the
128 arguments passed to your application on the command line, looking for
129 one of the following:
132 <item> <tt/--gtk-module/
133 <item> <tt/--g-fatal-warnings/
134 <item> <tt/--gtk-debug/
135 <item> <tt/--gtk-no-debug/
136 <item> <tt/--gdk-debug/
137 <item> <tt/--gdk-no-debug/
138 <item> <tt/--display/
140 <item> <tt/--no-xshm/
145 It removes these from the argument list, leaving anything it does not
146 recognize for your application to parse or ignore. This creates a set
147 of standard arguments accepted by all GTK applications.
149 The next two lines of code create and display a window.
152 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
153 gtk_widget_show (window);
156 The GTK_WINDOW_TOPLEVEL argument specifies that we want the window to
157 undergo window manager decoration and placement. Rather than create a
158 window of 0x0 size, a window without children is set to 200x200 by
159 default so you can still manipulate it.
161 The gtk_widget_show() function lets GTK know that we are done setting
162 the attributes of this widget, and that it can display it.
164 The last line enters the GTK main processing loop.
170 gtk_main() is another call you will see in every GTK application.
171 When control reaches this point, GTK will sleep waiting for X events
172 (such as button or key presses), timeouts, or file IO notifications to
173 occur. In our simple example however, events are ignored.
175 <!-- ----------------------------------------------------------------- -->
176 <sect1>Hello World in GTK
178 Now for a program with a widget (a button). It's the classic
179 hello world a la GTK.
182 /* example-start helloworld helloworld.c */
186 /* This is a callback function. The data arguments are ignored
187 * in this example. More on callbacks below. */
188 void hello( GtkWidget *widget,
191 g_print ("Hello World\n");
194 gint delete_event( GtkWidget *widget,
198 /* If you return FALSE in the "delete_event" signal handler,
199 * GTK will emit the "destroy" signal. Returning TRUE means
200 * you don't want the window to be destroyed.
201 * This is useful for popping up 'are you sure you want to quit?'
204 g_print ("delete event occurred\n");
206 /* Change TRUE to FALSE and the main window will be destroyed with
207 * a "delete_event". */
212 /* Another callback */
213 void destroy( GtkWidget *widget,
222 /* GtkWidget is the storage type for widgets */
226 /* This is called in all GTK applications. Arguments are parsed
227 * from the command line and are returned to the application. */
228 gtk_init(&argc, &argv);
230 /* create a new window */
231 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
233 /* When the window is given the "delete_event" signal (this is given
234 * by the window manager, usually by the 'close' option, or on the
235 * titlebar), we ask it to call the delete_event () function
236 * as defined above. The data passed to the callback
237 * function is NULL and is ignored in the callback function. */
238 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
239 GTK_SIGNAL_FUNC (delete_event), NULL);
241 /* Here we connect the "destroy" event to a signal handler.
242 * This event occurs when we call gtk_widget_destroy() on the window,
243 * or if we return 'FALSE' in the "delete_event" callback. */
244 gtk_signal_connect (GTK_OBJECT (window), "destroy",
245 GTK_SIGNAL_FUNC (destroy), NULL);
247 /* Sets the border width of the window. */
248 gtk_container_border_width (GTK_CONTAINER (window), 10);
250 /* Creates a new button with the label "Hello World". */
251 button = gtk_button_new_with_label ("Hello World");
253 /* When the button receives the "clicked" signal, it will call the
254 * function hello() passing it NULL as its argument. The hello()
255 * function is defined above. */
256 gtk_signal_connect (GTK_OBJECT (button), "clicked",
257 GTK_SIGNAL_FUNC (hello), NULL);
259 /* This will cause the window to be destroyed by calling
260 * gtk_widget_destroy(window) when "clicked". Again, the destroy
261 * signal could come from here, or the window manager. */
262 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
263 GTK_SIGNAL_FUNC (gtk_widget_destroy),
264 GTK_OBJECT (window));
266 /* This packs the button into the window (a gtk container). */
267 gtk_container_add (GTK_CONTAINER (window), button);
269 /* The final step is to display this newly created widget. */
270 gtk_widget_show (button);
273 gtk_widget_show (window);
275 /* All GTK applications must have a gtk_main(). Control ends here
276 * and waits for an event to occur (like a key press or
285 <!-- ----------------------------------------------------------------- -->
286 <sect1>Compiling Hello World
291 gcc -Wall -g helloworld.c -o helloworld `gtk-config --cflags` \
295 This uses the program <tt>gtk-config</>, which comes with gtk. This
296 program 'knows' what compiler switches are needed to compile programs
297 that use gtk. <tt>gtk-config --cflags</> will output a list of include
298 directories for the compiler to look in, and <tt>gtk-config --libs</>
299 will output the list of libraries for the compiler to link with and
300 the directories to find them in. In the aboce example they could have
301 been combined into a single instance, such as
302 `gtk-config --cflags --libs`.
304 Note that the type of single quote used in the compile command above
307 The libraries that are usually linked in are:
309 <item>The GTK library (-lgtk), the widget library, based on top of GDK.
310 <item>The GDK library (-lgdk), the Xlib wrapper.
311 <item>The gmodule library (-lgmodule), which is used to load run time
313 <item>The glib library (-lglib), containing miscellaneous functions, only
314 g_print() is used in this particular example. GTK is built on top
315 of glib so you will always require this library. See the section on
316 <ref id="sec_glib" name="glib"> for details.
317 <item>The Xlib library (-lX11) which is used by GDK.
318 <item>The Xext library (-lXext). This contains code for shared memory
319 pixmaps and other X extensions.
320 <item>The math library (-lm). This is used by GTK for various purposes.
323 <!-- ----------------------------------------------------------------- -->
324 <sect1>Theory of Signals and Callbacks
326 Before we look in detail at <em>helloworld</em>, we'll discuss signals
327 and callbacks. GTK is an event driven toolkit, which means it will
328 sleep in gtk_main until an event occurs and control is passed to the
329 appropriate function.
331 This passing of control is done using the idea of "signals". When an
332 event occurs, such as the press of a mouse button, the appropriate
333 signal will be "emitted" by the widget that was pressed. This is how
334 GTK does most of its useful work. There are a set of signals that all
335 widgets inherit, such as "destroy", and there are signals that are
336 widget specific, such as "toggled" on a toggle button.
338 To make a button perform an action, we set up a signal handler to
339 catch these signals and call the appropriate function. This is done by
340 using a function such as:
343 gint gtk_signal_connect( GtkObject *object,
346 gpointer func_data );
349 Where the first argument is the widget which will be emitting the
350 signal, and the second, the name of the signal you wish to catch. The
351 third is the function you wish to be called when it is caught, and the
352 fourth, the data you wish to have passed to this function.
354 The function specified in the third argument is called a "callback
355 function", and should generally be of the form:
358 void callback_func( GtkWidget *widget,
359 gpointer callback_data );
362 Where the first argument will be a pointer to the widget that emitted
363 the signal, and the second, a pointer to the data given as the last
364 argument to the gtk_signal_connect() function as shown above.
366 Note that the above form for a signal callback function declaration is
367 only a general guide, as some widget specific signals generate
368 different calling parameters. For example, the GtkCList "select_row"
369 signal provides both row and column parameters.
371 Another call used in the <em>helloworld</em> example, is:
374 gint gtk_signal_connect_object( GtkObject *object,
377 GtkObject *slot_object );
380 gtk_signal_connect_object() is the same as gtk_signal_connect() except
381 that the callback function only uses one argument, a pointer to a GTK
382 object. So when using this function to connect signals, the callback
383 should be of the form:
386 void callback_func( GtkObject *object );
389 Where the object is usually a widget. We usually don't setup callbacks
390 for gtk_signal_connect_object however. They are usually used to call a
391 GTK function that accepts a single widget or object as an argument, as
392 is the case in our <em>helloworld</em> example.
394 The purpose of having two functions to connect signals is simply to
395 allow the callbacks to have a different number of arguments. Many
396 functions in the GTK library accept only a single GtkWidget pointer as
397 an argument, so you want to use the gtk_signal_connect_object() for
398 these, whereas for your functions, you may need to have additional
399 data supplied to the callbacks.
401 <!-- ----------------------------------------------------------------- -->
404 In addition to the signal mechanism described above, there are a set
405 of <em>events</em> that reflect the X event mechanism. Callbacks may
406 also be attached to these events. These events are:
410 <item> button_press_event
411 <item> button_release_event
412 <item> motion_notify_event
416 <item> key_press_event
417 <item> key_release_event
418 <item> enter_notify_event
419 <item> leave_notify_event
420 <item> configure_event
421 <item> focus_in_event
422 <item> focus_out_event
425 <item> property_notify_event
426 <item> selection_clear_event
427 <item> selection_request_event
428 <item> selection_notify_event
429 <item> proximity_in_event
430 <item> proximity_out_event
431 <item> drag_begin_event
432 <item> drag_request_event
433 <item> drag_end_event
434 <item> drop_enter_event
435 <item> drop_leave_event
436 <item> drop_data_available_event
440 In order to connect a callback function to one of these events, you
441 use the function gtk_signal_connect, as described above, using one of
442 the above event names as the <tt/name/ parameter. The callback
443 function for events has a slightly different form than that for
447 void callback_func( GtkWidget *widget,
449 gpointer callback_data );
452 GdkEvent is a C <tt/union/ structure whose type will depend upon which
453 of the above events has occurred. In order for us to tell which event
454 has been issued each of the possible alternatives has a <tt/type/
455 parameter which reflects the event being issued. The other components
456 of the event structure will depend upon the type of the
457 event. Possible values for the type are:
479 GDK_SELECTION_REQUEST
489 GDK_VISIBILITY_NOTIFY
491 GDK_OTHER_EVENT /* Deprecated, use filters instead */
494 So, to connect a callback function to one of these events we would use
498 gtk_signal_connect( GTK_OBJECT(button), "button_press_event",
499 GTK_SIGNAL_FUNC(button_press_callback),
503 This assumes that <tt/button/ is a GtkButton widget. Now, when the
504 mouse is over the button and a mouse button is pressed, the function
505 <tt/button_press_callback/ will be called. This function may be
509 static gint button_press_event (GtkWidget *widget,
510 GdkEventButton *event,
514 Note that we can declare the second argument as type
515 <tt/GdkEventButton/ as we know what type of event will occur for this
516 function to be called.
518 The value returned from this function indicates whether the event
519 should be propagated further by the GTK event handling
520 mechanism. Returning TRUE indicates that the event has been handled,
521 and that it should not propagate further. Returning FALSE continues
522 the normal event handling. See the section on
523 <ref id="sec_Adv_Events_and_Signals"
524 name="Advanced Event and Signal Handling"> for more details on this
527 For details on the GdkEvent data types, see the appendix entitled
528 <ref id="sec_GDK_Event_Types" name="GDK Event Types">.
530 <!-- ----------------------------------------------------------------- -->
531 <sect1>Stepping Through Hello World
533 Now that we know the theory behind this, lets clarify by walking through
534 the example <em>helloworld</em> program.
536 Here is the callback function that will be called when the button is
537 "clicked". We ignore both the widget and the data in this example, but
538 it is not hard to do things with them. The next example will use the
539 data argument to tell us which button was pressed.
542 void hello( GtkWidget *widget,
545 g_print ("Hello World\n");
549 The next callback is a bit special. The "delete_event" occurs when the
550 window manager sends this event to the application. We have a choice
551 here as to what to do about these events. We can ignore them, make
552 some sort of response, or simply quit the application.
554 The value you return in this callback lets GTK know what action to
555 take. By returning TRUE, we let it know that we don't want to have
556 the "destroy" signal emitted, keeping our application running. By
557 returning FALSE, we ask that "destroy" is emitted, which in turn will
558 call our "destroy" signal handler.
561 gint delete_event( GtkWidget *widget,
565 g_print ("delete event occurred\n");
571 Here is another callback function which causes the program to quit by
572 calling gtk_main_quit(). This function tells GTK that it is to exit
573 from gtk_main when control is returned to it.
576 void destroy( GtkWidget *widget,
583 I assume you know about the main() function... yes, as with other
584 applications, all GTK applications will also have one of these.
592 This next part, declares a pointer to a structure of type
593 GtkWidget. These are used below to create a window and a button.
600 Here is our gtk_init again. As before, this initializes the toolkit,
601 and parses the arguments found on the command line. Any argument it
602 recognizes from the command line, it removes from the list, and
603 modifies argc and argv to make it look like they never existed,
604 allowing your application to parse the remaining arguments.
607 gtk_init (&argc, &argv);
610 Create a new window. This is fairly straight forward. Memory is
611 allocated for the GtkWidget *window structure so it now points to a
612 valid structure. It sets up a new window, but it is not displayed
613 until we call gtk_widget_show(window) near the end of our program.
616 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
619 Here is an example of connecting a signal handler to an object, in
620 this case, the window. Here, the "destroy" signal is caught. This is
621 emitted when we use the window manager to kill the window (and we
622 return TRUE in the "delete_event" handler), or when we use the
623 gtk_widget_destroy() call passing in the window widget as the object
624 to destroy. By setting this up, we handle both cases with a single
625 call. Here, it just calls the destroy() function defined above with a
626 NULL argument, which quits GTK for us.
628 The GTK_OBJECT and GTK_SIGNAL_FUNC are macros that perform type
629 casting and checking for us, as well as aid the readability of the
633 gtk_signal_connect (GTK_OBJECT (window), "destroy",
634 GTK_SIGNAL_FUNC (destroy), NULL);
637 This next function is used to set an attribute of a container object.
638 This just sets the window so it has a blank area along the inside of
639 it 10 pixels wide where no widgets will go. There are other similar
640 functions which we will look at in the section on
641 <ref id="sec_setting_widget_attributes" name="Setting Widget Attributes">
643 And again, GTK_CONTAINER is a macro to perform type casting.
646 gtk_container_border_width (GTK_CONTAINER (window), 10);
649 This call creates a new button. It allocates space for a new GtkWidget
650 structure in memory, initializes it, and makes the button pointer
651 point to it. It will have the label "Hello World" on it when
655 button = gtk_button_new_with_label ("Hello World");
658 Here, we take this button, and make it do something useful. We attach
659 a signal handler to it so when it emits the "clicked" signal, our
660 hello() function is called. The data is ignored, so we simply pass in
661 NULL to the hello() callback function. Obviously, the "clicked" signal
662 is emitted when we click the button with our mouse pointer.
665 gtk_signal_connect (GTK_OBJECT (button), "clicked",
666 GTK_SIGNAL_FUNC (hello), NULL);
669 We are also going to use this button to exit our program. This will
670 illustrate how the "destroy" signal may come from either the window
671 manager, or our program. When the button is "clicked", same as above,
672 it calls the first hello() callback function, and then this one in the
673 order they are set up. You may have as many callback functions as you
674 need, and all will be executed in the order you connected
675 them. Because the gtk_widget_destroy() function accepts only a
676 GtkWidget *widget as an argument, we use the
677 gtk_signal_connect_object() function here instead of straight
678 gtk_signal_connect().
681 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
682 GTK_SIGNAL_FUNC (gtk_widget_destroy),
683 GTK_OBJECT (window));
686 This is a packing call, which will be explained in depth later on. But
687 it is fairly easy to understand. It simply tells GTK that the button
688 is to be placed in the window where it will be displayed. Note that a
689 GTK container can only contain one widget. There are other widgets,
690 that are described later, which are designed to layout multiple
691 widgets in various ways.
694 gtk_container_add (GTK_CONTAINER (window), button);
697 Now we have everything set up the way we want it to be. With all the
698 signal handlers in place, and the button placed in the window where it
699 should be, we ask GTK to "show" the widgets on the screen. The window
700 widget is shown last so the whole window will pop up at once rather
701 than seeing the window pop up, and then the button form inside of
702 it. Although with such a simple example, you'd never notice.
705 gtk_widget_show (button);
707 gtk_widget_show (window);
710 And of course, we call gtk_main() which waits for events to come from
711 the X server and will call on the widgets to emit signals when these
718 And the final return. Control returns here after gtk_quit() is called.
724 Now, when we click the mouse button on a GTK button, the widget emits
725 a "clicked" signal. In order for us to use this information, our
726 program sets up a signal handler to catch that signal, which
727 dispatches the function of our choice. In our example, when the button
728 we created is "clicked", the hello() function is called with a NULL
729 argument, and then the next handler for this signal is called. This
730 calls the gtk_widget_destroy() function, passing it the window widget
731 as its argument, destroying the window widget. This causes the window
732 to emit the "destroy" signal, which is caught, and calls our destroy()
733 callback function, which simply exits GTK.
735 Another course of events, is to use the window manager to kill the
736 window. This will cause the "delete_event" to be emitted. This will
737 call our "delete_event" handler. If we return TRUE here, the window
738 will be left as is and nothing will happen. Returning FALSE will cause
739 GTK to emit the "destroy" signal which of course, calls the "destroy"
740 callback, exiting GTK.
742 Note that these signals are not the same as the Unix system signals,
743 and are not implemented using them, although the terminology is almost
746 <!-- ***************************************************************** -->
748 <!-- ***************************************************************** -->
750 <!-- ----------------------------------------------------------------- -->
753 There are a few things you probably noticed in the previous examples
754 that need explaining. The gint, gchar etc. that you see are typedefs
755 to int and char respectively. This is done to get around that nasty
756 dependency on the size of simple data types when doing calculations.
758 A good example is "gint32" which will be typedef'd to a 32 bit integer
759 for any given platform, whether it be the 64 bit alpha, or the 32 bit
760 i386. The typedefs are very straight forward and intuitive. They are
761 all defined in glib/glib.h (which gets included from gtk.h).
763 You'll also notice the ability to use GtkWidget when the function
764 calls for a GtkObject. GTK is an object oriented design, and a widget
767 <!-- ----------------------------------------------------------------- -->
768 <sect1>More on Signal Handlers
770 Lets take another look at the gtk_signal_connect declaration.
773 gint gtk_signal_connect( GtkObject *object,
776 gpointer func_data );
779 Notice the gint return value? This is a tag that identifies your
780 callback function. As stated above, you may have as many callbacks per
781 signal and per object as you need, and each will be executed in turn,
782 in the order they were attached.
784 This tag allows you to remove this callback from the list by using:
787 void gtk_signal_disconnect( GtkObject *object,
791 So, by passing in the widget you wish to remove the handler from, and
792 the tag returned by one of the signal_connect functions, you can
793 disconnect a signal handler.
795 Another function to remove all the signal handers from an object is:
798 void gtk_signal_handlers_destroy( GtkObject *object );
801 This call is fairly self explanatory. It simply removes all the
802 current signal handlers from the object passed in as the first
805 <!-- ----------------------------------------------------------------- -->
806 <sect1>An Upgraded Hello World
808 Let's take a look at a slightly improved <em>helloworld</em> with
809 better examples of callbacks. This will also introduce us to our next
810 topic, packing widgets.
813 /* example-start helloworld2 helloworld2.c */
817 /* Our new improved callback. The data passed to this function
818 * is printed to stdout. */
819 void callback( GtkWidget *widget,
822 g_print ("Hello again - %s was pressed\n", (char *) data);
825 /* another callback */
826 void delete_event( GtkWidget *widget,
836 /* GtkWidget is the storage type for widgets */
841 /* This is called in all GTK applications. Arguments are parsed
842 * from the command line and are returned to the application. */
843 gtk_init (&argc, &argv);
845 /* Create a new window */
846 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
848 /* This is a new call, this just sets the title of our
849 * new window to "Hello Buttons!" */
850 gtk_window_set_title (GTK_WINDOW (window), "Hello Buttons!");
852 /* Here we just set a handler for delete_event that immediately
854 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
855 GTK_SIGNAL_FUNC (delete_event), NULL);
857 /* Sets the border width of the window. */
858 gtk_container_border_width (GTK_CONTAINER (window), 10);
860 /* We create a box to pack widgets into. This is described in detail
861 * in the "packing" section. The box is not really visible, it
862 * is just used as a tool to arrange widgets. */
863 box1 = gtk_hbox_new(FALSE, 0);
865 /* Put the box into the main window. */
866 gtk_container_add (GTK_CONTAINER (window), box1);
868 /* Creates a new button with the label "Button 1". */
869 button = gtk_button_new_with_label ("Button 1");
871 /* Now when the button is clicked, we call the "callback" function
872 * with a pointer to "button 1" as its argument */
873 gtk_signal_connect (GTK_OBJECT (button), "clicked",
874 GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");
876 /* Instead of gtk_container_add, we pack this button into the invisible
877 * box, which has been packed into the window. */
878 gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
880 /* Always remember this step, this tells GTK that our preparation for
881 * this button is complete, and it can now be displayed. */
882 gtk_widget_show(button);
884 /* Do these same steps again to create a second button */
885 button = gtk_button_new_with_label ("Button 2");
887 /* Call the same callback function with a different argument,
888 * passing a pointer to "button 2" instead. */
889 gtk_signal_connect (GTK_OBJECT (button), "clicked",
890 GTK_SIGNAL_FUNC (callback), (gpointer) "button 2");
892 gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
894 /* The order in which we show the buttons is not really important, but I
895 * recommend showing the window last, so it all pops up at once. */
896 gtk_widget_show(button);
898 gtk_widget_show(box1);
900 gtk_widget_show (window);
902 /* Rest in gtk_main and wait for the fun to begin! */
910 Compile this program using the same linking arguments as our first
911 example. You'll notice this time there is no easy way to exit the
912 program, you have to use your window manager or command line to kill
913 it. A good exercise for the reader would be to insert a third "Quit"
914 button that will exit the program. You may also wish to play with the
915 options to gtk_box_pack_start() while reading the next section. Try
916 resizing the window, and observe the behavior.
918 Just as a side note, there is another useful define for
919 gtk_window_new() - GTK_WINDOW_DIALOG. This interacts with the window
920 manager a little differently and should be used for transient windows.
922 <!-- ***************************************************************** -->
923 <sect>Packing Widgets
924 <!-- ***************************************************************** -->
926 When creating an application, you'll want to put more than one widget
927 inside a window. Our first <em>helloworld</em> example only used one
928 widget so we could simply use a gtk_container_add call to "pack" the
929 widget into the window. But when you want to put more than one widget
930 into a window, how do you control where that widget is positioned?
931 This is where packing comes in.
933 <!-- ----------------------------------------------------------------- -->
934 <sect1>Theory of Packing Boxes
936 Most packing is done by creating boxes as in the example above. These
937 are invisible widget containers that we can pack our widgets into
938 which come in two forms, a horizontal box, and a vertical box. When
939 packing widgets into a horizontal box, the objects are inserted
940 horizontally from left to right or right to left depending on the call
941 used. In a vertical box, widgets are packed from top to bottom or vice
942 versa. You may use any combination of boxes inside or beside other
943 boxes to create the desired effect.
945 To create a new horizontal box, we use a call to gtk_hbox_new(), and
946 for vertical boxes, gtk_vbox_new().The gtk_box_pack_start() and
947 gtk_box_pack_end() functions are used to place objects inside of these
948 containers. The gtk_box_pack_start() function will start at the top
949 and work its way down in a vbox, and pack left to right in an hbox.
950 gtk_box_pack_end() will do the opposite, packing from bottom to top in
951 a vbox, and right to left in an hbox. Using these functions allow us
952 to right justify or left justify our widgets and may be mixed in any
953 way to achieve the desired effect. We will use gtk_box_pack_start() in
954 most of our examples. An object may be another container or a
955 widget. In fact, many widgets are actually containers themselves,
956 including the button, but we usually only use a label inside a button.
958 By using these calls, GTK knows where you want to place your widgets
959 so it can do automatic resizing and other nifty things. There's also a
960 number of options as to how your widgets should be packed. As you can
961 imagine, this method gives us a quite a bit of flexibility when
962 placing and creating widgets.
964 <!-- ----------------------------------------------------------------- -->
965 <sect1>Details of Boxes
967 Because of this flexibility, packing boxes in GTK can be confusing at
968 first. There are a lot of options, and it's not immediately obvious how
969 they all fit together. In the end however, there are basically five
974 <IMG SRC="gtk_tut_packbox1.gif" VSPACE="15" HSPACE="10" WIDTH="528"
975 HEIGHT="235" ALT="Box Packing Example Image">
979 Each line contains one horizontal box (hbox) with several buttons. The
980 call to gtk_box_pack is shorthand for the call to pack each of the
981 buttons into the hbox. Each of the buttons is packed into the hbox the
982 same way (i.e. same arguments to the gtk_box_pack_start() function).
984 This is the declaration of the gtk_box_pack_start function.
987 void gtk_box_pack_start( GtkBox *box,
994 The first argument is the box you are packing the object into, the
995 second is the object. The objects will all be buttons for now, so
996 we'll be packing buttons into boxes.
998 The expand argument to gtk_box_pack_start() and gtk_box_pack_end()
999 controls whether the widgets are laid out in the box to fill in all
1000 the extra space in the box so the box is expanded to fill the area
1001 alloted to it (TRUE). Or the box is shrunk to just fit the widgets
1002 (FALSE). Setting expand to FALSE will allow you to do right and left
1003 justification of your widgets. Otherwise, they will all expand to fit
1004 into the box, and the same effect could be achieved by using only one
1005 of gtk_box_pack_start or gtk_box_pack_end.
1007 The fill argument to the gtk_box_pack functions control whether the
1008 extra space is allocated to the objects themselves (TRUE), or as extra
1009 padding in the box around these objects (FALSE). It only has an effect
1010 if the expand argument is also TRUE.
1012 When creating a new box, the function looks like this:
1015 GtkWidget *gtk_hbox_new (gint homogeneous,
1019 The homogeneous argument to gtk_hbox_new (and the same for
1020 gtk_vbox_new) controls whether each object in the box has the same
1021 size (i.e. the same width in an hbox, or the same height in a
1022 vbox). If it is set, the expand argument to the gtk_box_pack routines
1023 is always turned on.
1025 What's the difference between spacing (set when the box is created)
1026 and padding (set when elements are packed)? Spacing is added between
1027 objects, and padding is added on either side of an object. The
1028 following figure should make it clearer:
1032 <IMG ALIGN="center" SRC="gtk_tut_packbox2.gif" WIDTH="509"
1033 HEIGHT="213" VSPACE="15" HSPACE="10"
1034 ALT="Box Packing Example Image">
1038 Here is the code used to create the above images. I've commented it
1039 fairly heavily so hopefully you won't have any problems following
1040 it. Compile it yourself and play with it.
1042 <!-- ----------------------------------------------------------------- -->
1043 <sect1>Packing Demonstration Program
1046 /* example-start packbox packbox.c */
1049 #include "gtk/gtk.h"
1051 void delete_event( GtkWidget *widget,
1058 /* Make a new hbox filled with button-labels. Arguments for the
1059 * variables we're interested are passed in to this function.
1060 * We do not show the box, but do show everything inside. */
1061 GtkWidget *make_box( gint homogeneous,
1071 /* Create a new hbox with the appropriate homogeneous
1072 * and spacing settings */
1073 box = gtk_hbox_new (homogeneous, spacing);
1075 /* Create a series of buttons with the appropriate settings */
1076 button = gtk_button_new_with_label ("gtk_box_pack");
1077 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1078 gtk_widget_show (button);
1080 button = gtk_button_new_with_label ("(box,");
1081 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1082 gtk_widget_show (button);
1084 button = gtk_button_new_with_label ("button,");
1085 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1086 gtk_widget_show (button);
1088 /* Create a button with the label depending on the value of
1091 button = gtk_button_new_with_label ("TRUE,");
1093 button = gtk_button_new_with_label ("FALSE,");
1095 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1096 gtk_widget_show (button);
1098 /* This is the same as the button creation for "expand"
1099 * above, but uses the shorthand form. */
1100 button = gtk_button_new_with_label (fill ? "TRUE," : "FALSE,");
1101 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1102 gtk_widget_show (button);
1104 sprintf (padstr, "%d);", padding);
1106 button = gtk_button_new_with_label (padstr);
1107 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1108 gtk_widget_show (button);
1120 GtkWidget *separator;
1125 /* Our init, don't forget this! :) */
1126 gtk_init (&argc, &argv);
1129 fprintf (stderr, "usage: packbox num, where num is 1, 2, or 3.\n");
1130 /* this just does cleanup in GTK, and exits with an exit status of 1. */
1134 which = atoi (argv[1]);
1136 /* Create our window */
1137 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1139 /* You should always remember to connect the destroy signal to the
1140 * main window. This is very important for proper intuitive
1142 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
1143 GTK_SIGNAL_FUNC (delete_event), NULL);
1144 gtk_container_border_width (GTK_CONTAINER (window), 10);
1146 /* We create a vertical box (vbox) to pack the horizontal boxes into.
1147 * This allows us to stack the horizontal boxes filled with buttons one
1148 * on top of the other in this vbox. */
1149 box1 = gtk_vbox_new (FALSE, 0);
1151 /* which example to show. These correspond to the pictures above. */
1154 /* create a new label. */
1155 label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1157 /* Align the label to the left side. We'll discuss this function and
1158 * others in the section on Widget Attributes. */
1159 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1161 /* Pack the label into the vertical box (vbox box1). Remember that
1162 * widgets added to a vbox will be packed one on top of the other in
1164 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1166 /* Show the label */
1167 gtk_widget_show (label);
1169 /* Call our make box function - homogeneous = FALSE, spacing = 0,
1170 * expand = FALSE, fill = FALSE, padding = 0 */
1171 box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1172 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1173 gtk_widget_show (box2);
1175 /* Call our make box function - homogeneous = FALSE, spacing = 0,
1176 * expand = FALSE, fill = FALSE, padding = 0 */
1177 box2 = make_box (FALSE, 0, TRUE, FALSE, 0);
1178 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1179 gtk_widget_show (box2);
1181 /* Args are: homogeneous, spacing, expand, fill, padding */
1182 box2 = make_box (FALSE, 0, TRUE, TRUE, 0);
1183 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1184 gtk_widget_show (box2);
1186 /* Creates a separator, we'll learn more about these later,
1187 * but they are quite simple. */
1188 separator = gtk_hseparator_new ();
1190 /* Cack the separator into the vbox. Remember each of these
1191 * widgets are being packed into a vbox, so they'll be stacked
1193 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1194 gtk_widget_show (separator);
1196 /* Create another new label, and show it. */
1197 label = gtk_label_new ("gtk_hbox_new (TRUE, 0);");
1198 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1199 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1200 gtk_widget_show (label);
1202 /* Args are: homogeneous, spacing, expand, fill, padding */
1203 box2 = make_box (TRUE, 0, TRUE, FALSE, 0);
1204 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1205 gtk_widget_show (box2);
1207 /* Args are: homogeneous, spacing, expand, fill, padding */
1208 box2 = make_box (TRUE, 0, TRUE, TRUE, 0);
1209 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1210 gtk_widget_show (box2);
1212 /* Another new separator. */
1213 separator = gtk_hseparator_new ();
1214 /* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */
1215 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1216 gtk_widget_show (separator);
1222 /* Create a new label, remember box1 is a vbox as created
1223 * near the beginning of main() */
1224 label = gtk_label_new ("gtk_hbox_new (FALSE, 10);");
1225 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1226 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1227 gtk_widget_show (label);
1229 /* Args are: homogeneous, spacing, expand, fill, padding */
1230 box2 = make_box (FALSE, 10, TRUE, FALSE, 0);
1231 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1232 gtk_widget_show (box2);
1234 /* Args are: homogeneous, spacing, expand, fill, padding */
1235 box2 = make_box (FALSE, 10, TRUE, TRUE, 0);
1236 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1237 gtk_widget_show (box2);
1239 separator = gtk_hseparator_new ();
1240 /* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */
1241 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1242 gtk_widget_show (separator);
1244 label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1245 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1246 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1247 gtk_widget_show (label);
1249 /* Args are: homogeneous, spacing, expand, fill, padding */
1250 box2 = make_box (FALSE, 0, TRUE, FALSE, 10);
1251 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1252 gtk_widget_show (box2);
1254 /* Args are: homogeneous, spacing, expand, fill, padding */
1255 box2 = make_box (FALSE, 0, TRUE, TRUE, 10);
1256 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1257 gtk_widget_show (box2);
1259 separator = gtk_hseparator_new ();
1260 /* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */
1261 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1262 gtk_widget_show (separator);
1267 /* This demonstrates the ability to use gtk_box_pack_end() to
1268 * right justify widgets. First, we create a new box as before. */
1269 box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1271 /* Create the label that will be put at the end. */
1272 label = gtk_label_new ("end");
1273 /* Pack it using gtk_box_pack_end(), so it is put on the right
1274 * side of the hbox created in the make_box() call. */
1275 gtk_box_pack_end (GTK_BOX (box2), label, FALSE, FALSE, 0);
1276 /* Show the label. */
1277 gtk_widget_show (label);
1279 /* Pack box2 into box1 (the vbox remember ? :) */
1280 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1281 gtk_widget_show (box2);
1283 /* A separator for the bottom. */
1284 separator = gtk_hseparator_new ();
1285 /* This explicitly sets the separator to 400 pixels wide by 5 pixels
1286 * high. This is so the hbox we created will also be 400 pixels wide,
1287 * and the "end" label will be separated from the other labels in the
1288 * hbox. Otherwise, all the widgets in the hbox would be packed as
1289 * close together as possible. */
1290 gtk_widget_set_usize (separator, 400, 5);
1291 /* pack the separator into the vbox (box1) created near the start
1293 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1294 gtk_widget_show (separator);
1297 /* Create another new hbox.. remember we can use as many as we need! */
1298 quitbox = gtk_hbox_new (FALSE, 0);
1300 /* Our quit button. */
1301 button = gtk_button_new_with_label ("Quit");
1303 /* Setup the signal to destroy the window. Remember that this will send
1304 * the "destroy" signal to the window which will be caught by our signal
1305 * handler as defined above. */
1306 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
1307 GTK_SIGNAL_FUNC (gtk_main_quit),
1308 GTK_OBJECT (window));
1309 /* Pack the button into the quitbox.
1310 * The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */
1311 gtk_box_pack_start (GTK_BOX (quitbox), button, TRUE, FALSE, 0);
1312 /* pack the quitbox into the vbox (box1) */
1313 gtk_box_pack_start (GTK_BOX (box1), quitbox, FALSE, FALSE, 0);
1315 /* Pack the vbox (box1) which now contains all our widgets, into the
1317 gtk_container_add (GTK_CONTAINER (window), box1);
1319 /* And show everything left */
1320 gtk_widget_show (button);
1321 gtk_widget_show (quitbox);
1323 gtk_widget_show (box1);
1324 /* Showing the window last so everything pops up at once. */
1325 gtk_widget_show (window);
1327 /* And of course, our main function. */
1330 /* Control returns here when gtk_main_quit() is called, but not when
1331 * gtk_exit is used. */
1338 <!-- ----------------------------------------------------------------- -->
1339 <sect1>Packing Using Tables
1341 Let's take a look at another way of packing - Tables. These can be
1342 extremely useful in certain situations.
1344 Using tables, we create a grid that we can place widgets in. The
1345 widgets may take up as many spaces as we specify.
1347 The first thing to look at of course, is the gtk_table_new function:
1350 GtkWidget *gtk_table_new( gint rows,
1355 The first argument is the number of rows to make in the table, while
1356 the second, obviously, is the number of columns.
1358 The homogeneous argument has to do with how the table's boxes are
1359 sized. If homogeneous is TRUE, the table boxes are resized to the size
1360 of the largest widget in the table. If homogeneous is FALSE, the size
1361 of a table boxes is dictated by the tallest widget in its same row,
1362 and the widest widget in its column.
1364 The rows and columns are laid out from 0 to n, where n was the number
1365 specified in the call to gtk_table_new. So, if you specify rows = 2
1366 and columns = 2, the layout would look something like this:
1370 0+----------+----------+
1372 1+----------+----------+
1374 2+----------+----------+
1377 Note that the coordinate system starts in the upper left hand corner.
1378 To place a widget into a box, use the following function:
1381 void gtk_table_attach( GtkTable *table,
1393 Where the first argument ("table") is the table you've created and the
1394 second ("child") the widget you wish to place in the table.
1396 The left and right attach arguments specify where to place the widget,
1397 and how many boxes to use. If you want a button in the lower right
1398 table entry of our 2x2 table, and want it to fill that entry ONLY,
1399 left_attach would be = 1, right_attach = 2, top_attach = 1,
1402 Now, if you wanted a widget to take up the whole top row of our 2x2
1403 table, you'd use left_attach = 0, right_attach = 2, top_attach = 0,
1406 The xoptions and yoptions are used to specify packing options and may
1407 be bitwise OR'ed together to allow multiple options.
1411 <item>GTK_FILL - If the table box is larger than the widget, and
1412 GTK_FILL is specified, the widget will expand to use all the room
1415 <item>GTK_SHRINK - If the table widget was allocated less space then
1416 was requested (usually by the user resizing the window), then the
1417 widgets would normally just be pushed off the bottom of the window and
1418 disappear. If GTK_SHRINK is specified, the widgets will shrink with
1421 <item>GTK_EXPAND - This will cause the table to expand to use up any
1422 remaining space in the window.
1425 Padding is just like in boxes, creating a clear area around the widget
1426 specified in pixels.
1428 gtk_table_attach() has a LOT of options. So, there's a shortcut:
1431 void gtk_table_attach_defaults( GtkTable *table,
1436 gint bottom_attach );
1439 The X and Y options default to GTK_FILL | GTK_EXPAND, and X and Y
1440 padding are set to 0. The rest of the arguments are identical to the
1443 We also have gtk_table_set_row_spacing() and
1444 gtk_table_set_col_spacing(). This places spacing between the rows at
1445 the specified row or column.
1448 void gtk_table_set_row_spacing( GtkTable *table,
1456 void gtk_table_set_col_spacing ( GtkTable *table,
1461 Note that for columns, the space goes to the right of the column, and
1462 for rows, the space goes below the row.
1464 You can also set a consistent spacing of all rows and/or columns with:
1467 void gtk_table_set_row_spacings( GtkTable *table,
1474 void gtk_table_set_col_spacings( GtkTable *table,
1478 Note that with these calls, the last row and last column do not get
1481 <!-- ----------------------------------------------------------------- -->
1482 <sect1>Table Packing Example
1484 Here we make a window with three buttons in a 2x2 table.
1485 The first two buttons will be placed in the upper row.
1486 A third, quit button, is placed in the lower row, spanning both columns.
1487 Which means it should look something like this:
1491 <IMG SRC="gtk_tut_table.gif" VSPACE="15" HSPACE="10"
1492 ALT="Table Packing Example Image" WIDTH="180" HEIGHT="120">
1496 Here's the source code:
1499 /* example-start table table.c */
1501 #include <gtk/gtk.h>
1504 * The data passed to this function is printed to stdout */
1505 void callback( GtkWidget *widget,
1508 g_print ("Hello again - %s was pressed\n", (char *) data);
1511 /* This callback quits the program */
1512 void delete_event( GtkWidget *widget,
1526 gtk_init (&argc, &argv);
1528 /* Create a new window */
1529 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1531 /* Set the window title */
1532 gtk_window_set_title (GTK_WINDOW (window), "Table");
1534 /* Set a handler for delete_event that immediately
1536 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
1537 GTK_SIGNAL_FUNC (delete_event), NULL);
1539 /* Sets the border width of the window. */
1540 gtk_container_border_width (GTK_CONTAINER (window), 20);
1542 /* Create a 2x2 table */
1543 table = gtk_table_new (2, 2, TRUE);
1545 /* Put the table in the main window */
1546 gtk_container_add (GTK_CONTAINER (window), table);
1548 /* Create first button */
1549 button = gtk_button_new_with_label ("button 1");
1551 /* When the button is clicked, we call the "callback" function
1552 * with a pointer to "button 1" as its argument */
1553 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1554 GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");
1557 /* Insert button 1 into the upper left quadrant of the table */
1558 gtk_table_attach_defaults (GTK_TABLE(table), button, 0, 1, 0, 1);
1560 gtk_widget_show (button);
1562 /* Create second button */
1564 button = gtk_button_new_with_label ("button 2");
1566 /* When the button is clicked, we call the "callback" function
1567 * with a pointer to "button 2" as its argument */
1568 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1569 GTK_SIGNAL_FUNC (callback), (gpointer) "button 2");
1570 /* Insert button 2 into the upper right quadrant of the table */
1571 gtk_table_attach_defaults (GTK_TABLE(table), button, 1, 2, 0, 1);
1573 gtk_widget_show (button);
1575 /* Create "Quit" button */
1576 button = gtk_button_new_with_label ("Quit");
1578 /* When the button is clicked, we call the "delete_event" function
1579 * and the program exits */
1580 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1581 GTK_SIGNAL_FUNC (delete_event), NULL);
1583 /* Insert the quit button into the both
1584 * lower quadrants of the table */
1585 gtk_table_attach_defaults (GTK_TABLE(table), button, 0, 2, 1, 2);
1587 gtk_widget_show (button);
1589 gtk_widget_show (table);
1590 gtk_widget_show (window);
1599 <!-- ***************************************************************** -->
1600 <sect>Widget Overview
1601 <!-- ***************************************************************** -->
1603 The general steps to creating a widget in GTK are:
1605 <item> gtk_*_new - one of various functions to create a new widget.
1606 These are all detailed in this section.
1608 <item> Connect all signals and events we wish to use to the
1609 appropriate handlers.
1611 <item> Set the attributes of the widget.
1613 <item> Pack the widget into a container using the appropriate call
1614 such as gtk_container_add() or gtk_box_pack_start().
1616 <item> gtk_widget_show() the widget.
1619 gtk_widget_show() lets GTK know that we are done setting the
1620 attributes of the widget, and it is ready to be displayed. You may
1621 also use gtk_widget_hide to make it disappear again. The order in
1622 which you show the widgets is not important, but I suggest showing the
1623 window last so the whole window pops up at once rather than seeing the
1624 individual widgets come up on the screen as they're formed. The
1625 children of a widget (a window is a widget too) will not be displayed
1626 until the window itself is shown using the gtk_widget_show() function.
1628 <!-- ----------------------------------------------------------------- -->
1631 You'll notice as you go on, that GTK uses a type casting system. This
1632 is always done using macros that both test the ability to cast the
1633 given item, and perform the cast. Some common ones you will see are:
1636 <item> GTK_WIDGET(widget)
1637 <item> GTK_OBJECT(object)
1638 <item> GTK_SIGNAL_FUNC(function)
1639 <item> GTK_CONTAINER(container)
1640 <item> GTK_WINDOW(window)
1644 These are all used to cast arguments in functions. You'll see them in the
1645 examples, and can usually tell when to use them simply by looking at the
1646 function's declaration.
1648 As you can see below in the class hierarchy, all GtkWidgets are
1649 derived from the GtkObject base class. This means you can use a widget
1650 in any place the function asks for an object - simply use the
1656 gtk_signal_connect( GTK_OBJECT(button), "clicked",
1657 GTK_SIGNAL_FUNC(callback_function), callback_data);
1660 This casts the button into an object, and provides a cast for the
1661 function pointer to the callback.
1663 Many widgets are also containers. If you look in the class hierarchy
1664 below, you'll notice that many widgets derive from the GtkContainer
1665 class. Any one of these widgets may be used with the GTK_CONTAINER
1666 macro to pass them to functions that ask for containers.
1668 Unfortunately, these macros are not extensively covered in the
1669 tutorial, but I recommend taking a look through the GTK header
1670 files. It can be very educational. In fact, it's not difficult to
1671 learn how a widget works just by looking at the function declarations.
1673 <!-- ----------------------------------------------------------------- -->
1674 <sect1>Widget Hierarchy
1676 For your reference, here is the class hierarchy tree used to implement widgets.
1683 | | | +GtkAccelLabel
1692 | | | | `GtkAspectFrame
1694 | | | | +GtkToggleButton
1695 | | | | | `GtkCheckButton
1696 | | | | | `GtkRadioButton
1697 | | | | `GtkOptionMenu
1699 | | | | +GtkMenuItem
1700 | | | | | +GtkCheckMenuItem
1701 | | | | | | `GtkRadioMenuItem
1702 | | | | | `GtkTearoffMenuItem
1703 | | | | +GtkListItem
1704 | | | | `GtkTreeItem
1706 | | | | +GtkColorSelectionDialog
1708 | | | | | `GtkInputDialog
1709 | | | | +GtkDrawWindow
1710 | | | | +GtkFileSelection
1711 | | | | +GtkFontSelectionDialog
1715 | | | +GtkScrolledWindow
1719 | | | | +GtkHButtonBox
1720 | | | | `GtkVButtonBox
1722 | | | | +GtkColorSelection
1723 | | | | `GtkGammaCurve
1731 | | | `GtkFontSelection
1750 | | | `GtkSpinButton
1774 <!-- ----------------------------------------------------------------- -->
1775 <sect1>Widgets Without Windows
1777 The following widgets do not have an associated window. If you want to
1778 capture events, you'll have to use the GtkEventBox. See the section on
1779 the <ref id="sec_EventBox" name="EventBox"> widget.
1801 We'll further our exploration of GTK by examining each widget in turn,
1802 creating a few simple functions to display them. Another good source
1803 is the testgtk.c program that comes with GTK. It can be found in
1806 <!-- ***************************************************************** -->
1807 <sect>The Button Widget
1808 <!-- ***************************************************************** -->
1810 <!-- ----------------------------------------------------------------- -->
1811 <sect1>Normal Buttons
1813 We've almost seen all there is to see of the button widget. It's
1814 pretty simple. There are however two ways to create a button. You can
1815 use the gtk_button_new_with_label() to create a button with a label,
1816 or use gtk_button_new() to create a blank button. It's then up to you
1817 to pack a label or pixmap into this new button. To do this, create a
1818 new box, and then pack your objects into this box using the usual
1819 gtk_box_pack_start, and then use gtk_container_add to pack the box
1822 Here's an example of using gtk_button_new to create a button with a
1823 picture and a label in it. I've broken up the code to create a box
1824 from the rest so you can use it in your programs. There are further
1825 examples of using pixmaps later in the tutorial.
1828 /* example-start buttons buttons.c */
1830 #include <gtk/gtk.h>
1832 /* Create a new hbox with an image and a label packed into it
1833 * and return the box. */
1835 GtkWidget *xpm_label_box( GtkWidget *parent,
1836 gchar *xpm_filename,
1841 GtkWidget *pixmapwid;
1846 /* Create box for xpm and label */
1847 box1 = gtk_hbox_new (FALSE, 0);
1848 gtk_container_border_width (GTK_CONTAINER (box1), 2);
1850 /* Get the style of the button to get the
1851 * background color. */
1852 style = gtk_widget_get_style(parent);
1854 /* Now on to the xpm stuff */
1855 pixmap = gdk_pixmap_create_from_xpm (parent->window, &mask,
1856 &style->bg[GTK_STATE_NORMAL],
1858 pixmapwid = gtk_pixmap_new (pixmap, mask);
1860 /* Create a label for the button */
1861 label = gtk_label_new (label_text);
1863 /* Pack the pixmap and label into the box */
1864 gtk_box_pack_start (GTK_BOX (box1),
1865 pixmapwid, FALSE, FALSE, 3);
1867 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 3);
1869 gtk_widget_show(pixmapwid);
1870 gtk_widget_show(label);
1875 /* Our usual callback function */
1876 void callback( GtkWidget *widget,
1879 g_print ("Hello again - %s was pressed\n", (char *) data);
1886 /* GtkWidget is the storage type for widgets */
1891 gtk_init (&argc, &argv);
1893 /* Create a new window */
1894 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1896 gtk_window_set_title (GTK_WINDOW (window), "Pixmap'd Buttons!");
1898 /* It's a good idea to do this for all windows. */
1899 gtk_signal_connect (GTK_OBJECT (window), "destroy",
1900 GTK_SIGNAL_FUNC (gtk_exit), NULL);
1902 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
1903 GTK_SIGNAL_FUNC (gtk_exit), NULL);
1906 /* Sets the border width of the window. */
1907 gtk_container_border_width (GTK_CONTAINER (window), 10);
1908 gtk_widget_realize(window);
1910 /* Create a new button */
1911 button = gtk_button_new ();
1913 /* Connect the "clicked" signal of the button to our callback */
1914 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1915 GTK_SIGNAL_FUNC (callback), (gpointer) "cool button");
1917 /* This calls our box creating function */
1918 box1 = xpm_label_box(window, "info.xpm", "cool button");
1920 /* Pack and show all our widgets */
1921 gtk_widget_show(box1);
1923 gtk_container_add (GTK_CONTAINER (button), box1);
1925 gtk_widget_show(button);
1927 gtk_container_add (GTK_CONTAINER (window), button);
1929 gtk_widget_show (window);
1931 /* Rest in gtk_main and wait for the fun to begin! */
1939 The xpm_label_box function could be used to pack xpm's and labels into
1940 any widget that can be a container.
1942 The Button widget has the following signals:
1952 <!-- ----------------------------------------------------------------- -->
1953 <sect1> Toggle Buttons
1955 Toggle buttons are derived from normal buttons and are very similar,
1956 except they will always be in one of two states, alternated by a
1957 click. They may be depressed, and when you click again, they will pop
1958 back up. Click again, and they will pop back down.
1960 Toggle buttons are the basis for check buttons and radio buttons, as
1961 such, many of the calls used for toggle buttons are inherited by radio
1962 and check buttons. I will point these out when we come to them.
1964 Creating a new toggle button:
1967 GtkWidget *gtk_toggle_button_new( void );
1969 GtkWidget *gtk_toggle_button_new_with_label( gchar *label );
1972 As you can imagine, these work identically to the normal button widget
1973 calls. The first creates a blank toggle button, and the second, a
1974 button with a label widget already packed into it.
1976 To retrieve the state of the toggle widget, including radio and check
1977 buttons, we use a GTK macro as shown in our example below. This tests
1978 the state of the toggle in a callback. The signal of interest emitted
1979 to us by toggle buttons (the toggle button, check button, and radio
1980 button widgets), is the "toggled" signal. To check the state of these
1981 buttons, set up a signal handler to catch the toggled signal, and use
1982 the macro to determine its state. The callback will look something
1986 void toggle_button_callback (GtkWidget *widget, gpointer data)
1988 if (GTK_TOGGLE_BUTTON (widget)->active)
1990 /* If control reaches here, the toggle button is down */
1994 /* If control reaches here, the toggle button is up */
2000 void gtk_toggle_button_set_state( GtkToggleButton *toggle_button,
2004 The above call can be used to set the state of the toggle button, and
2005 its children the radio and check buttons. Passing in your created
2006 button as the first argument, and a TRUE or FALSE for the second state
2007 argument to specify whether it should be down (depressed) or up
2008 (released). Default is up, or FALSE.
2010 Note that when you use the gtk_toggle_button_set_state() function, and
2011 the state is actually changed, it causes the "clicked" signal to be
2012 emitted from the button.
2015 void gtk_toggle_button_toggled (GtkToggleButton *toggle_button);
2018 This simply toggles the button, and emits the "toggled" signal.
2020 <!-- ----------------------------------------------------------------- -->
2021 <sect1> Check Buttons
2023 Check buttons inherent many properties and functions from the the
2024 toggle buttons above, but look a little different. Rather than being
2025 buttons with text inside them, they are small squares with the text to
2026 the right of them. These are often used for toggling options on and
2027 off in applications.
2029 The two creation functions are similar to those of the normal button.
2032 GtkWidget *gtk_check_button_new( void );
2034 GtkWidget *gtk_check_button_new_with_label ( gchar *label );
2037 The new_with_label function creates a check button with a label beside
2040 Checking the state of the check button is identical to that of the
2043 <!-- ----------------------------------------------------------------- -->
2044 <sect1> Radio Buttons <label id="sec_Radio_Buttons">
2046 Radio buttons are similar to check buttons except they are grouped so
2047 that only one may be selected/depressed at a time. This is good for
2048 places in your application where you need to select from a short list
2051 Creating a new radio button is done with one of these calls:
2054 GtkWidget *gtk_radio_button_new( GSList *group );
2056 GtkWidget *gtk_radio_button_new_with_label( GSList *group,
2060 You'll notice the extra argument to these calls. They require a group
2061 to perform their duty properly. The first call to
2062 gtk_radio_button_new_with_label or gtk_radio_button_new_with_label
2063 should pass NULL as the first argument. Then create a group using:
2066 GSList *gtk_radio_button_group( GtkRadioButton *radio_button );
2069 The important thing to remember is that gtk_radio_button_group must be
2070 called for each new button added to the group, with the previous
2071 button passed in as an argument. The result is then passed into the
2072 call to gtk_radio_button_new or gtk_radio_button_new_with_label. This
2073 allows a chain of buttons to be established. The example below should
2076 You can shorten this slightly by using the following syntax, which
2077 removes the need for a variable to hold the list of buttons. This form
2078 is used in the example to create the third button:
2081 button2 = gtk_radio_button_new_with_label(
2082 gtk_radio_button_group (GTK_RADIO_BUTTON (button1)),
2086 It is also a good idea to explicitly set which button should be the
2087 default depressed button with:
2090 void gtk_toggle_button_set_state( GtkToggleButton *toggle_button,
2094 This is described in the section on toggle buttons, and works in
2095 exactly the same way.
2097 The following example creates a radio button group with three buttons.
2100 /* example-start radiobuttons radiobuttons.c */
2102 #include <gtk/gtk.h>
2105 void close_application( GtkWidget *widget,
2115 GtkWidget *window = NULL;
2119 GtkWidget *separator;
2122 gtk_init(&argc,&argv);
2124 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2126 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
2127 GTK_SIGNAL_FUNC(close_application),
2130 gtk_window_set_title (GTK_WINDOW (window), "radio buttons");
2131 gtk_container_border_width (GTK_CONTAINER (window), 0);
2133 box1 = gtk_vbox_new (FALSE, 0);
2134 gtk_container_add (GTK_CONTAINER (window), box1);
2135 gtk_widget_show (box1);
2137 box2 = gtk_vbox_new (FALSE, 10);
2138 gtk_container_border_width (GTK_CONTAINER (box2), 10);
2139 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2140 gtk_widget_show (box2);
2142 button = gtk_radio_button_new_with_label (NULL, "button1");
2143 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2144 gtk_widget_show (button);
2146 group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
2147 button = gtk_radio_button_new_with_label(group, "button2");
2148 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
2149 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2150 gtk_widget_show (button);
2152 button = gtk_radio_button_new_with_label(
2153 gtk_radio_button_group (GTK_RADIO_BUTTON (button)),
2155 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2156 gtk_widget_show (button);
2158 separator = gtk_hseparator_new ();
2159 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
2160 gtk_widget_show (separator);
2162 box2 = gtk_vbox_new (FALSE, 10);
2163 gtk_container_border_width (GTK_CONTAINER (box2), 10);
2164 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
2165 gtk_widget_show (box2);
2167 button = gtk_button_new_with_label ("close");
2168 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2169 GTK_SIGNAL_FUNC(close_application),
2170 GTK_OBJECT (window));
2171 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2172 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
2173 gtk_widget_grab_default (button);
2174 gtk_widget_show (button);
2175 gtk_widget_show (window);
2184 <!-- TODO: check out gtk_radio_button_new_from_widget function - TRG -->
2186 <!-- ***************************************************************** -->
2187 <sect> Adjustments <label id="sec_Adjustment">
2188 <!-- ***************************************************************** -->
2190 GTK+ has various widgets that can be visually adjusted by the user
2191 using the mouse or the keyboard, such as the range widgets, described
2192 in the <ref id="sec_Range_Widgets" name="Range Widgets">
2193 section. There are also a few widgets that display some adjustable
2194 portion of a larger area of data, such as the text widget and the
2197 Obviously, an application needs to be able to react to changes the
2198 user makes in range widgets. One way to do this would be to have each
2199 widget emit its own type of signal when its adjustment changes, and
2200 either pass the new value to the signal handler, or require it to look
2201 inside the widget's data structure in order to ascertain the value.
2202 But you may also want to connect the adjustments of several widgets
2203 together, so that adjusting one adjusts the others. The most obvious
2204 example of this is connecting a scrollbar to a panning viewport or a
2205 scrolling text area. If each widget has its own way of setting or
2206 getting the adjustment value, then the programmer may have to write
2207 their own signal handlers to translate between the output of one
2208 widget's signal and the "input" of another's adjustment setting
2211 GTK+ solves this problem using the GtkAdjustment object, which is a
2212 way for widgets to store and pass adjustment information in an
2213 abstract and flexible form. The most obvious use of GtkAdjustment is
2214 to store the configuration parameters and values of range widgets,
2215 such as scrollbars and scale controls. However, since GtkAdjustments
2216 are derived from GtkObject, they have some special powers beyond those
2217 of normal data structures. Most importantly, they can emit signals,
2218 just like widgets, and these signals can be used not only to allow
2219 your program to react to user input on adjustable widgets, but also to
2220 propagate adjustment values transparently between adjustable widgets.
2222 <sect1> Creating an Adjustment
2224 You create an adjustment using:
2227 GtkObject *gtk_adjustment_new( gfloat value,
2230 gfloat step_increment,
2231 gfloat page_increment,
2235 The <tt/value/ argument is the initial value you want to give to the
2236 adjustment, usually corresponding to the topmost or leftmost position
2237 of an adjustable widget. The <tt/lower/ argument specifies the lowest
2238 value which the adjustment can hold. The <tt/step_increment/ argument
2239 specifies the "smaller" of the two increments by which the user can
2240 change the value, while the <tt/page_increment/ is the "larger" one.
2241 The <tt/page_size/ argument usually corresponds somehow to the visible
2242 area of a panning widget. The <tt/upper/ argument is used to represent
2243 the bottom most or right most coordinate in a panning widget's
2244 child. Therefore it is <em/not/ always the largest number that
2245 <tt/value/ can take, since the <tt/page_size/ of such widgets is
2248 <!-- ----------------------------------------------------------------- -->
2249 <sect1> Using Adjustments the Easy Way
2251 The adjustable widgets can be roughly divided into those which use and
2252 require specific units for these values and those which treat them as
2253 arbitrary numbers. The group which treats the values as arbitrary
2254 numbers includes the range widgets (scrollbars and scales, the
2255 progress bar widget, and the spin button widget). These widgets are
2256 all the widgets which are typically "adjusted" directly by the user
2257 with the mouse or keyboard. They will treat the <tt/lower/ and
2258 <tt/upper/ values of an adjustment as a range within which the user
2259 can manipulate the adjustment's <tt/value/. By default, they will only
2260 modify the <tt/value/ of an adjustment.
2262 The other group includes the text widget, the viewport widget, the
2263 compound list widget, and the scrolled window widget. All of these
2264 widgets use pixel values for their adjustments. These are also all
2265 widgets which are typically "adjusted" indirectly using scrollbars.
2266 While all widgets which use adjustments can either create their own
2267 adjustments or use ones you supply, you'll generally want to let this
2268 particular category of widgets create its own adjustments. Usually,
2269 they will eventually override all the values except the <tt/value/
2270 itself in whatever adjustments you give them, but the results are, in
2271 general, undefined (meaning, you'll have to read the source code to
2272 find out, and it may be different from widget to widget).
2274 Now, you're probably thinking, since text widgets and viewports insist
2275 on setting everything except the <tt/value/ of their adjustments,
2276 while scrollbars will <em/only/ touch the adjustment's <tt/value/, if
2277 you <em/share/ an adjustment object between a scrollbar and a text
2278 widget, manipulating the scrollbar will automagically adjust the text
2279 widget? Of course it will! Just like this:
2282 /* creates its own adjustments */
2283 text = gtk_text_new (NULL, NULL);
2284 /* uses the newly-created adjustment for the scrollbar as well */
2285 vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
2289 <!-- ----------------------------------------------------------------- -->
2290 <sect1> Adjustment Internals
2292 Ok, you say, that's nice, but what if I want to create my own handlers
2293 to respond when the user adjusts a range widget or a spin button, and
2294 how do I get at the value of the adjustment in these handlers? To
2295 answer these questions and more, let's start by taking a look at
2296 <tt>struct _GtkAdjustment</tt> itself:
2299 struct _GtkAdjustment
2306 gfloat step_increment;
2307 gfloat page_increment;
2312 The first thing you should know is that there aren't any handy-dandy
2313 macros or accessor functions for getting the <tt/value/ out of a
2314 GtkAdjustment, so you'll have to (horror of horrors) do it like a
2315 <em/real/ C programmer. Don't worry - the <tt>GTK_ADJUSTMENT
2316 (Object)</tt> macro does run-time type checking (as do all the GTK+
2317 type-casting macros, actually).
2319 Since, when you set the <tt/value/ of an adjustment, you generally
2320 want the change to be reflected by every widget that uses this
2321 adjustment, GTK+ provides this convenience function to do this:
2324 void gtk_adjustment_set_value( GtkAdjustment *adjustment,
2328 As mentioned earlier, GtkAdjustment is a subclass of GtkObject just
2329 like all the various widgets, and thus it is able to emit signals.
2330 This is, of course, why updates happen automagically when you share an
2331 adjustment object between a scrollbar and another adjustable widget;
2332 all adjustable widgets connect signal handlers to their adjustment's
2333 <tt/value_changed/ signal, as can your program. Here's the definition
2334 of this signal in <tt/struct _GtkAdjustmentClass/:
2337 void (* value_changed) (GtkAdjustment *adjustment);
2340 The various widgets that use the GtkAdjustment object will emit this
2341 signal on an adjustment whenever they change its value. This happens
2342 both when user input causes the slider to move on a range widget, as
2343 well as when the program explicitly changes the value with
2344 <tt/gtk_adjustment_set_value()/. So, for example, if you have a scale
2345 widget, and you want to change the rotation of a picture whenever its
2346 value changes, you would create a callback like this:
2349 void cb_rotate_picture (GtkAdjustment *adj, GtkWidget *picture)
2351 set_picture_rotation (picture, adj->value);
2355 and connect it to the scale widget's adjustment like this:
2358 gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
2359 GTK_SIGNAL_FUNC (cb_rotate_picture), picture);
2362 What about when a widget reconfigures the <tt/upper/ or <tt/lower/
2363 fields of its adjustment, such as when a user adds more text to a text
2364 widget? In this case, it emits the <tt/changed/ signal, which looks
2368 void (* changed) (GtkAdjustment *adjustment);
2371 Range widgets typically connect a handler to this signal, which
2372 changes their appearance to reflect the change - for example, the size
2373 of the slider in a scrollbar will grow or shrink in inverse proportion
2374 to the difference between the <tt/lower/ and <tt/upper/ values of its
2377 You probably won't ever need to attach a handler to this signal,
2378 unless you're writing a new type of range widget. However, if you
2379 change any of the values in a GtkAdjustment directly, you should emit
2380 this signal on it to reconfigure whatever widgets are using it, like
2384 gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");
2387 Now go forth and adjust!
2391 <!-- ***************************************************************** -->
2392 <sect> Range Widgets<label id="sec_Range_Widgets">
2393 <!-- ***************************************************************** -->
2396 The category of range widgets includes the ubiquitous scrollbar widget
2397 and the less common "scale" widget. Though these two types of widgets
2398 are generally used for different purposes, they are quite similar in
2399 function and implementation. All range widgets share a set of common
2400 graphic elements, each of which has its own X window and receives
2401 events. They all contain a "trough" and a "slider" (what is sometimes
2402 called a "thumbwheel" in other GUI environments). Dragging the slider
2403 with the pointer moves it back and forth within the trough, while
2404 clicking in the trough advances the slider towards the location of the
2405 click, either completely, or by a designated amount, depending on
2406 which mouse button is used.
2408 As mentioned in <ref id="sec_Adjustment" name="Adjustments"> above,
2409 all range widgets are associated with an adjustment object, from which
2410 they calculate the length of the slider and it's position within the
2411 trough. When the user manipulates the slider, the range widget will
2412 change the value of the adjustment.
2414 <!-- ----------------------------------------------------------------- -->
2415 <sect1> Scrollbar Widgets
2417 These are your standard, run-of-the-mill scrollbars. These should be
2418 used only for scrolling some other widget, such as a list, a text box,
2419 or a viewport (and it's generally easier to use the scrolled window
2420 widget in most cases). For other purposes, you should use scale
2421 widgets, as they are friendlier and more featureful.
2423 There are separate types for horizontal and vertical scrollbars.
2424 There really isn't much to say about these. You create them with the
2425 following functions, defined in <tt><gtk/gtkhscrollbar.h></tt>
2426 and <tt><gtk/gtkvscrollbar.h></tt>:
2429 GtkWidget *gtk_hscrollbar_new( GtkAdjustment *adjustment );
2431 GtkWidget *gtk_vscrollbar_new( GtkAdjustment *adjustment );
2434 and that's about it (if you don't believe me, look in the header
2435 files!). The <tt/adjustment/ argument can either be a pointer to an
2436 existing GtkAdjustment, or NULL, in which case one will be created for
2437 you. Specifying NULL might actually be useful in this case, if you
2438 wish to pass the newly-created adjustment to the constructor function
2439 of some other widget which will configure it for you, such as a text
2443 <!-- ----------------------------------------------------------------- -->
2444 <sect1> Scale Widgets
2446 Scale widgets are used to allow the user to visually select and
2447 manipulate a value within a specific range. You might want to use a
2448 scale widget, for example, to adjust the magnification level on a
2449 zoomed preview of a picture, or to control the brightness of a colour,
2450 or to specify the number of minutes of inactivity before a screensaver
2451 takes over the screen.
2453 <!-- ----------------------------------------------------------------- -->
2454 <sect2>Creating a Scale Widget
2456 As with scrollbars, there are separate widget types for horizontal and
2457 vertical scale widgets. (Most programmers seem to favour horizontal
2458 scale widgets). Since they work essentially the same way, there's no
2459 need to treat them separately here. The following functions, defined
2460 in <tt><gtk/gtkvscale.h></tt> and
2461 <tt><gtk/gtkhscale.h></tt>, create vertical and horizontal scale
2462 widgets, respectively:
2466 GtkWidget *gtk_vscale_new( GtkAdjustment *adjustment );
2468 GtkWidget *gtk_hscale_new( GtkAdjustment *adjustment );
2472 The <tt/adjustment/ argument can either be an adjustment which has
2473 already been created with <tt/gtk_adjustment_new()/, or <tt/NULL/, in
2474 which case, an anonymous GtkAdjustment is created with all of its
2475 values set to <tt/0.0/ (which isn't very useful in this case). In
2476 order to avoid confusing yourself, you probably want to create your
2477 adjustment with a <tt/page_size/ of <tt/0.0/ so that its <tt/upper/
2478 value actually corresponds to the highest value the user can select.
2479 (If you're <em/already/ thoroughly confused, read the section on <ref
2480 id="sec_Adjustment" name="Adjustments"> again for an explanation of
2481 what exactly adjustments do and how to create and manipulate them).
2483 <!-- ----------------------------------------------------------------- -->
2484 <sect2> Functions and Signals (well, functions, at least)
2486 Scale widgets can display their current value as a number beside the
2487 trough. The default behaviour is to show the value, but you can change
2488 this with this function:
2491 void gtk_scale_set_draw_value( GtkScale *scale,
2495 As you might have guessed, <tt/draw_value/ is either <tt/TRUE/ or
2496 <tt/FALSE/, with predictable consequences for either one.
2498 The value displayed by a scale widget is rounded to one decimal point
2499 by default, as is the <tt/value/ field in its GtkAdjustment. You can
2504 void gtk_scale_set_digits( GtkScale *scale,
2509 where <tt/digits/ is the number of decimal places you want. You can
2510 set <tt/digits/ to anything you like, but no more than 13 decimal
2511 places will actually be drawn on screen.
2513 Finally, the value can be drawn in different positions
2514 relative to the trough:
2518 void gtk_scale_set_value_pos( GtkScale *scale,
2519 GtkPositionType pos );
2523 The argument <tt/pos/ is of type <tt>GtkPositionType</tt>, which is
2524 defined in <tt><gtk/gtkenums.h></tt>, and can take one of the
2529 <item> GTK_POS_RIGHT
2531 <item> GTK_POS_BOTTOM
2534 If you position the value on the "side" of the trough (e.g. on the top
2535 or bottom of a horizontal scale widget), then it will follow the
2536 slider up and down the trough.
2538 All the preceding functions are defined in
2539 <tt><gtk/gtkscale.h></tt>.
2543 <!-- ----------------------------------------------------------------- -->
2544 <sect1> Common Functions <label id="sec_Range_Functions">
2546 The GtkRange widget class is fairly complicated internally, but, like
2547 all the "base class" widgets, most of its complexity is only
2548 interesting if you want to hack on it. Also, almost all of the
2549 functions and signals it defines are only really used in writing
2550 derived widgets. There are, however, a few useful functions that are
2551 defined in <tt><gtk/gtkrange.h></tt> and will work on all range
2554 <!-- ----------------------------------------------------------------- -->
2555 <sect2> Setting the Update Policy
2557 The "update policy" of a range widget defines at what points during
2558 user interaction it will change the <tt/value/ field of its
2559 GtkAdjustment and emit the "value_changed" signal on this
2560 GtkAdjustment. The update policies, defined in
2561 <tt><gtk/gtkenums.h></tt> as type <tt>enum GtkUpdateType</tt>,
2565 <item>GTK_UPDATE_POLICY_CONTINUOUS - This is the default. The
2566 "value_changed" signal is emitted continuously, i.e. whenever the
2567 slider is moved by even the tiniest amount.
2569 <item>GTK_UPDATE_POLICY_DISCONTINUOUS - The "value_changed" signal is
2570 only emitted once the slider has stopped moving and the user has
2571 released the mouse button.
2573 <item>GTK_UPDATE_POLICY_DELAYED - The "value_change" signal is emitted
2574 when the user releases the mouse button, or if the slider stops moving
2575 for a short period of time.
2579 The update policy of a range widget can be set by casting it using the
2580 <tt>GTK_RANGE (Widget)</tt> macro and passing it to this function:
2583 void gtk_range_set_update_policy( GtkRange *range,
2584 GtkUpdateType policy) ;
2587 <!-- ----------------------------------------------------------------- -->
2588 <sect2>Getting and Setting Adjustments
2590 Getting and setting the adjustment for a range widget "on the fly" is
2591 done, predictably, with:
2594 GtkAdjustment* gtk_range_get_adjustment( GtkRange *range );
2596 void gtk_range_set_adjustment( GtkRange *range,
2597 GtkAdjustment *adjustment );
2600 <tt/gtk_range_get_adjustment()/ returns a pointer to the adjustment to
2601 which <tt/range/ is connected.
2603 <tt/gtk_range_set_adjustment()/ does absolutely nothing if you pass it
2604 the adjustment that <tt/range/ is already using, regardless of whether
2605 you changed any of its fields or not. If you pass it a new
2606 GtkAdjustment, it will unreference the old one if it exists (possibly
2607 destroying it), connect the appropriate signals to the new one, and
2608 call the private function <tt/gtk_range_adjustment_changed()/, which
2609 will (or at least, is supposed to...) recalculate the size and/or
2610 position of the slider and redraw if necessary. As mentioned in the
2611 section on adjustments, if you wish to reuse the same GtkAdjustment,
2612 when you modify its values directly, you should emit the "changed"
2613 signal on it, like this:
2616 gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");
2621 <!-- ----------------------------------------------------------------- -->
2622 <sect1> Key and Mouse bindings
2624 All of the GTK+ range widgets react to mouse clicks in more or less
2625 the same way. Clicking button-1 in the trough will cause its
2626 adjustment's <tt/page_increment/ to be added or subtracted from its
2627 <tt/value/, and the slider to be moved accordingly. Clicking mouse
2628 button-2 in the trough will jump the slider to the point at which the
2629 button was clicked. Clicking any button on a scrollbar's arrows will
2630 cause its adjustment's value to change <tt/step_increment/ at a time.
2632 It may take a little while to get used to, but by default, scrollbars
2633 as well as scale widgets can take the keyboard focus in GTK+. If you
2634 think your users will find this too confusing, you can always disable
2635 this by unsetting the GTK_CAN_FOCUS flag on the scrollbar, like this:
2638 GTK_WIDGET_UNSET_FLAGS (scrollbar, GTK_CAN_FOCUS);
2641 The key bindings (which are, of course, only active when the widget
2642 has focus) are slightly different between horizontal and vertical
2643 range widgets, for obvious reasons. They are also not quite the same
2644 for scale widgets as they are for scrollbars, for somewhat less
2645 obvious reasons (possibly to avoid confusion between the keys for
2646 horizontal and vertical scrollbars in scrolled windows, where both
2647 operate on the same area).
2649 <sect2> Vertical Range Widgets
2651 All vertical range widgets can be operated with the up and down arrow
2652 keys, as well as with the <tt/Page Up/ and <tt/Page Down/ keys. The
2653 arrows move the slider up and down by <tt/step_increment/, while
2654 <tt/Page Up/ and <tt/Page Down/ move it by <tt/page_increment/.
2656 The user can also move the slider all the way to one end or the other
2657 of the trough using the keyboard. With the GtkVScale widget, this is
2658 done with the <tt/Home/ and <tt/End/ keys, whereas with the
2659 GtkVScrollbar widget, this is done by typing <tt>Control-Page Up</tt>
2660 and <tt>Control-Page Down</tt>.
2662 <!-- ----------------------------------------------------------------- -->
2663 <sect2> Horizontal Range Widgets
2665 The left and right arrow keys work as you might expect in these
2666 widgets, moving the slider back and forth by <tt/step_increment/. The
2667 <tt/Home/ and <tt/End/ keys move the slider to the ends of the trough.
2668 For the GtkHScale widget, moving the slider by <tt/page_increment/ is
2669 accomplished with <tt>Control-Left</tt> and <tt>Control-Right</tt>,
2670 while for GtkHScrollbar, it's done with <tt>Control-Home</tt> and
2671 <tt>Control-End</tt>.
2675 <!-- ----------------------------------------------------------------- -->
2676 <sect1> Example<label id="sec_Range_Example">
2678 This example is a somewhat modified version of the "range controls"
2679 test from <tt/testgtk.c/. It basically puts up a window with three
2680 range widgets all connected to the same adjustment, and a couple of
2681 controls for adjusting some of the parameters mentioned above and in
2682 the seciton on adjustments, so you can see how they affect the way
2683 these widgets work for the user.
2686 /* example-start rangewidgets rangewidgets.c */
2688 #include <gtk/gtk.h>
2690 GtkWidget *hscale, *vscale;
2692 void cb_pos_menu_select( GtkWidget *item,
2693 GtkPositionType pos )
2695 /* Set the value position on both scale widgets */
2696 gtk_scale_set_value_pos (GTK_SCALE (hscale), pos);
2697 gtk_scale_set_value_pos (GTK_SCALE (vscale), pos);
2700 void cb_update_menu_select( GtkWidget *item,
2701 GtkUpdateType policy )
2703 /* Set the update policy for both scale widgets */
2704 gtk_range_set_update_policy (GTK_RANGE (hscale), policy);
2705 gtk_range_set_update_policy (GTK_RANGE (vscale), policy);
2708 void cb_digits_scale( GtkAdjustment *adj )
2710 /* Set the number of decimal places to which adj->value is rounded */
2711 gtk_scale_set_digits (GTK_SCALE (hscale), (gint) adj->value);
2712 gtk_scale_set_digits (GTK_SCALE (vscale), (gint) adj->value);
2715 void cb_page_size( GtkAdjustment *get,
2716 GtkAdjustment *set )
2718 /* Set the page size and page increment size of the sample
2719 * adjustment to the value specified by the "Page Size" scale */
2720 set->page_size = get->value;
2721 set->page_increment = get->value;
2722 /* Now emit the "changed" signal to reconfigure all the widgets that
2723 * are attached to this adjustment */
2724 gtk_signal_emit_by_name (GTK_OBJECT (set), "changed");
2727 void cb_draw_value( GtkToggleButton *button )
2729 /* Turn the value display on the scale widgets off or on depending
2730 * on the state of the checkbutton */
2731 gtk_scale_set_draw_value (GTK_SCALE (hscale), button->active);
2732 gtk_scale_set_draw_value (GTK_SCALE (vscale), button->active);
2735 /* Convenience functions */
2737 GtkWidget *make_menu_item( gchar *name,
2738 GtkSignalFunc callback,
2743 item = gtk_menu_item_new_with_label (name);
2744 gtk_signal_connect (GTK_OBJECT (item), "activate",
2746 gtk_widget_show (item);
2751 void scale_set_default_values( GtkScale *scale )
2753 gtk_range_set_update_policy (GTK_RANGE (scale),
2754 GTK_UPDATE_CONTINUOUS);
2755 gtk_scale_set_digits (scale, 1);
2756 gtk_scale_set_value_pos (scale, GTK_POS_TOP);
2757 gtk_scale_set_draw_value (scale, TRUE);
2760 /* makes the sample window */
2762 void create_range_controls( void )
2765 GtkWidget *box1, *box2, *box3;
2767 GtkWidget *scrollbar;
2768 GtkWidget *separator;
2769 GtkWidget *opt, *menu, *item;
2772 GtkObject *adj1, *adj2;
2774 /* Standard window-creating stuff */
2775 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2776 gtk_signal_connect (GTK_OBJECT (window), "destroy",
2777 GTK_SIGNAL_FUNC(gtk_main_quit),
2779 gtk_window_set_title (GTK_WINDOW (window), "range controls");
2781 box1 = gtk_vbox_new (FALSE, 0);
2782 gtk_container_add (GTK_CONTAINER (window), box1);
2783 gtk_widget_show (box1);
2785 box2 = gtk_hbox_new (FALSE, 10);
2786 gtk_container_border_width (GTK_CONTAINER (box2), 10);
2787 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2788 gtk_widget_show (box2);
2790 /* calue, lower, upper, step_increment, page_increment, page_size */
2791 /* Note that the page_size value only makes a difference for
2792 * scrollbar widgets, and the highest value you'll get is actually
2793 * (upper - page_size). */
2794 adj1 = gtk_adjustment_new (0.0, 0.0, 101.0, 0.1, 1.0, 1.0);
2796 vscale = gtk_vscale_new (GTK_ADJUSTMENT (adj1));
2797 scale_set_default_values (GTK_SCALE (vscale));
2798 gtk_box_pack_start (GTK_BOX (box2), vscale, TRUE, TRUE, 0);
2799 gtk_widget_show (vscale);
2801 box3 = gtk_vbox_new (FALSE, 10);
2802 gtk_box_pack_start (GTK_BOX (box2), box3, TRUE, TRUE, 0);
2803 gtk_widget_show (box3);
2805 /* Reuse the same adjustment */
2806 hscale = gtk_hscale_new (GTK_ADJUSTMENT (adj1));
2807 gtk_widget_set_usize (GTK_WIDGET (hscale), 200, 30);
2808 scale_set_default_values (GTK_SCALE (hscale));
2809 gtk_box_pack_start (GTK_BOX (box3), hscale, TRUE, TRUE, 0);
2810 gtk_widget_show (hscale);
2812 /* Reuse the same adjustment again */
2813 scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adj1));
2814 /* Notice how this causes the scales to always be updated
2815 * continuously when the scrollbar is moved */
2816 gtk_range_set_update_policy (GTK_RANGE (scrollbar),
2817 GTK_UPDATE_CONTINUOUS);
2818 gtk_box_pack_start (GTK_BOX (box3), scrollbar, TRUE, TRUE, 0);
2819 gtk_widget_show (scrollbar);
2821 box2 = gtk_hbox_new (FALSE, 10);
2822 gtk_container_border_width (GTK_CONTAINER (box2), 10);
2823 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2824 gtk_widget_show (box2);
2826 /* A checkbutton to control whether the value is displayed or not */
2827 button = gtk_check_button_new_with_label("Display value on scale widgets");
2828 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
2829 gtk_signal_connect (GTK_OBJECT (button), "toggled",
2830 GTK_SIGNAL_FUNC(cb_draw_value), NULL);
2831 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2832 gtk_widget_show (button);
2834 box2 = gtk_hbox_new (FALSE, 10);
2835 gtk_container_border_width (GTK_CONTAINER (box2), 10);
2837 /* An option menu to change the position of the value */
2838 label = gtk_label_new ("Scale Value Position:");
2839 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
2840 gtk_widget_show (label);
2842 opt = gtk_option_menu_new();
2843 menu = gtk_menu_new();
2845 item = make_menu_item ("Top",
2846 GTK_SIGNAL_FUNC(cb_pos_menu_select),
2847 GINT_TO_POINTER (GTK_POS_TOP));
2848 gtk_menu_append (GTK_MENU (menu), item);
2850 item = make_menu_item ("Bottom", GTK_SIGNAL_FUNC (cb_pos_menu_select),
2851 GINT_TO_POINTER (GTK_POS_BOTTOM));
2852 gtk_menu_append (GTK_MENU (menu), item);
2854 item = make_menu_item ("Left", GTK_SIGNAL_FUNC (cb_pos_menu_select),
2855 GINT_TO_POINTER (GTK_POS_LEFT));
2856 gtk_menu_append (GTK_MENU (menu), item);
2858 item = make_menu_item ("Right", GTK_SIGNAL_FUNC (cb_pos_menu_select),
2859 GINT_TO_POINTER (GTK_POS_RIGHT));
2860 gtk_menu_append (GTK_MENU (menu), item);
2862 gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
2863 gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
2864 gtk_widget_show (opt);
2866 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2867 gtk_widget_show (box2);
2869 box2 = gtk_hbox_new (FALSE, 10);
2870 gtk_container_border_width (GTK_CONTAINER (box2), 10);
2872 /* Yet another option menu, this time for the update policy of the
2874 label = gtk_label_new ("Scale Update Policy:");
2875 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
2876 gtk_widget_show (label);
2878 opt = gtk_option_menu_new();
2879 menu = gtk_menu_new();
2881 item = make_menu_item ("Continuous",
2882 GTK_SIGNAL_FUNC (cb_update_menu_select),
2883 GINT_TO_POINTER (GTK_UPDATE_CONTINUOUS));
2884 gtk_menu_append (GTK_MENU (menu), item);
2886 item = make_menu_item ("Discontinuous",
2887 GTK_SIGNAL_FUNC (cb_update_menu_select),
2888 GINT_TO_POINTER (GTK_UPDATE_DISCONTINUOUS));
2889 gtk_menu_append (GTK_MENU (menu), item);
2891 item = make_menu_item ("Delayed",
2892 GTK_SIGNAL_FUNC (cb_update_menu_select),
2893 GINT_TO_POINTER (GTK_UPDATE_DELAYED));
2894 gtk_menu_append (GTK_MENU (menu), item);
2896 gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
2897 gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
2898 gtk_widget_show (opt);
2900 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2901 gtk_widget_show (box2);
2903 box2 = gtk_hbox_new (FALSE, 10);
2904 gtk_container_border_width (GTK_CONTAINER (box2), 10);
2906 /* A GtkHScale widget for adjusting the number of digits on the
2908 label = gtk_label_new ("Scale Digits:");
2909 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
2910 gtk_widget_show (label);
2912 adj2 = gtk_adjustment_new (1.0, 0.0, 5.0, 1.0, 1.0, 0.0);
2913 gtk_signal_connect (GTK_OBJECT (adj2), "value_changed",
2914 GTK_SIGNAL_FUNC (cb_digits_scale), NULL);
2915 scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
2916 gtk_scale_set_digits (GTK_SCALE (scale), 0);
2917 gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
2918 gtk_widget_show (scale);
2920 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2921 gtk_widget_show (box2);
2923 box2 = gtk_hbox_new (FALSE, 10);
2924 gtk_container_border_width (GTK_CONTAINER (box2), 10);
2926 /* And, one last GtkHScale widget for adjusting the page size of the
2928 label = gtk_label_new ("Scrollbar Page Size:");
2929 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
2930 gtk_widget_show (label);
2932 adj2 = gtk_adjustment_new (1.0, 1.0, 101.0, 1.0, 1.0, 0.0);
2933 gtk_signal_connect (GTK_OBJECT (adj2), "value_changed",
2934 GTK_SIGNAL_FUNC (cb_page_size), adj1);
2935 scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
2936 gtk_scale_set_digits (GTK_SCALE (scale), 0);
2937 gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
2938 gtk_widget_show (scale);
2940 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2941 gtk_widget_show (box2);
2943 separator = gtk_hseparator_new ();
2944 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
2945 gtk_widget_show (separator);
2947 box2 = gtk_vbox_new (FALSE, 10);
2948 gtk_container_border_width (GTK_CONTAINER (box2), 10);
2949 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
2950 gtk_widget_show (box2);
2952 button = gtk_button_new_with_label ("Quit");
2953 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2954 GTK_SIGNAL_FUNC(gtk_main_quit),
2956 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2957 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
2958 gtk_widget_grab_default (button);
2959 gtk_widget_show (button);
2961 gtk_widget_show (window);
2967 gtk_init(&argc, &argv);
2969 create_range_controls();
2981 <!-- ***************************************************************** -->
2982 <sect> Miscellaneous Widgets
2983 <!-- ***************************************************************** -->
2985 <!-- ----------------------------------------------------------------- -->
2988 Labels are used a lot in GTK, and are relatively simple. Labels emit
2989 no signals as they do not have an associated X window. If you need to
2990 catch signals, or do clipping, use the <ref id="sec_EventBox"
2991 name="EventBox"> widget.
2993 To create a new label, use:
2996 GtkWidget *gtk_label_new( char *str );
2999 Where the sole argument is the string you wish the label to display.
3001 To change the label's text after creation, use the function:
3004 void gtk_label_set( GtkLabel *label,
3008 Where the first argument is the label you created previously (cast
3009 using the GTK_LABEL() macro), and the second is the new string.
3011 The space needed for the new string will be automatically adjusted if
3014 To retrieve the current string, use:
3017 void gtk_label_get( GtkLabel *label,
3021 Where the first argument is the label you've created, and the second,
3022 the return for the string.
3024 <!-- ----------------------------------------------------------------- -->
3025 <sect1>The Tooltips Widget
3027 These are the little text strings that pop up when you leave your
3028 pointer over a button or other widget for a few seconds. They are easy
3029 to use, so I will just explain them without giving an example. If you
3030 want to see some code, take a look at the testgtk.c program
3031 distributed with GTK.
3033 Widgets that do not receieve events (widgets that do not have their
3034 own window) will not work with tooltips.
3036 The first call you will use creates a new tooltip. You only need to do
3037 this once for a set of tooltips as the <tt/GtkTooltip/ object this
3038 function returns can be used to create multiple tooltips.
3041 GtkTooltips *gtk_tooltips_new( void );
3044 Once you have created a new tooltip, and the widget you wish to use it
3045 on, simply use this call to set it:
3048 void gtk_tooltips_set_tip( GtkTooltips *tooltips,
3050 const gchar *tip_text,
3051 const gchar *tip_private );
3054 The first argument is the tooltip you've already created, followed by
3055 the widget you wish to have this tooltip pop up for, and the text you
3056 wish it to say. The last argument is a text string that can be used as
3057 an identifier when using GtkTipsQuery to implement context sensitive
3058 help. For now, you can set it to NULL.
3060 <!-- TODO: sort out what how to do the context sensitive help -->
3062 Here's a short example:
3065 GtkTooltips *tooltips;
3070 tooltips = gtk_tooltips_new ();
3071 button = gtk_button_new_with_label ("button 1");
3075 gtk_tooltips_set_tip (tooltips, button, "This is button 1", NULL);
3078 There are other calls that can be used with tooltips. I will just list
3079 them with a brief description of what they do.
3082 void gtk_tooltips_enable( GtkTooltips *tooltips );
3085 Enable a disabled set of tooltips.
3088 void gtk_tooltips_disable( GtkTooltips *tooltips );
3091 Disable an enabled set of tooltips.
3094 void gtk_tooltips_set_delay( GtkTooltips *tooltips,
3099 Sets how many milliseconds you have to hold your pointer over the
3100 widget before the tooltip will pop up. The default is 500
3101 milliseconds (half a second).
3104 void gtk_tooltips_set_colors( GtkTooltips *tooltips,
3105 GdkColor *background,
3106 GdkColor *foreground );
3109 Set the foreground and background color of the tooltips.
3111 And that's all the functions associated with tooltips. More than
3112 you'll ever want to know :-)
3114 <!-- ----------------------------------------------------------------- -->
3115 <sect1> Progress Bars
3117 Progress bars are used to show the status of an operation. They are
3118 pretty easy to use, as you will see with the code below. But first
3119 lets start out with the calls to create a new progress bar.
3121 There are two ways to create a progress bar, one simple one takes
3122 no arguments, and one that takes a GtkAdjustment object as an
3123 argument. If the former is used, the progress bar creates it's own
3127 GtkWidget *gtk_progress_bar_new( void );
3129 GtkWidget *gtk_progress_bar_new_with_adjustment( GtkAdjustment *adjustment );
3132 The second method has the advantage that we can use the adjustment
3133 object to specify our own range parameters for the progress bar.
3135 Now that the progress bar has been created we can use it.
3138 void gtk_progress_bar_update( GtkProgressBar *pbar,
3139 gfloat percentage );
3142 The first argument is the progress bar you wish to operate on, and the
3143 second argument is the amount 'completed', meaning the amount the
3144 progress bar has been filled from 0-100%. This is passed to the
3145 function as a real number ranging from 0 to 1.
3147 GTK v1.1 has added new functionality to the progress bar that enables
3148 it to display it's value in different ways, and to inform the user of
3149 its current value and its range.
3151 A progress bar may be set to one of a number of orientations using the
3155 void gtk_progress_bar_set_orientation( GtkProgressBar *pbar,
3156 GtkProgressBarOrientation orientation );
3159 Where the <tt/orientation/ argument may take one of the following
3160 values to indicate the direction in which the progress bar moves:
3163 <item> GTK_PROGRESS_LEFT_TO_RIGHT
3164 <item> GTK_PROGRESS_RIGHT_TO_LEFT
3165 <item> GTK_PROGRESS_BOTTOM_TO_TOP
3166 <item> GTK_PROGRESS_TOP_TO_BOTTOM
3169 When used as a measure of how far a process has progressed, the
3170 GtkProgressBar can be set to display it's value in either a continuous
3171 or discrete mode. In continuous mode, the progress bar is updated for
3172 each value. In discrete mode, the progress bar is updated in a number
3173 of discrete blocks. The number of blocks is also configurable.
3175 The style of a progress bar can be set using the following function.
3178 void gtk_progress_bar_set_bar_style( GtkProgressBar *pbar,
3179 GtkProgressBarStyle style );
3182 The <tt/style/ parameter can take one of two values:
3185 <item>GTK_PROGRESS_CONTINUOUS
3186 <item>GTK_PROGRESS_DISCRETE
3189 The number of discrete blocks can be set by calling
3192 void gtk_progress_bar_set_discrete_blocks( GtkProgressBar *pbar,
3196 As well as indicating the amount of progress that has occured, the
3197 progress bar may be set to just indicate that there is some
3198 activity. This can be useful in situations where progress cannot be
3199 measured against a value range. Activity mode is not effected by the
3200 bar style that is described above, and overrides it.This mode is
3201 selected by the following function.
3204 void gtk_progress_set_activity_mode( GtkProgress *progress,
3205 guint activity_mode );
3208 The step size of the activity indicator, and the number of blocks are
3209 set using the following functions.
3212 void gtk_progress_bar_set_activity_step( GtkProgressBar *pbar,
3215 void gtk_progress_bar_set_activity_blocks( GtkProgressBar *pbar,
3219 When in continuous mode, the progress bar can also display a
3220 configurable text string within it's trough, using the following
3224 void gtk_progress_set_format_string( GtkProgress *progress,
3228 The <tt/format/ argument is similiar to one that would be used in a C
3229 <tt/printf/ statement. The following directives may be used within the
3233 <item> %p - percentage
3235 <item> %l - lower range value
3236 <item> %u - upper range value
3239 Progress Bars are usually used with timeouts or other such functions
3240 (see section on <ref id="sec_timeouts" name="Timeouts, I/O and Idle
3241 Functions">) to give the illusion of multitasking. All will employ the
3242 gtk_progress_bar_update function in the same manner.
3244 Here is an example of the progress bar, updated using timeouts. This
3245 code also shows you how to reset the Progress Bar.
3248 /* example-start progressbar progressbar.c */
3250 #include <gtk/gtk.h>
3252 typedef struct _ProgressData {
3258 /* Update the value of the progress bar so that we get
3260 gint progress_timeout( gpointer data )
3265 adj = GTK_PROGRESS (data)->adjustment;
3267 /* Calculate the value of the progress bar using the
3268 * value range set in the adjustment object */
3269 new_val = adj->value + 1;
3270 if (new_val > adj->upper)
3271 new_val = adj->lower;
3273 /* Set the new value */
3274 gtk_progress_set_value (GTK_PROGRESS (data), new_val);
3276 /* As this is a timeout function, return TRUE so that it
3277 * continues to get called */
3281 /* Callback that toggles the text display within the progress
3283 void toggle_show_text( GtkWidget *widget,
3284 ProgressData *pdata )
3286 gtk_progress_set_show_text (GTK_PROGRESS (pdata->pbar),
3287 GTK_TOGGLE_BUTTON (widget)->active);
3290 /* Callback that toggles the activity mode of the progress
3292 void toggle_activity_mode( GtkWidget *widget,
3293 ProgressData *pdata )
3295 gtk_progress_set_activity_mode (GTK_PROGRESS (pdata->pbar),
3296 GTK_TOGGLE_BUTTON (widget)->active);
3299 /* Callback that toggles the continuous mode of the progress
3301 void set_continuous_mode( GtkWidget *widget,
3302 ProgressData *pdata )
3304 gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
3305 GTK_PROGRESS_CONTINUOUS);
3308 /* Callback that toggles the discrete mode of the progress
3310 void set_discrete_mode( GtkWidget *widget,
3311 ProgressData *pdata )
3313 gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
3314 GTK_PROGRESS_DISCRETE);
3317 /* Clean up allocated memory and remove the timer */
3318 void destroy_progress( GtkWidget *widget,
3319 ProgressData *pdata)
3321 gtk_timeout_remove (pdata->timer);
3323 pdata->window = NULL;
3331 ProgressData *pdata;
3333 GtkWidget *separator;
3340 gtk_init (&argc, &argv);
3342 /* Allocate memory for the data that is passwd to the callbacks */
3343 pdata = g_malloc( sizeof(ProgressData) );
3345 pdata->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3346 gtk_window_set_policy (GTK_WINDOW (pdata->window), FALSE, FALSE, TRUE);
3348 gtk_signal_connect (GTK_OBJECT (pdata->window), "destroy",
3349 GTK_SIGNAL_FUNC (destroy_progress),
3351 gtk_window_set_title (GTK_WINDOW (pdata->window), "GtkProgressBar");
3352 gtk_container_set_border_width (GTK_CONTAINER (pdata->window), 0);
3354 vbox = gtk_vbox_new (FALSE, 5);
3355 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
3356 gtk_container_add (GTK_CONTAINER (pdata->window), vbox);
3357 gtk_widget_show(vbox);
3359 /* Create a centering alignment object */
3360 align = gtk_alignment_new (0.5, 0.5, 0, 0);
3361 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 5);
3362 gtk_widget_show(align);
3364 /* Create a GtkAdjusment object to hold the range of the
3366 adj = (GtkAdjustment *) gtk_adjustment_new (0, 1, 150, 0, 0, 0);
3368 /* Create the GtkProgressBar using the adjustment */
3369 pdata->pbar = gtk_progress_bar_new_with_adjustment (adj);
3371 /* Set the format of the string that can be displayed in the
3372 * trough of the progress bar:
3375 * %l - lower range value
3376 * %u - upper range value */
3377 gtk_progress_set_format_string (GTK_PROGRESS (pdata->pbar),
3378 "%v from [%l-%u] (=%p%%)");
3379 gtk_container_add (GTK_CONTAINER (align), pdata->pbar);
3380 gtk_widget_show(pdata->pbar);
3382 /* Add a timer callback to update the value of the progress bar */
3383 pdata->timer = gtk_timeout_add (100, progress_timeout, pdata->pbar);
3385 separator = gtk_hseparator_new ();
3386 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
3387 gtk_widget_show(separator);
3389 /* rows, columns, homogeneous */
3390 table = gtk_table_new (2, 3, FALSE);
3391 gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0);
3392 gtk_widget_show(table);
3394 /* Add a check button to select displaying of the trough text */
3395 check = gtk_check_button_new_with_label ("Show text");
3396 gtk_table_attach (GTK_TABLE (table), check, 0, 1, 0, 1,
3397 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3399 gtk_signal_connect (GTK_OBJECT (check), "clicked",
3400 GTK_SIGNAL_FUNC (toggle_show_text),
3402 gtk_widget_show(check);
3404 /* Add a check button to toggle activity mode */
3405 check = gtk_check_button_new_with_label ("Activity mode");
3406 gtk_table_attach (GTK_TABLE (table), check, 0, 1, 1, 2,
3407 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3409 gtk_signal_connect (GTK_OBJECT (check), "clicked",
3410 GTK_SIGNAL_FUNC (toggle_activity_mode),
3412 gtk_widget_show(check);
3414 separator = gtk_vseparator_new ();
3415 gtk_table_attach (GTK_TABLE (table), separator, 1, 2, 0, 2,
3416 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3418 gtk_widget_show(separator);
3420 /* Add a radio button to select continuous display mode */
3421 button = gtk_radio_button_new_with_label (NULL, "Continuous");
3422 gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1,
3423 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3425 gtk_signal_connect (GTK_OBJECT (button), "clicked",
3426 GTK_SIGNAL_FUNC (set_continuous_mode),
3428 gtk_widget_show (button);
3430 /* Add a radio button to select discrete display mode */
3431 button = gtk_radio_button_new_with_label(
3432 gtk_radio_button_group (GTK_RADIO_BUTTON (button)),
3434 gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2,
3435 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3437 gtk_signal_connect (GTK_OBJECT (button), "clicked",
3438 GTK_SIGNAL_FUNC (set_discrete_mode),
3440 gtk_widget_show (button);
3442 separator = gtk_hseparator_new ();
3443 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
3444 gtk_widget_show(separator);
3446 /* Add a button to exit the program */
3447 button = gtk_button_new_with_label ("close");
3448 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
3449 (GtkSignalFunc) gtk_widget_destroy,
3450 GTK_OBJECT (pdata->window));
3451 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
3453 /* This makes it so the button is the default. */
3454 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
3456 /* This grabs this button to be the default button. Simply hitting
3457 * the "Enter" key will cause this button to activate. */
3458 gtk_widget_grab_default (button);
3459 gtk_widget_show(button);
3461 gtk_widget_show (pdata->window);
3470 <!-- ----------------------------------------------------------------- -->
3473 The Dialog widget is very simple, and is actually just a window with a
3474 few things pre-packed into it for you. The structure for a Dialog is:
3482 GtkWidget *action_area;
3486 So you see, it simply creates a window, and then packs a vbox into the
3487 top, then a separator, and then an hbox for the "action_area".
3489 The Dialog widget can be used for pop-up messages to the user, and
3490 other similar tasks. It is really basic, and there is only one
3491 function for the dialog box, which is:
3494 GtkWidget *gtk_dialog_new( void );
3497 So to create a new dialog box, use,
3501 window = gtk_dialog_new ();
3504 This will create the dialog box, and it is now up to you to use it.
3505 you could pack a button in the action_area by doing something like this:
3509 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area),
3510 button, TRUE, TRUE, 0);
3511 gtk_widget_show (button);
3514 And you could add to the vbox area by packing, for instance, a label
3515 in it, try something like this:
3518 label = gtk_label_new ("Dialogs are groovy");
3519 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox),
3520 label, TRUE, TRUE, 0);
3521 gtk_widget_show (label);
3524 As an example in using the dialog box, you could put two buttons in
3525 the action_area, a Cancel button and an Ok button, and a label in the
3526 vbox area, asking the user a question or giving an error etc. Then
3527 you could attach a different signal to each of the buttons and perform
3528 the operation the user selects.
3530 If the simple functionality provided by the default vertical and
3531 horizontal boxes in the two areas does't give you enough control for
3532 your application, then you can simply pack another layout widget into
3533 the boxes provided. For example, you could pack a table into the
3536 <!-- ----------------------------------------------------------------- -->
3537 <sect1> Pixmaps <label id="sec_Pixmaps">
3539 Pixmaps are data structures that contain pictures. These pictures can
3540 be used in various places, but most visibly as icons on the X-Windows
3541 desktop, or as cursors. A bitmap is a 2-color pixmap.
3543 To use pixmaps in GTK, we must first build a GdkPixmap structure using
3544 routines from the GDK layer. Pixmaps can either be created from
3545 in-memory data, or from data read from a file. We'll go through each
3546 of the calls to create a pixmap.
3549 GdkPixmap *gdk_bitmap_create_from_data( GdkWindow *window,
3555 This routine is used to create a single-plane pixmap (2 colors) from
3556 data in memory. Each bit of the data represents whether that pixel is
3557 off or on. Width and height are in pixels. The GdkWindow pointer is
3558 to the current window, since a pixmap resources are meaningful only in
3559 the context of the screen where it is to be displayed.
3562 GdkPixmap *gdk_pixmap_create_from_data( GdkWindow *window,
3571 This is used to create a pixmap of the given depth (number of colors) from
3572 the bitmap data specified. <tt/fg/ and <tt/bg/ are the foreground and
3573 background color to use.
3576 GdkPixmap *gdk_pixmap_create_from_xpm( GdkWindow *window,
3578 GdkColor *transparent_color,
3579 const gchar *filename );
3582 XPM format is a readable pixmap representation for the X Window
3583 System. It is widely used and many different utilities are available
3584 for creating image files in this format. The file specified by
3585 filename must contain an image in that format and it is loaded into
3586 the pixmap structure. The mask specifies which bits of the pixmap are
3587 opaque. All other bits are colored using the color specified by
3588 transparent_color. An example using this follows below.
3591 GdkPixmap *gdk_pixmap_create_from_xpm_d( GdkWindow *window,
3593 GdkColor *transparent_color,
3597 Small images can be incorporated into a program as data in the XPM
3598 format. A pixmap is created using this data, instead of reading it
3599 from a file. An example of such data is
3603 static const char * xpm_data[] = {
3606 ". c #000000000000",
3607 "X c #FFFFFFFFFFFF",
3626 When we're done using a pixmap and not likely to reuse it again soon,
3627 it is a good idea to release the resource using
3628 gdk_pixmap_unref(). Pixmaps should be considered a precious resource.
3630 Once we've created a pixmap, we can display it as a GTK widget. We
3631 must create a GTK pixmap widget to contain the GDK pixmap. This is
3635 GtkWidget *gtk_pixmap_new( GdkPixmap *pixmap,
3639 The other pixmap widget calls are
3642 guint gtk_pixmap_get_type( void );
3644 void gtk_pixmap_set( GtkPixmap *pixmap,
3648 void gtk_pixmap_get( GtkPixmap *pixmap,
3653 gtk_pixmap_set is used to change the pixmap that the widget is currently
3654 managing. Val is the pixmap created using GDK.
3656 The following is an example of using a pixmap in a button.
3659 /* example-start pixmap pixmap.c */
3661 #include <gtk/gtk.h>
3664 /* XPM data of Open-File icon */
3665 static const char * xpm_data[] = {
3668 ". c #000000000000",
3669 "X c #FFFFFFFFFFFF",
3688 /* when invoked (via signal delete_event), terminates the application.
3690 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
3695 /* is invoked when the button is clicked. It just prints a message.
3697 void button_clicked( GtkWidget *widget, gpointer data ) {
3698 printf( "button clicked\n" );
3701 int main( int argc, char *argv[] )
3703 /* GtkWidget is the storage type for widgets */
3704 GtkWidget *window, *pixmapwid, *button;
3709 /* create the main window, and attach delete_event signal to terminating
3711 gtk_init( &argc, &argv );
3712 window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
3713 gtk_signal_connect( GTK_OBJECT (window), "delete_event",
3714 GTK_SIGNAL_FUNC (close_application), NULL );
3715 gtk_container_border_width( GTK_CONTAINER (window), 10 );
3716 gtk_widget_show( window );
3718 /* now for the pixmap from gdk */
3719 style = gtk_widget_get_style( window );
3720 pixmap = gdk_pixmap_create_from_xpm_d( window->window, &mask,
3721 &style->bg[GTK_STATE_NORMAL],
3722 (gchar **)xpm_data );
3724 /* a pixmap widget to contain the pixmap */
3725 pixmapwid = gtk_pixmap_new( pixmap, mask );
3726 gtk_widget_show( pixmapwid );
3728 /* a button to contain the pixmap widget */
3729 button = gtk_button_new();
3730 gtk_container_add( GTK_CONTAINER(button), pixmapwid );
3731 gtk_container_add( GTK_CONTAINER(window), button );
3732 gtk_widget_show( button );
3734 gtk_signal_connect( GTK_OBJECT(button), "clicked",
3735 GTK_SIGNAL_FUNC(button_clicked), NULL );
3737 /* show the window */
3745 To load a file from an XPM data file called icon0.xpm in the current
3746 directory, we would have created the pixmap thus
3749 /* load a pixmap from a file */
3750 pixmap = gdk_pixmap_create_from_xpm( window->window, &mask,
3751 &style->bg[GTK_STATE_NORMAL],
3753 pixmapwid = gtk_pixmap_new( pixmap, mask );
3754 gtk_widget_show( pixmapwid );
3755 gtk_container_add( GTK_CONTAINER(window), pixmapwid );
3758 A disadvantage of using pixmaps is that the displayed object is always
3759 rectangular, regardless of the image. We would like to create desktops
3760 and applications with icons that have more natural shapes. For
3761 example, for a game interface, we would like to have round buttons to
3762 push. The way to do this is using shaped windows.
3764 A shaped window is simply a pixmap where the background pixels are
3765 transparent. This way, when the background image is multi-colored, we
3766 don't overwrite it with a rectangular, non-matching border around our
3767 icon. The following example displays a full wheelbarrow image on the
3771 /* example-start wheelbarrow wheelbarrow.c */
3773 #include <gtk/gtk.h>
3776 static char * WheelbarrowFull_xpm[] = {
3779 ". c #DF7DCF3CC71B",
3780 "X c #965875D669A6",
3781 "o c #71C671C671C6",
3782 "O c #A699A289A699",
3783 "+ c #965892489658",
3784 "@ c #8E38410330C2",
3785 "# c #D75C7DF769A6",
3786 "$ c #F7DECF3CC71B",
3787 "% c #96588A288E38",
3788 "& c #A69992489E79",
3789 "* c #8E3886178E38",
3790 "= c #104008200820",
3791 "- c #596510401040",
3792 "; c #C71B30C230C2",
3793 ": c #C71B9A699658",
3794 "> c #618561856185",
3795 ", c #20811C712081",
3796 "< c #104000000000",
3797 "1 c #861720812081",
3798 "2 c #DF7D4D344103",
3799 "3 c #79E769A671C6",
3800 "4 c #861782078617",
3801 "5 c #41033CF34103",
3802 "6 c #000000000000",
3803 "7 c #49241C711040",
3804 "8 c #492445144924",
3805 "9 c #082008200820",
3806 "0 c #69A618611861",
3807 "q c #B6DA71C65144",
3808 "w c #410330C238E3",
3809 "e c #CF3CBAEAB6DA",
3810 "r c #71C6451430C2",
3811 "t c #EFBEDB6CD75C",
3812 "y c #28A208200820",
3813 "u c #186110401040",
3814 "i c #596528A21861",
3815 "p c #71C661855965",
3816 "a c #A69996589658",
3817 "s c #30C228A230C2",
3818 "d c #BEFBA289AEBA",
3819 "f c #596545145144",
3820 "g c #30C230C230C2",
3821 "h c #8E3882078617",
3822 "j c #208118612081",
3823 "k c #38E30C300820",
3824 "l c #30C2208128A2",
3825 "z c #38E328A238E3",
3826 "x c #514438E34924",
3827 "c c #618555555965",
3828 "v c #30C2208130C2",
3829 "b c #38E328A230C2",
3830 "n c #28A228A228A2",
3831 "m c #41032CB228A2",
3832 "M c #104010401040",
3833 "N c #492438E34103",
3834 "B c #28A2208128A2",
3835 "V c #A699596538E3",
3836 "C c #30C21C711040",
3837 "Z c #30C218611040",
3838 "A c #965865955965",
3839 "S c #618534D32081",
3840 "D c #38E31C711040",
3841 "F c #082000000820",
3850 "ty> 459@>+&& ",
3852 "%$;=* *3:.Xa.dfg> ",
3853 "Oh$;ya *3d.a8j,Xe.d3g8+ ",
3854 " Oh$;ka *3d$a8lz,,xxc:.e3g54 ",
3855 " Oh$;kO *pd$%svbzz,sxxxxfX..&wn> ",
3856 " Oh$@mO *3dthwlsslszjzxxxxxxx3:td8M4 ",
3857 " Oh$@g& *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B* ",
3858 " Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5& ",
3859 " Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM* ",
3860 " OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
3861 " 2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
3862 " :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
3863 " +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
3864 " *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&en",
3865 " p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>",
3866 " OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ",
3867 " 3206Bwxxszx%et.eaAp77m77mmmf3&eeeg* ",
3868 " @26MvzxNzvlbwfpdettttttttttt.c,n& ",
3869 " *;16=lsNwwNwgsvslbwwvccc3pcfu<o ",
3870 " p;<69BvwwsszslllbBlllllllu<5+ ",
3871 " OS0y6FBlvvvzvzss,u=Blllj=54 ",
3872 " c1-699Blvlllllu7k96MMMg4 ",
3873 " *10y8n6FjvllllB<166668 ",
3874 " S-kg+>666<M<996-y6n<8* ",
3875 " p71=4 m69996kD8Z-66698&& ",
3876 " &i0ycm6n4 ogk17,0<6666g ",
3877 " N-k-<> >=01-kuu666> ",
3878 " ,6ky& &46-10ul,66, ",
3879 " Ou0<> o66y<ulw<66& ",
3880 " *kk5 >66By7=xu664 ",
3881 " <<M4 466lj<Mxu66o ",
3882 " *>> +66uv,zN666* ",
3892 /* When invoked (via signal delete_event), terminates the application */
3893 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
3897 int main (int argc, char *argv[])
3899 /* GtkWidget is the storage type for widgets */
3900 GtkWidget *window, *pixmap, *fixed;
3901 GdkPixmap *gdk_pixmap;
3906 /* Create the main window, and attach delete_event signal to terminate
3907 * the application. Note that the main window will not have a titlebar
3908 * since we're making it a popup. */
3909 gtk_init (&argc, &argv);
3910 window = gtk_window_new( GTK_WINDOW_POPUP );
3911 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
3912 GTK_SIGNAL_FUNC (close_application), NULL);
3913 gtk_widget_show (window);
3915 /* Now for the pixmap and the pixmap widget */
3916 style = gtk_widget_get_default_style();
3917 gc = style->black_gc;
3918 gdk_pixmap = gdk_pixmap_create_from_xpm_d( window->window, &mask,
3919 &style->bg[GTK_STATE_NORMAL],
3920 WheelbarrowFull_xpm );
3921 pixmap = gtk_pixmap_new( gdk_pixmap, mask );
3922 gtk_widget_show( pixmap );
3924 /* To display the pixmap, we use a fixed widget to place the pixmap */
3925 fixed = gtk_fixed_new();
3926 gtk_widget_set_usize( fixed, 200, 200 );
3927 gtk_fixed_put( GTK_FIXED(fixed), pixmap, 0, 0 );
3928 gtk_container_add( GTK_CONTAINER(window), fixed );
3929 gtk_widget_show( fixed );
3931 /* This masks out everything except for the image itself */
3932 gtk_widget_shape_combine_mask( window, mask, 0, 0 );
3934 /* show the window */
3935 gtk_widget_set_uposition( window, 20, 400 );
3936 gtk_widget_show( window );
3944 To make the wheelbarrow image sensitive, we could attach the button
3945 press event signal to make it do something. The following few lines
3946 would make the picture sensitive to a mouse button being pressed which
3947 makes the application terminate.
3950 gtk_widget_set_events( window,
3951 gtk_widget_get_events( window ) |
3952 GDK_BUTTON_PRESS_MASK );
3954 gtk_signal_connect( GTK_OBJECT(window), "button_press_event",
3955 GTK_SIGNAL_FUNC(close_application), NULL );
3958 <!-- ----------------------------------------------------------------- -->
3961 Ruler widgets are used to indicate the location of the mouse pointer
3962 in a given window. A window can have a vertical ruler spanning across
3963 the width and a horizontal ruler spanning down the height. A small
3964 triangular indicator on the ruler shows the exact location of the
3965 pointer relative to the ruler.
3967 A ruler must first be created. Horizontal and vertical rulers are
3971 GtkWidget *gtk_hruler_new( void ); /* horizontal ruler */
3973 GtkWidget *gtk_vruler_new( void ); /* vertical ruler */
3976 Once a ruler is created, we can define the unit of measurement. Units
3977 of measure for rulers can be GTK_PIXELS, GTK_INCHES or
3978 GTK_CENTIMETERS. This is set using
3981 void gtk_ruler_set_metric( GtkRuler *ruler,
3982 GtkMetricType metric );
3985 The default measure is GTK_PIXELS.
3988 gtk_ruler_set_metric( GTK_RULER(ruler), GTK_PIXELS );
3991 Other important characteristics of a ruler are how to mark the units
3992 of scale and where the position indicator is initially placed. These
3993 are set for a ruler using
3996 void gtk_ruler_set_range( GtkRuler *ruler,
4003 The lower and upper arguments define the extent of the ruler, and
4004 max_size is the largest possible number that will be displayed.
4005 Position defines the initial position of the pointer indicator within
4008 A vertical ruler can span an 800 pixel wide window thus
4011 gtk_ruler_set_range( GTK_RULER(vruler), 0, 800, 0, 800);
4014 The markings displayed on the ruler will be from 0 to 800, with a
4015 number for every 100 pixels. If instead we wanted the ruler to range
4016 from 7 to 16, we would code
4019 gtk_ruler_set_range( GTK_RULER(vruler), 7, 16, 0, 20);
4022 The indicator on the ruler is a small triangular mark that indicates
4023 the position of the pointer relative to the ruler. If the ruler is
4024 used to follow the mouse pointer, the motion_notify_event signal
4025 should be connected to the motion_notify_event method of the ruler.
4026 To follow all mouse movements within a window area, we would use
4029 #define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
4031 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4032 (GtkSignalFunc)EVENT_METHOD(ruler, motion_notify_event),
4033 GTK_OBJECT(ruler) );
4036 The following example creates a drawing area with a horizontal ruler
4037 above it and a vertical ruler to the left of it. The size of the
4038 drawing area is 600 pixels wide by 400 pixels high. The horizontal
4039 ruler spans from 7 to 13 with a mark every 100 pixels, while the
4040 vertical ruler spans from 0 to 400 with a mark every 100 pixels.
4041 Placement of the drawing area and the rulers is done using a table.
4044 /* example-start rulers rulers.c */
4046 #include <gtk/gtk.h>
4048 #define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
4053 /* This routine gets control when the close button is clicked */
4054 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
4058 /* The main routine */
4059 int main( int argc, char *argv[] ) {
4060 GtkWidget *window, *table, *area, *hrule, *vrule;
4062 /* Initialize GTK and create the main window */
4063 gtk_init( &argc, &argv );
4065 window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
4066 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
4067 GTK_SIGNAL_FUNC( close_application ), NULL);
4068 gtk_container_border_width (GTK_CONTAINER (window), 10);
4070 /* Create a table for placing the ruler and the drawing area */
4071 table = gtk_table_new( 3, 2, FALSE );
4072 gtk_container_add( GTK_CONTAINER(window), table );
4074 area = gtk_drawing_area_new();
4075 gtk_drawing_area_size( (GtkDrawingArea *)area, XSIZE, YSIZE );
4076 gtk_table_attach( GTK_TABLE(table), area, 1, 2, 1, 2,
4077 GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0 );
4078 gtk_widget_set_events( area, GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK );
4080 /* The horizontal ruler goes on top. As the mouse moves across the drawing area,
4081 * a motion_notify_event is passed to the appropriate event handler for the ruler. */
4082 hrule = gtk_hruler_new();
4083 gtk_ruler_set_metric( GTK_RULER(hrule), GTK_PIXELS );
4084 gtk_ruler_set_range( GTK_RULER(hrule), 7, 13, 0, 20 );
4085 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4086 (GtkSignalFunc)EVENT_METHOD(hrule, motion_notify_event),
4087 GTK_OBJECT(hrule) );
4088 /* GTK_WIDGET_CLASS(GTK_OBJECT(hrule)->klass)->motion_notify_event, */
4089 gtk_table_attach( GTK_TABLE(table), hrule, 1, 2, 0, 1,
4090 GTK_EXPAND|GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0 );
4092 /* The vertical ruler goes on the left. As the mouse moves across the drawing area,
4093 * a motion_notify_event is passed to the appropriate event handler for the ruler. */
4094 vrule = gtk_vruler_new();
4095 gtk_ruler_set_metric( GTK_RULER(vrule), GTK_PIXELS );
4096 gtk_ruler_set_range( GTK_RULER(vrule), 0, YSIZE, 10, YSIZE );
4097 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4099 GTK_WIDGET_CLASS(GTK_OBJECT(vrule)->klass)->motion_notify_event,
4100 GTK_OBJECT(vrule) );
4101 gtk_table_attach( GTK_TABLE(table), vrule, 0, 1, 1, 2,
4102 GTK_FILL, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0 );
4104 /* Now show everything */
4105 gtk_widget_show( area );
4106 gtk_widget_show( hrule );
4107 gtk_widget_show( vrule );
4108 gtk_widget_show( table );
4109 gtk_widget_show( window );
4117 <!-- ----------------------------------------------------------------- -->
4120 Statusbars are simple widgets used to display a text message. They
4121 keep a stack of the messages pushed onto them, so that popping the
4122 current message will re-display the previous text message.
4124 In order to allow different parts of an application to use the same
4125 statusbar to display messages, the statusbar widget issues Context
4126 Identifiers which are used to identify different 'users'. The message
4127 on top of the stack is the one displayed, no matter what context it is
4128 in. Messages are stacked in last-in-first-out order, not context
4131 A statusbar is created with a call to:
4134 GtkWidget *gtk_statusbar_new( void );
4137 A new Context Identifier is requested using a call to the following
4138 function with a short textual description of the context:
4141 guint gtk_statusbar_get_context_id( GtkStatusbar *statusbar,
4142 const gchar *context_description );
4145 There are three functions that can operate on statusbars:
4148 guint gtk_statusbar_push( GtkStatusbar *statusbar,
4152 void gtk_statusbar_pop( GtkStatusbar *statusbar)
4155 void gtk_statusbar_remove( GtkStatusbar *statusbar,
4160 The first, gtk_statusbar_push, is used to add a new message to the
4161 statusbar. It returns a Message Identifier, which can be passed later
4162 to the function gtk_statusbar_remove to remove the message with the
4163 given Message and Context Identifiers from the statusbar's stack.
4165 The function gtk_statusbar_pop removes the message highest in the
4166 stack with the given Context Identifier.
4168 The following example creates a statusbar and two buttons, one for
4169 pushing items onto the statusbar, and one for popping the last item
4173 /* example-start statusbar statusbar.c */
4175 #include <gtk/gtk.h>
4178 GtkWidget *status_bar;
4180 void push_item (GtkWidget *widget, gpointer data)
4182 static int count = 1;
4185 g_snprintf(buff, 20, "Item %d", count++);
4186 gtk_statusbar_push( GTK_STATUSBAR(status_bar), (guint) &data, buff);
4191 void pop_item (GtkWidget *widget, gpointer data)
4193 gtk_statusbar_pop( GTK_STATUSBAR(status_bar), (guint) &data );
4197 int main (int argc, char *argv[])
4206 gtk_init (&argc, &argv);
4208 /* create a new window */
4209 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4210 gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
4211 gtk_window_set_title(GTK_WINDOW (window), "GTK Statusbar Example");
4212 gtk_signal_connect(GTK_OBJECT (window), "delete_event",
4213 (GtkSignalFunc) gtk_exit, NULL);
4215 vbox = gtk_vbox_new(FALSE, 1);
4216 gtk_container_add(GTK_CONTAINER(window), vbox);
4217 gtk_widget_show(vbox);
4219 status_bar = gtk_statusbar_new();
4220 gtk_box_pack_start (GTK_BOX (vbox), status_bar, TRUE, TRUE, 0);
4221 gtk_widget_show (status_bar);
4223 context_id = gtk_statusbar_get_context_id( GTK_STATUSBAR(status_bar), "Statusbar example");
4225 button = gtk_button_new_with_label("push item");
4226 gtk_signal_connect(GTK_OBJECT(button), "clicked",
4227 GTK_SIGNAL_FUNC (push_item), &context_id);
4228 gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 2);
4229 gtk_widget_show(button);
4231 button = gtk_button_new_with_label("pop last item");
4232 gtk_signal_connect(GTK_OBJECT(button), "clicked",
4233 GTK_SIGNAL_FUNC (pop_item), &context_id);
4234 gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 2);
4235 gtk_widget_show(button);
4237 /* always display the window as the last step so it all splashes on
4238 * the screen at once. */
4239 gtk_widget_show(window);
4248 <!-- ----------------------------------------------------------------- -->
4251 The Entry widget allows text to be typed and displayed in a single line
4252 text box. The text may be set with function calls that allow new text
4253 to replace, prepend or append the current contents of the Entry widget.
4255 There are two functions for creating Entry widgets:
4258 GtkWidget *gtk_entry_new( void );
4260 GtkWidget *gtk_entry_new_with_max_length( guint16 max );
4263 The first just creates a new Entry widget, whilst the second creates a
4264 new Entry and sets a limit on the length of the text within the Entry.
4266 There are several functions for altering the text which is currently
4267 within the Entry widget.
4270 void gtk_entry_set_text( GtkEntry *entry,
4271 const gchar *text );
4273 void gtk_entry_append_text( GtkEntry *entry,
4274 const gchar *text );
4276 void gtk_entry_prepend_text( GtkEntry *entry,
4277 const gchar *text );
4280 The function gtk_entry_set_text sets the contents of the Entry widget,
4281 replacing the current contents. The functions gtk_entry_append_text
4282 and gtk_entry_prepend_text allow the current contents to be appended
4285 The next function allows the current insertion point to be set.
4288 void gtk_entry_set_position( GtkEntry *entry,
4292 The contents of the Entry can be retrieved by using a call to the
4293 following function. This is useful in the callback functions described below.
4296 gchar *gtk_entry_get_text( GtkEntry *entry );
4299 If we don't want the contents of the Entry to be changed by someone typing
4300 into it, we can change its editable state.
4303 void gtk_entry_set_editable( GtkEntry *entry,
4304 gboolean editable );
4307 The function above allows us to toggle the editable state of the
4308 Entry widget by passing in a TRUE or FALSE value for the <tt/editable/
4311 If we are using the Entry where we don't want the text entered to be
4312 visible, for example when a password is being entered, we can use the
4313 following function, which also takes a boolean flag.
4316 void gtk_entry_set_visibility( GtkEntry *entry,
4320 A region of the text may be set as selected by using the following
4321 function. This would most often be used after setting some default
4322 text in an Entry, making it easy for the user to remove it.
4325 void gtk_entry_select_region( GtkEntry *entry,
4330 If we want to catch when the user has entered text, we can connect to
4331 the <tt/activate/ or <tt/changed/ signal. Activate is raised when the
4332 user hits the enter key within the Entry widget. Changed is raised
4333 when the text changes at all, e.g. for every character entered or
4336 The following code is an example of using an Entry widget.
4339 /* example-start entry entry.c */
4341 #include <gtk/gtk.h>
4343 void enter_callback(GtkWidget *widget, GtkWidget *entry)
4346 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
4347 printf("Entry contents: %s\n", entry_text);
4350 void entry_toggle_editable (GtkWidget *checkbutton,
4353 gtk_entry_set_editable(GTK_ENTRY(entry),
4354 GTK_TOGGLE_BUTTON(checkbutton)->active);
4357 void entry_toggle_visibility (GtkWidget *checkbutton,
4360 gtk_entry_set_visibility(GTK_ENTRY(entry),
4361 GTK_TOGGLE_BUTTON(checkbutton)->active);
4364 int main (int argc, char *argv[])
4368 GtkWidget *vbox, *hbox;
4373 gtk_init (&argc, &argv);
4375 /* create a new window */
4376 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4377 gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
4378 gtk_window_set_title(GTK_WINDOW (window), "GTK Entry");
4379 gtk_signal_connect(GTK_OBJECT (window), "delete_event",
4380 (GtkSignalFunc) gtk_exit, NULL);
4382 vbox = gtk_vbox_new (FALSE, 0);
4383 gtk_container_add (GTK_CONTAINER (window), vbox);
4384 gtk_widget_show (vbox);
4386 entry = gtk_entry_new_with_max_length (50);
4387 gtk_signal_connect(GTK_OBJECT(entry), "activate",
4388 GTK_SIGNAL_FUNC(enter_callback),
4390 gtk_entry_set_text (GTK_ENTRY (entry), "hello");
4391 gtk_entry_append_text (GTK_ENTRY (entry), " world");
4392 gtk_entry_select_region (GTK_ENTRY (entry),
4393 0, GTK_ENTRY(entry)->text_length);
4394 gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0);
4395 gtk_widget_show (entry);
4397 hbox = gtk_hbox_new (FALSE, 0);
4398 gtk_container_add (GTK_CONTAINER (vbox), hbox);
4399 gtk_widget_show (hbox);
4401 check = gtk_check_button_new_with_label("Editable");
4402 gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
4403 gtk_signal_connect (GTK_OBJECT(check), "toggled",
4404 GTK_SIGNAL_FUNC(entry_toggle_editable), entry);
4405 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
4406 gtk_widget_show (check);
4408 check = gtk_check_button_new_with_label("Visible");
4409 gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
4410 gtk_signal_connect (GTK_OBJECT(check), "toggled",
4411 GTK_SIGNAL_FUNC(entry_toggle_visibility), entry);
4412 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
4413 gtk_widget_show (check);
4415 button = gtk_button_new_with_label ("Close");
4416 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
4417 GTK_SIGNAL_FUNC(gtk_exit),
4418 GTK_OBJECT (window));
4419 gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
4420 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
4421 gtk_widget_grab_default (button);
4422 gtk_widget_show (button);
4424 gtk_widget_show(window);
4432 <!-- ----------------------------------------------------------------- -->
4433 <sect1> Color Selection
4435 The color selection widget is, not surprisingly, a widget for
4436 interactive selection of colors. This composite widget lets the user
4437 select a color by manipulating RGB (Red, Green, Blue) and HSV (Hue,
4438 Saturation, Value) triples. This is done either by adjusting single
4439 values with sliders or entries, or by picking the desired color from a
4440 hue-saturation wheel/value bar. Optionally, the opacity of the color
4443 The color selection widget currently emits only one signal,
4444 "color_changed", which is emitted whenever the current color in the
4445 widget changes, either when the user changes it or if it's set
4446 explicitly through gtk_color_selection_set_color().
4448 Lets have a look at what the color selection widget has to offer
4449 us. The widget comes in two flavours: gtk_color_selection and
4450 gtk_color_selection_dialog.
4453 GtkWidget *gtk_color_selection_new( void );
4456 You'll probably not be using this constructor directly. It creates an
4457 orphan GtkColorSelection widget which you'll have to parent
4458 yourself. The GtkColorSelection widget inherits from the GtkVBox
4462 GtkWidget *gtk_color_selection_dialog_new( const gchar *title );
4465 This is the most common color selection constructor. It creates a
4466 GtkColorSelectionDialog, which inherits from a GtkDialog. It consists
4467 of a GtkFrame containing a GtkColorSelection widget, a GtkHSeparator
4468 and a GtkHBox with three buttons, "Ok", "Cancel" and "Help". You can
4469 reach these buttons by accessing the "ok_button", "cancel_button" and
4470 "help_button" widgets in the GtkColorSelectionDialog structure,
4471 (i.e. GTK_COLOR_SELECTION_DIALOG(colorseldialog)->ok_button).
4474 void gtk_color_selection_set_update_policy( GtkColorSelection *colorsel,
4475 GtkUpdateType policy );
4478 This function sets the update policy. The default policy is
4479 GTK_UPDATE_CONTINUOUS which means that the current color is updated
4480 continuously when the user drags the sliders or presses the mouse and
4481 drags in the hue-saturation wheel or value bar. If you experience
4482 performance problems, you may want to set the policy to
4483 GTK_UPDATE_DISCONTINUOUS or GTK_UPDATE_DELAYED.
4486 void gtk_color_selection_set_opacity( GtkColorSelection *colorsel,
4490 The color selection widget supports adjusting the opacity of a color
4491 (also known as the alpha channel). This is disabled by
4492 default. Calling this function with use_opacity set to TRUE enables
4493 opacity. Likewise, use_opacity set to FALSE will disable opacity.
4496 void gtk_color_selection_set_color( GtkColorSelection *colorsel,
4500 You can set the current color explicitly by calling this function with
4501 a pointer to an array of colors (gdouble). The length of the array
4502 depends on whether opacity is enabled or not. Position 0 contains the
4503 red component, 1 is green, 2 is blue and opacity is at position 3
4504 (only if opacity is enabled, see
4505 gtk_color_selection_set_opacity()). All values are between 0.0 and
4509 void gtk_color_selection_get_color( GtkColorSelection *colorsel,
4513 When you need to query the current color, typically when you've
4514 received a "color_changed" signal, you use this function. Color is a
4515 pointer to the array of colors to fill in. See the
4516 gtk_color_selection_set_color() function for the description of this
4519 <!-- Need to do a whole section on DnD - TRG
4523 The color sample areas (right under the hue-saturation wheel) supports
4524 drag and drop. The type of drag and drop is "application/x-color". The
4525 message data consists of an array of 4 (or 5 if opacity is enabled)
4526 gdouble values, where the value at position 0 is 0.0 (opacity on) or
4527 1.0 (opacity off) followed by the red, green and blue values at
4528 positions 1,2 and 3 respectively. If opacity is enabled, the opacity
4529 is passed in the value at position 4.
4532 Here's a simple example demonstrating the use of the
4533 GtkColorSelectionDialog. The program displays a window containing a
4534 drawing area. Clicking on it opens a color selection dialog, and
4535 changing the color in the color selection dialog changes the
4539 /* example-start colorsel colorsel.c */
4542 #include <gdk/gdk.h>
4543 #include <gtk/gtk.h>
4545 GtkWidget *colorseldlg = NULL;
4546 GtkWidget *drawingarea = NULL;
4548 /* Color changed handler */
4550 void color_changed_cb (GtkWidget *widget, GtkColorSelection *colorsel)
4554 GdkColormap *colormap;
4556 /* Get drawingarea colormap */
4558 colormap = gdk_window_get_colormap (drawingarea->window);
4560 /* Get current color */
4562 gtk_color_selection_get_color (colorsel,color);
4564 /* Fit to a unsigned 16 bit integer (0..65535) and insert into the GdkColor structure */
4566 gdk_color.red = (guint16)(color[0]*65535.0);
4567 gdk_color.green = (guint16)(color[1]*65535.0);
4568 gdk_color.blue = (guint16)(color[2]*65535.0);
4570 /* Allocate color */
4572 gdk_color_alloc (colormap, &gdk_color);
4574 /* Set window background color */
4576 gdk_window_set_background (drawingarea->window, &gdk_color);
4580 gdk_window_clear (drawingarea->window);
4583 /* Drawingarea event handler */
4585 gint area_event (GtkWidget *widget, GdkEvent *event, gpointer client_data)
4587 gint handled = FALSE;
4588 GtkWidget *colorsel;
4590 /* Check if we've received a button pressed event */
4592 if (event->type == GDK_BUTTON_PRESS && colorseldlg == NULL)
4594 /* Yes, we have an event and there's no colorseldlg yet! */
4598 /* Create color selection dialog */
4600 colorseldlg = gtk_color_selection_dialog_new("Select background color");
4602 /* Get the GtkColorSelection widget */
4604 colorsel = GTK_COLOR_SELECTION_DIALOG(colorseldlg)->colorsel;
4606 /* Connect to the "color_changed" signal, set the client-data to the colorsel widget */
4608 gtk_signal_connect(GTK_OBJECT(colorsel), "color_changed",
4609 (GtkSignalFunc)color_changed_cb, (gpointer)colorsel);
4611 /* Show the dialog */
4613 gtk_widget_show(colorseldlg);
4619 /* Close down and exit handler */
4621 void destroy_window (GtkWidget *widget, gpointer client_data)
4628 gint main (gint argc, gchar *argv[])
4632 /* Initialize the toolkit, remove gtk-related commandline stuff */
4634 gtk_init (&argc,&argv);
4636 /* Create toplevel window, set title and policies */
4638 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4639 gtk_window_set_title (GTK_WINDOW(window), "Color selection test");
4640 gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, TRUE);
4642 /* Attach to the "delete" and "destroy" events so we can exit */
4644 gtk_signal_connect (GTK_OBJECT(window), "delete_event",
4645 (GtkSignalFunc)destroy_window, (gpointer)window);
4647 gtk_signal_connect (GTK_OBJECT(window), "destroy",
4648 (GtkSignalFunc)destroy_window, (gpointer)window);
4650 /* Create drawingarea, set size and catch button events */
4652 drawingarea = gtk_drawing_area_new ();
4654 gtk_drawing_area_size (GTK_DRAWING_AREA(drawingarea), 200, 200);
4656 gtk_widget_set_events (drawingarea, GDK_BUTTON_PRESS_MASK);
4658 gtk_signal_connect (GTK_OBJECT(drawingarea), "event",
4659 (GtkSignalFunc)area_event, (gpointer)drawingarea);
4661 /* Add drawingarea to window, then show them both */
4663 gtk_container_add (GTK_CONTAINER(window), drawingarea);
4665 gtk_widget_show (drawingarea);
4666 gtk_widget_show (window);
4668 /* Enter the gtk main loop (this never returns) */
4672 /* Satisfy grumpy compilers */
4679 <!-- ----------------------------------------------------------------- -->
4680 <sect1> File Selections
4682 The file selection widget is a quick and simple way to display a File
4683 dialog box. It comes complete with Ok, Cancel, and Help buttons, a
4684 great way to cut down on programming time.
4686 To create a new file selection box use:
4689 GtkWidget *gtk_file_selection_new( gchar *title );
4692 To set the filename, for example to bring up a specific directory, or
4693 give a default filename, use this function:
4696 void gtk_file_selection_set_filename( GtkFileSelection *filesel,
4700 To grab the text that the user has entered or clicked on, use this
4704 gchar *gtk_file_selection_get_filename( GtkFileSelection *filesel );
4707 There are also pointers to the widgets contained within the file
4708 selection widget. These are:
4713 <item>selection_entry
4714 <item>selection_text
4721 Most likely you will want to use the ok_button, cancel_button, and
4722 help_button pointers in signaling their use.
4724 Included here is an example stolen from testgtk.c, modified to run on
4725 its own. As you will see, there is nothing much to creating a file
4726 selection widget. While in this example the Help button appears on the
4727 screen, it does nothing as there is not a signal attached to it.
4730 /* example-start filesel filesel.c */
4732 #include <gtk/gtk.h>
4734 /* Get the selected filename and print it to the console */
4735 void file_ok_sel (GtkWidget *w, GtkFileSelection *fs)
4737 g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
4740 void destroy (GtkWidget *widget, gpointer data)
4745 int main (int argc, char *argv[])
4749 gtk_init (&argc, &argv);
4751 /* Create a new file selection widget */
4752 filew = gtk_file_selection_new ("File selection");
4754 gtk_signal_connect (GTK_OBJECT (filew), "destroy",
4755 (GtkSignalFunc) destroy, &filew);
4756 /* Connect the ok_button to file_ok_sel function */
4757 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
4758 "clicked", (GtkSignalFunc) file_ok_sel, filew );
4760 /* Connect the cancel_button to destroy the widget */
4761 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button),
4762 "clicked", (GtkSignalFunc) gtk_widget_destroy,
4763 GTK_OBJECT (filew));
4765 /* Lets set the filename, as if this were a save dialog, and we are giving
4766 a default filename */
4767 gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew),
4770 gtk_widget_show(filew);
4777 <!-- ***************************************************************** -->
4778 <sect> Container Widgets
4779 <!-- ***************************************************************** -->
4781 <!-- ----------------------------------------------------------------- -->
4784 The NoteBook Widget is a collection of 'pages' that overlap each other,
4785 each page contains different information. This widget has become more common
4786 lately in GUI programming, and it is a good way to show blocks of similar
4787 information that warrant separation in their display.
4789 The first function call you will need to know, as you can probably
4790 guess by now, is used to create a new notebook widget.
4793 GtkWidget *gtk_notebook_new( void );
4796 Once the notebook has been created, there are 12 functions that
4797 operate on the notebook widget. Let's look at them individually.
4799 The first one we will look at is how to position the page indicators.
4800 These page indicators or 'tabs' as they are referred to, can be positioned
4801 in four ways: top, bottom, left, or right.
4804 void gtk_notebook_set_tab_pos( GtkNotebook *notebook,
4805 GtkPositionType pos );
4808 GtkPostionType will be one of the following, and they are pretty self explanatory:
4811 <item> GTK_POS_RIGHT
4813 <item> GTK_POS_BOTTOM
4816 GTK_POS_TOP is the default.
4818 Next we will look at how to add pages to the notebook. There are three
4819 ways to add pages to the NoteBook. Let's look at the first two together as
4820 they are quite similar.
4823 void gtk_notebook_append_page( GtkNotebook *notebook,
4825 GtkWidget *tab_label );
4827 void gtk_notebook_prepend_page( GtkNotebook *notebook,
4829 GtkWidget *tab_label );
4832 These functions add pages to the notebook by inserting them from the
4833 back of the notebook (append), or the front of the notebook (prepend).
4834 <tt/child/ is the widget that is placed within the notebook page, and
4835 <tt/tab_label/ is the label for the page being added.
4837 The final function for adding a page to the notebook contains all of
4838 the properties of the previous two, but it allows you to specify what position
4839 you want the page to be in the notebook.
4842 void gtk_notebook_insert_page( GtkNotebook *notebook,
4844 GtkWidget *tab_label,
4848 The parameters are the same as _append_ and _prepend_ except it
4849 contains an extra parameter, <tt/position/. This parameter is used to
4850 specify what place this page will be inserted into.
4852 Now that we know how to add a page, lets see how we can remove a page
4856 void gtk_notebook_remove_page( GtkNotebook *notebook,
4860 This function takes the page specified by page_num and removes it from
4861 the widget pointed to by <tt/notebook/.
4863 To find out what the current page is in a notebook use the function:
4866 gint gtk_notebook_current_page( GtkNotebook *notebook );
4869 These next two functions are simple calls to move the notebook page
4870 forward or backward. Simply provide the respective function call with the
4871 notebook widget you wish to operate on. Note: when the NoteBook is currently
4872 on the last page, and gtk_notebook_next_page is called, the notebook will
4873 wrap back to the first page. Likewise, if the NoteBook is on the first page,
4874 and gtk_notebook_prev_page is called, the notebook will wrap to the last page.
4877 void gtk_notebook_next_page( GtkNoteBook *notebook );
4879 void gtk_notebook_prev_page( GtkNoteBook *notebook );
4882 This next function sets the 'active' page. If you wish the
4883 notebook to be opened to page 5 for example, you would use this function.
4884 Without using this function, the notebook defaults to the first page.
4887 void gtk_notebook_set_page( GtkNotebook *notebook,
4891 The next two functions add or remove the notebook page tabs and the
4892 notebook border respectively.
4895 void gtk_notebook_set_show_tabs( GtkNotebook *notebook,
4898 void gtk_notebook_set_show_border( GtkNotebook *notebook,
4902 show_tabs and show_border can be either TRUE or FALSE.
4904 Now lets look at an example, it is expanded from the testgtk.c code
4905 that comes with the GTK distribution, and it shows all 13 functions. This
4906 small program creates a window with a notebook and six buttons. The notebook
4907 contains 11 pages, added in three different ways, appended, inserted, and
4908 prepended. The buttons allow you rotate the tab positions, add/remove the tabs
4909 and border, remove a page, change pages in both a forward and backward manner,
4910 and exit the program.
4913 /* example-start notebook notebook.c */
4915 #include <gtk/gtk.h>
4917 /* This function rotates the position of the tabs */
4918 void rotate_book (GtkButton *button, GtkNotebook *notebook)
4920 gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos +1) %4);
4923 /* Add/Remove the page tabs and the borders */
4924 void tabsborder_book (GtkButton *button, GtkNotebook *notebook)
4928 if (notebook->show_tabs == 0)
4930 if (notebook->show_border == 0)
4933 gtk_notebook_set_show_tabs (notebook, tval);
4934 gtk_notebook_set_show_border (notebook, bval);
4937 /* Remove a page from the notebook */
4938 void remove_book (GtkButton *button, GtkNotebook *notebook)
4942 page = gtk_notebook_current_page(notebook);
4943 gtk_notebook_remove_page (notebook, page);
4944 /* Need to refresh the widget --
4945 This forces the widget to redraw itself. */
4946 gtk_widget_draw(GTK_WIDGET(notebook), NULL);
4949 void delete (GtkWidget *widget, GtkWidget *event, gpointer data)
4954 int main (int argc, char *argv[])
4959 GtkWidget *notebook;
4962 GtkWidget *checkbutton;
4967 gtk_init (&argc, &argv);
4969 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4971 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
4972 GTK_SIGNAL_FUNC (delete), NULL);
4974 gtk_container_border_width (GTK_CONTAINER (window), 10);
4976 table = gtk_table_new(2,6,TRUE);
4977 gtk_container_add (GTK_CONTAINER (window), table);
4979 /* Create a new notebook, place the position of the tabs */
4980 notebook = gtk_notebook_new ();
4981 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
4982 gtk_table_attach_defaults(GTK_TABLE(table), notebook, 0,6,0,1);
4983 gtk_widget_show(notebook);
4985 /* lets append a bunch of pages to the notebook */
4986 for (i=0; i < 5; i++) {
4987 sprintf(bufferf, "Append Frame %d", i+1);
4988 sprintf(bufferl, "Page %d", i+1);
4990 frame = gtk_frame_new (bufferf);
4991 gtk_container_border_width (GTK_CONTAINER (frame), 10);
4992 gtk_widget_set_usize (frame, 100, 75);
4993 gtk_widget_show (frame);
4995 label = gtk_label_new (bufferf);
4996 gtk_container_add (GTK_CONTAINER (frame), label);
4997 gtk_widget_show (label);
4999 label = gtk_label_new (bufferl);
5000 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
5004 /* now lets add a page to a specific spot */
5005 checkbutton = gtk_check_button_new_with_label ("Check me please!");
5006 gtk_widget_set_usize(checkbutton, 100, 75);
5007 gtk_widget_show (checkbutton);
5009 label = gtk_label_new ("Add spot");
5010 gtk_container_add (GTK_CONTAINER (checkbutton), label);
5011 gtk_widget_show (label);
5012 label = gtk_label_new ("Add page");
5013 gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, label, 2);
5015 /* Now finally lets prepend pages to the notebook */
5016 for (i=0; i < 5; i++) {
5017 sprintf(bufferf, "Prepend Frame %d", i+1);
5018 sprintf(bufferl, "PPage %d", i+1);
5020 frame = gtk_frame_new (bufferf);
5021 gtk_container_border_width (GTK_CONTAINER (frame), 10);
5022 gtk_widget_set_usize (frame, 100, 75);
5023 gtk_widget_show (frame);
5025 label = gtk_label_new (bufferf);
5026 gtk_container_add (GTK_CONTAINER (frame), label);
5027 gtk_widget_show (label);
5029 label = gtk_label_new (bufferl);
5030 gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook), frame, label);
5033 /* Set what page to start at (page 4) */
5034 gtk_notebook_set_page (GTK_NOTEBOOK(notebook), 3);
5037 /* create a bunch of buttons */
5038 button = gtk_button_new_with_label ("close");
5039 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
5040 GTK_SIGNAL_FUNC (delete), NULL);
5041 gtk_table_attach_defaults(GTK_TABLE(table), button, 0,1,1,2);
5042 gtk_widget_show(button);
5044 button = gtk_button_new_with_label ("next page");
5045 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
5046 (GtkSignalFunc) gtk_notebook_next_page,
5047 GTK_OBJECT (notebook));
5048 gtk_table_attach_defaults(GTK_TABLE(table), button, 1,2,1,2);
5049 gtk_widget_show(button);
5051 button = gtk_button_new_with_label ("prev page");
5052 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
5053 (GtkSignalFunc) gtk_notebook_prev_page,
5054 GTK_OBJECT (notebook));
5055 gtk_table_attach_defaults(GTK_TABLE(table), button, 2,3,1,2);
5056 gtk_widget_show(button);
5058 button = gtk_button_new_with_label ("tab position");
5059 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
5060 (GtkSignalFunc) rotate_book, GTK_OBJECT(notebook));
5061 gtk_table_attach_defaults(GTK_TABLE(table), button, 3,4,1,2);
5062 gtk_widget_show(button);
5064 button = gtk_button_new_with_label ("tabs/border on/off");
5065 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
5066 (GtkSignalFunc) tabsborder_book,
5067 GTK_OBJECT (notebook));
5068 gtk_table_attach_defaults(GTK_TABLE(table), button, 4,5,1,2);
5069 gtk_widget_show(button);
5071 button = gtk_button_new_with_label ("remove page");
5072 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
5073 (GtkSignalFunc) remove_book,
5074 GTK_OBJECT(notebook));
5075 gtk_table_attach_defaults(GTK_TABLE(table), button, 5,6,1,2);
5076 gtk_widget_show(button);
5078 gtk_widget_show(table);
5079 gtk_widget_show(window);
5088 Hopefully this helps you on your way with creating notebooks for your
5091 <!-- ----------------------------------------------------------------- -->
5092 <sect1>Scrolled Windows
5094 Scrolled windows are used to create a scrollable area inside a real window.
5095 You may insert any type of widget into a scrolled window, and it will
5096 be accessible regardless of the size by using the scrollbars.
5098 The following function is used to create a new scrolled window.
5101 GtkWidget *gtk_scrolled_window_new( GtkAdjustment *hadjustment,
5102 GtkAdjustment *vadjustment );
5105 Where the first argument is the adjustment for the horizontal
5106 direction, and the second, the adjustment for the vertical direction.
5107 These are almost always set to NULL.
5110 void gtk_scrolled_window_set_policy( GtkScrolledWindow *scrolled_window,
5111 GtkPolicyType hscrollbar_policy,
5112 GtkPolicyType vscrollbar_policy );
5115 This sets the policy to be used with respect to the scrollbars.
5116 The first argument is the scrolled window you wish to change. The second
5117 sets the policy for the horizontal scrollbar, and the third the policy for
5118 the vertical scrollbar.
5120 The policy may be one of GTK_POLICY AUTOMATIC, or GTK_POLICY_ALWAYS.
5121 GTK_POLICY_AUTOMATIC will automatically decide whether you need
5122 scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars
5125 Here is a simple example that packs 100 toggle buttons into a scrolled window.
5126 I've only commented on the parts that may be new to you.
5129 /* example-start scrolledwin scrolledwin.c */
5131 #include <gtk/gtk.h>
5133 void destroy(GtkWidget *widget, gpointer data)
5138 int main (int argc, char *argv[])
5140 static GtkWidget *window;
5141 GtkWidget *scrolled_window;
5147 gtk_init (&argc, &argv);
5149 /* Create a new dialog window for the scrolled window to be
5150 * packed into. A dialog is just like a normal window except it has a
5151 * vbox and a horizontal separator packed into it. It's just a shortcut
5152 * for creating dialogs */
5153 window = gtk_dialog_new ();
5154 gtk_signal_connect (GTK_OBJECT (window), "destroy",
5155 (GtkSignalFunc) destroy, NULL);
5156 gtk_window_set_title (GTK_WINDOW (window), "dialog");
5157 gtk_container_border_width (GTK_CONTAINER (window), 0);
5158 gtk_widget_set_usize(window, 300, 300);
5160 /* create a new scrolled window. */
5161 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
5163 gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10);
5165 /* the policy is one of GTK_POLICY AUTOMATIC, or GTK_POLICY_ALWAYS.
5166 * GTK_POLICY_AUTOMATIC will automatically decide whether you need
5167 * scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars
5168 * there. The first one is the horizontal scrollbar, the second,
5170 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
5171 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
5172 /* The dialog window is created with a vbox packed into it. */
5173 gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)->vbox), scrolled_window,
5175 gtk_widget_show (scrolled_window);
5177 /* create a table of 10 by 10 squares. */
5178 table = gtk_table_new (10, 10, FALSE);
5180 /* set the spacing to 10 on x and 10 on y */
5181 gtk_table_set_row_spacings (GTK_TABLE (table), 10);
5182 gtk_table_set_col_spacings (GTK_TABLE (table), 10);
5184 /* pack the table into the scrolled window */
5185 gtk_container_add (GTK_CONTAINER (scrolled_window), table);
5186 gtk_widget_show (table);
5188 /* this simply creates a grid of toggle buttons on the table
5189 * to demonstrate the scrolled window. */
5190 for (i = 0; i < 10; i++)
5191 for (j = 0; j < 10; j++) {
5192 sprintf (buffer, "button (%d,%d)\n", i, j);
5193 button = gtk_toggle_button_new_with_label (buffer);
5194 gtk_table_attach_defaults (GTK_TABLE (table), button,
5196 gtk_widget_show (button);
5199 /* Add a "close" button to the bottom of the dialog */
5200 button = gtk_button_new_with_label ("close");
5201 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
5202 (GtkSignalFunc) gtk_widget_destroy,
5203 GTK_OBJECT (window));
5205 /* this makes it so the button is the default. */
5207 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
5208 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0);
5210 /* This grabs this button to be the default button. Simply hitting
5211 * the "Enter" key will cause this button to activate. */
5212 gtk_widget_grab_default (button);
5213 gtk_widget_show (button);
5215 gtk_widget_show (window);
5224 Try playing with resizing the window. You'll notice how the scrollbars
5225 react. You may also wish to use the gtk_widget_set_usize() call to set
5226 the default size of the window or other widgets.
5228 <!-- ----------------------------------------------------------------- -->
5229 <sect1> Paned Window Widgets
5231 The paned window widgets are useful when you want to divide an area
5232 into two parts, with the relative size of the two parts controlled by
5233 the user. A groove is drawn between the two portions with a handle
5234 that the user can drag to change the ratio. The division can either
5235 be horizontal (HPaned) or vertical (VPaned).
5237 To create a new paned window, call one of:
5240 GtkWidget *gtk_hpaned_new (void);
5242 GtkWidget *gtk_vpaned_new (void);
5245 After creating the paned window widget, you need to add child widgets
5246 to its two halves. To do this, use the functions:
5249 void gtk_paned_add1 (GtkPaned *paned, GtkWidget *child);
5251 void gtk_paned_add2 (GtkPaned *paned, GtkWidget *child);
5254 <tt/gtk_paned_add1()/ adds the child widget to the left or top half of
5255 the paned window. <tt/gtk_paned_add2()/ adds the child widget to the
5256 right or bottom half of the paned window.
5258 As an example, we will create part of the user interface of an
5259 imaginary email program. A window is divided into two portions
5260 vertically, with the top portion being a list of email messages and
5261 the bottom portion the text of the email message. Most of the program
5262 is pretty straightforward. A couple of points to note: text can't
5263 be added to a Text widget until it is realized. This could be done by
5264 calling <tt/gtk_widget_realize()/, but as a demonstration of an alternate
5265 technique, we connect a handler to the "realize" signal to add the
5266 text. Also, we need to add the <tt/GTK_SHRINK/ option to some of the
5267 items in the table containing the text window and its scrollbars, so
5268 that when the bottom portion is made smaller, the correct portions
5269 shrink instead of being pushed off the bottom of the window.
5272 /* example-start paned paned.c */
5274 #include <gtk/gtk.h>
5276 /* Create the list of "messages" */
5281 GtkWidget *scrolled_window;
5283 GtkWidget *list_item;
5288 /* Create a new scrolled window, with scrollbars only if needed */
5289 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
5290 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
5291 GTK_POLICY_AUTOMATIC,
5292 GTK_POLICY_AUTOMATIC);
5294 /* Create a new list and put it in the scrolled window */
5295 list = gtk_list_new ();
5296 gtk_container_add (GTK_CONTAINER(scrolled_window), list);
5297 gtk_widget_show (list);
5299 /* Add some messages to the window */
5300 for (i=0; i<10; i++) {
5302 sprintf(buffer,"Message #%d",i);
5303 list_item = gtk_list_item_new_with_label (buffer);
5304 gtk_container_add (GTK_CONTAINER(list), list_item);
5305 gtk_widget_show (list_item);
5309 return scrolled_window;
5312 /* Add some text to our text widget - this is a callback that is invoked
5313 when our window is realized. We could also force our window to be
5314 realized with gtk_widget_realize, but it would have to be part of
5315 a hierarchy first */
5318 realize_text (GtkWidget *text, gpointer data)
5320 gtk_text_freeze (GTK_TEXT (text));
5321 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
5322 "From: pathfinder@nasa.gov\n"
5323 "To: mom@nasa.gov\n"
5324 "Subject: Made it!\n"
5326 "We just got in this morning. The weather has been\n"
5327 "great - clear but cold, and there are lots of fun sights.\n"
5328 "Sojourner says hi. See you soon.\n"
5331 gtk_text_thaw (GTK_TEXT (text));
5334 /* Create a scrolled text area that displays a "message" */
5340 GtkWidget *hscrollbar;
5341 GtkWidget *vscrollbar;
5343 /* Create a table to hold the text widget and scrollbars */
5344 table = gtk_table_new (2, 2, FALSE);
5346 /* Put a text widget in the upper left hand corner. Note the use of
5347 * GTK_SHRINK in the y direction */
5348 text = gtk_text_new (NULL, NULL);
5349 gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
5350 GTK_FILL | GTK_EXPAND,
5351 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
5352 gtk_widget_show (text);
5354 /* Put a HScrollbar in the lower left hand corner */
5355 hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
5356 gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
5357 GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
5358 gtk_widget_show (hscrollbar);
5360 /* And a VScrollbar in the upper right */
5361 vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
5362 gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
5363 GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
5364 gtk_widget_show (vscrollbar);
5366 /* Add a handler to put a message in the text widget when it is realized */
5367 gtk_signal_connect (GTK_OBJECT (text), "realize",
5368 GTK_SIGNAL_FUNC (realize_text), NULL);
5374 main (int argc, char *argv[])
5381 gtk_init (&argc, &argv);
5383 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5384 gtk_window_set_title (GTK_WINDOW (window), "Paned Windows");
5385 gtk_signal_connect (GTK_OBJECT (window), "destroy",
5386 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
5387 gtk_container_border_width (GTK_CONTAINER (window), 10);
5389 /* create a vpaned widget and add it to our toplevel window */
5391 vpaned = gtk_vpaned_new ();
5392 gtk_container_add (GTK_CONTAINER(window), vpaned);
5393 gtk_widget_show (vpaned);
5395 /* Now create the contents of the two halves of the window */
5397 list = create_list ();
5398 gtk_paned_add1 (GTK_PANED(vpaned), list);
5399 gtk_widget_show (list);
5401 text = create_text ();
5402 gtk_paned_add2 (GTK_PANED(vpaned), text);
5403 gtk_widget_show (text);
5404 gtk_widget_show (window);
5411 <!-- ----------------------------------------------------------------- -->
5414 Toolbars are usually used to group some number of widgets in order to simplify
5415 customization of their look and layout. Typically a toolbar consists of buttons
5416 with icons, labels and tooltips, but any other widget can also
5417 be put inside a toolbar. Finally, items can be arranged horizontally
5418 or vertically and buttons can be displayed with icons, labels or both.
5420 Creating a toolbar is (as one may already suspect) done with the following
5424 GtkWidget *gtk_toolbar_new( GtkOrientation orientation,
5425 GtkToolbarStyle style );
5428 where orientation may be one of:
5431 GTK_ORIENTATION_HORIZONTAL
5432 GTK_ORIENTATION_VERTICAL
5443 The style applies to all the buttons created with the `item' functions
5444 (not to buttons inserted into toolbar as separate widgets).
5446 After creating a toolbar one can append,prepend and insert items (that
5447 means simple buttons) into the toolbar. To describe an item we need a
5448 label text, a tooltip text, a private tooltip text, an icon
5449 for the button and a callback function for it. For example, to append
5450 an item you may use the following function:
5453 GtkWidget *gtk_toolbar_append_item( GtkToolbar *toolbar,
5455 const char *tooltip_text,
5456 const char *tooltip_private_text,
5458 GtkSignalFunc callback,
5459 gpointer user_data );
5462 If you want to use gtk_toolbar_insert_item, the only additional parameter
5463 which must be specified is the position in which the item should be inserted.
5465 To simplify adding spaces between toolbar items, you may use the following
5469 void gtk_toolbar_append_space( GtkToolbar *toolbar );
5471 void gtk_toolbar_prepend_space( GtkToolbar *toolbar );
5473 void gtk_toolbar_insert_space( GtkToolbar *toolbar,
5478 While the size of the added space can be set globally for a
5479 whole toolbar with the function:
5482 void gtk_toolbar_set_space_size( GtkToolbar *toolbar,
5486 If it's needed the orientation of a toolbar and its style can be changed
5487 `on the fly' using the following functions:
5490 void gtk_toolbar_set_orientation( GtkToolbar *toolbar,
5491 GtkOrientation orientation );
5493 void gtk_toolbar_set_style( GtkToolbar *toolbar,
5494 GtkToolbarStyle style );
5496 void gtk_toolbar_set_tooltips( GtkToolbar *toolbar,
5500 To show some other things that can be done with a toolbar, let's take the
5501 following program (we'll interrupt the listing with some additional explanations):
5504 #include <gtk/gtk.h>
5508 /* This function is connected to the Close button or
5509 * closing the window from the WM */
5510 void delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
5516 The above beginning seems for sure familiar to you if it's not your first
5517 GTK program. There is one additional thing though, we include a nice XPM
5518 picture to serve as an icon for all of the buttons.
5521 GtkWidget* close_button; // this button will emit signal to close application
5522 GtkWidget* tooltips_button; // to enable/disable tooltips
5523 GtkWidget* text_button,
5525 * both_button; // radio buttons for toolbar style
5526 GtkWidget* entry; // a text entry to show packing any widget into toolbar
5529 In fact not all of the above widgets are needed here, but to make things
5530 clearer I put them all together.
5533 /* that's easy... when one of the buttons is toggled, we just
5534 * check which one is active and set the style of the toolbar
5536 * ATTENTION: our toolbar is passed as data to callback ! */
5537 void radio_event (GtkWidget *widget, gpointer data)
5539 if (GTK_TOGGLE_BUTTON (text_button)->active)
5540 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_TEXT);
5541 else if (GTK_TOGGLE_BUTTON (icon_button)->active)
5542 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_ICONS);
5543 else if (GTK_TOGGLE_BUTTON (both_button)->active)
5544 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_BOTH);
5547 /* even easier, just check given toggle button and enable/disable
5549 void toggle_event (GtkWidget *widget, gpointer data)
5551 gtk_toolbar_set_tooltips (GTK_TOOLBAR ( data ),
5552 GTK_TOGGLE_BUTTON (widget)->active );
5556 The above are just two callback functions that will be called when
5557 one of the buttons on a toolbar is pressed. You should already be
5558 familiar with things like this if you've already used toggle buttons (and
5562 int main (int argc, char *argv[])
5564 /* Here is our main window (a dialog) and a handle for the handlebox */
5566 GtkWidget* handlebox;
5568 /* Ok, we need a toolbar, an icon with a mask (one for all of
5569 the buttons) and an icon widget to put this icon in (but
5570 we'll create a separate widget for each button) */
5571 GtkWidget * toolbar;
5576 /* this is called in all GTK application. */
5577 gtk_init (&argc, &argv);
5579 /* create a new window with a given title, and nice size */
5580 dialog = gtk_dialog_new ();
5581 gtk_window_set_title ( GTK_WINDOW ( dialog ) , "GTKToolbar Tutorial");
5582 gtk_widget_set_usize( GTK_WIDGET ( dialog ) , 600 , 300 );
5583 GTK_WINDOW ( dialog ) ->allow_shrink = TRUE;
5585 /* typically we quit if someone tries to close us */
5586 gtk_signal_connect ( GTK_OBJECT ( dialog ), "delete_event",
5587 GTK_SIGNAL_FUNC ( delete_event ), NULL);
5589 /* we need to realize the window because we use pixmaps for
5590 * items on the toolbar in the context of it */
5591 gtk_widget_realize ( dialog );
5593 /* to make it nice we'll put the toolbar into the handle box,
5594 * so that it can be detached from the main window */
5595 handlebox = gtk_handle_box_new ();
5596 gtk_box_pack_start ( GTK_BOX ( GTK_DIALOG(dialog)->vbox ),
5597 handlebox, FALSE, FALSE, 5 );
5600 The above should be similar to any other GTK application. Just initialization
5601 of GTK, creating the window etc.. There is only one thing that probably
5602 needs some explanation: a handle box. A handle box is just another box
5603 that can be used to pack widgets in to. The difference between it and typical
5604 boxes is that it can be detached from a parent window (or, in fact, the handle
5605 box remains in the parent, but it is reduced to a very small rectangle, while
5606 all of its contents are reparented to a new freely floating window). It is
5607 usually nice to have a detachable toolbar, so these two widgets occur together
5611 /* toolbar will be horizontal, with both icons and text, and
5612 * with 5pxl spaces between items and finally,
5613 * we'll also put it into our handlebox */
5614 toolbar = gtk_toolbar_new ( GTK_ORIENTATION_HORIZONTAL,
5616 gtk_container_border_width ( GTK_CONTAINER ( toolbar ) , 5 );
5617 gtk_toolbar_set_space_size ( GTK_TOOLBAR ( toolbar ), 5 );
5618 gtk_container_add ( GTK_CONTAINER ( handlebox ) , toolbar );
5620 /* now we create icon with mask: we'll reuse it to create
5621 * icon widgets for toolbar items */
5622 icon = gdk_pixmap_create_from_xpm_d ( dialog->window, &mask,
5623 &dialog->style->white, gtk_xpm );
5626 Well, what we do above is just a straight-forward initialization of the toolbar
5627 widget and creation of a GDK pixmap with its mask. If you want to know
5628 something more about using pixmaps, refer to GDK documentation
5629 or to the <ref id="sec_Pixmaps" name="Pixmaps"> section earlier in this tutorial.
5632 /* our first item is <close> button */
5633 iconw = gtk_pixmap_new ( icon, mask ); // icon widget
5635 gtk_toolbar_append_item ( GTK_TOOLBAR (toolbar), // our toolbar
5636 "Close", // button label
5637 "Closes this app", // tooltip for this button
5638 "Private", // tooltip private string
5639 iconw, // icon widget
5640 GTK_SIGNAL_FUNC (delete_event), // a signal
5642 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) ); // space after item
5645 In the above code you see the simplest case: adding a button to toolbar.
5646 Just before appending a new item, we have to construct a pixmap widget
5647 to serve as an icon for this item; this step will have to be repeated for
5648 each new item. Just after the item we also add a space, so the following
5649 items will not touch each other. As you see gtk_toolbar_append_item returns
5650 a pointer to our newly created button widget, so that we can work with it in
5654 /* now, let's make our radio buttons group... */
5655 iconw = gtk_pixmap_new ( icon, mask );
5657 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
5658 GTK_TOOLBAR_CHILD_RADIOBUTTON, // a type of element
5659 NULL, // pointer to widget
5661 "Only icons in toolbar", // tooltip
5662 "Private", // tooltip private string
5664 GTK_SIGNAL_FUNC (radio_event), // signal
5665 toolbar); // data for signal
5666 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
5669 Here we begin creating a radio buttons group. To do this we use gtk_toolbar_append_element.
5670 In fact, using this function one can also add simple items or even spaces
5671 (type = GTK_TOOLBAR_CHILD_SPACE or GTK_TOOLBAR_CHILD_BUTTON). In the above
5672 case we start creating a radio group. In creating other radio buttons for
5673 this group a pointer to the previous button in the group is required,
5674 so that a list of buttons can be easily constructed (see the section on
5675 <ref id="sec_Radio_Buttons" name="Radio Buttons"> earlier in this tutorial).
5678 /* following radio buttons refer to previous ones */
5679 iconw = gtk_pixmap_new ( icon, mask );
5681 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
5682 GTK_TOOLBAR_CHILD_RADIOBUTTON,
5685 "Only texts in toolbar",
5688 GTK_SIGNAL_FUNC (radio_event),
5690 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
5692 iconw = gtk_pixmap_new ( icon, mask );
5694 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
5695 GTK_TOOLBAR_CHILD_RADIOBUTTON,
5698 "Icons and text in toolbar",
5701 GTK_SIGNAL_FUNC (radio_event),
5703 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
5704 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(both_button),TRUE);
5707 In the end we have set the state of one of the buttons manually (otherwise
5708 they all stay in active state, preventing us from switching between them).
5711 /* here we have just a simple toggle button */
5712 iconw = gtk_pixmap_new ( icon, mask );
5714 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
5715 GTK_TOOLBAR_CHILD_TOGGLEBUTTON,
5718 "Toolbar with or without tips",
5721 GTK_SIGNAL_FUNC (toggle_event),
5723 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
5724 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(tooltips_button),TRUE);
5727 A toggle button can be created in the obvious way (if one knows how to create
5728 radio buttons already).
5731 /* to pack a widget into toolbar, we only have to
5732 * create it and append it with an appropriate tooltip */
5733 entry = gtk_entry_new ();
5734 gtk_toolbar_append_widget( GTK_TOOLBAR (toolbar),
5736 "This is just an entry",
5739 /* well, it isn't created within thetoolbar, so we must still show it */
5740 gtk_widget_show ( entry );
5743 As you see, adding any kind of widget to a toolbar is simple. The
5744 one thing you have to remember is that this widget must be shown manually
5745 (contrary to other items which will be shown together with the toolbar).
5748 /* that's it ! let's show everything. */
5749 gtk_widget_show ( toolbar );
5750 gtk_widget_show (handlebox);
5751 gtk_widget_show ( dialog );
5753 /* rest in gtk_main and wait for the fun to begin! */
5760 So, here we are at the end of toolbar tutorial. Of course, to appreciate
5761 it in full you need also this nice XPM icon, so here it is:
5765 static char * gtk_xpm[] = {
5772 "................+...............",
5773 "..............+++++.............",
5774 "............+++++@@++...........",
5775 "..........+++++@@@@@@++.........",
5776 "........++++@@@@@@@@@@++........",
5777 "......++++@@++++++++@@@++.......",
5778 ".....+++@@@+++++++++++@@@++.....",
5779 "...+++@@@@+++@@@@@@++++@@@@+....",
5780 "..+++@@@@+++@@@@@@@@+++@@@@@++..",
5781 ".++@@@@@@+++@@@@@@@@@@@@@@@@@@++",
5782 ".+#+@@@@@@++@@@@+++@@@@@@@@@@@@+",
5783 ".+##++@@@@+++@@@+++++@@@@@@@@$@.",
5784 ".+###++@@@@+++@@@+++@@@@@++$$$@.",
5785 ".+####+++@@@+++++++@@@@@+@$$$$@.",
5786 ".+#####+++@@@@+++@@@@++@$$$$$$+.",
5787 ".+######++++@@@@@@@++@$$$$$$$$+.",
5788 ".+#######+##+@@@@+++$$$$$$@@$$+.",
5789 ".+###+++##+##+@@++@$$$$$$++$$$+.",
5790 ".+###++++##+##+@@$$$$$$$@+@$$@+.",
5791 ".+###++++++#+++@$$@+@$$@++$$$@+.",
5792 ".+####+++++++#++$$@+@$$++$$$$+..",
5793 ".++####++++++#++$$@+@$++@$$$$+..",
5794 ".+#####+++++##++$$++@+++$$$$$+..",
5795 ".++####+++##+#++$$+++++@$$$$$+..",
5796 ".++####+++####++$$++++++@$$$@+..",
5797 ".+#####++#####++$$+++@++++@$@+..",
5798 ".+#####++#####++$$++@$$@+++$@@..",
5799 ".++####++#####++$$++$$$$$+@$@++.",
5800 ".++####++#####++$$++$$$$$$$$+++.",
5801 ".+++####+#####++$$++$$$$$$$@+++.",
5802 "..+++#########+@$$+@$$$$$$+++...",
5803 "...+++########+@$$$$$$$$@+++....",
5804 ".....+++######+@$$$$$$$+++......",
5805 "......+++#####+@$$$$$@++........",
5806 ".......+++####+@$$$$+++.........",
5807 ".........++###+$$$@++...........",
5808 "..........++##+$@+++............",
5809 "...........+++++++..............",
5810 ".............++++..............."};
5813 <!-- ----------------------------------------------------------------- -->
5814 <sect1> Aspect Frames
5816 The aspect frame widget is like a frame widget, except that it also
5817 enforces the aspect ratio (that is, the ratio of the width to the
5818 height) of the child widget to have a certain value, adding extra
5819 space if necessary. This is useful, for instance, if you want to
5820 preview a larger image. The size of the preview should vary when
5821 the user resizes the window, but the aspect ratio needs to always match
5824 To create a new aspect frame use:
5827 GtkWidget *gtk_aspect_frame_new( const gchar *label,
5834 <tt/xalign/ and <tt/yalign/ specify alignment as with Alignment
5835 widgets. If <tt/obey_child/ is true, the aspect ratio of a child
5836 widget will match the aspect ratio of the ideal size it requests.
5837 Otherwise, it is given by <tt/ratio/.
5839 To change the options of an existing aspect frame, you can use:
5842 void gtk_aspect_frame_set( GtkAspectFrame *aspect_frame,
5849 As an example, the following program uses an AspectFrame to
5850 present a drawing area whose aspect ratio will always be 2:1, no
5851 matter how the user resizes the top-level window.
5854 /* example-start aspectframe aspectframe.c */
5856 #include <gtk/gtk.h>
5859 main (int argc, char *argv[])
5862 GtkWidget *aspect_frame;
5863 GtkWidget *drawing_area;
5864 gtk_init (&argc, &argv);
5866 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5867 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
5868 gtk_signal_connect (GTK_OBJECT (window), "destroy",
5869 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
5870 gtk_container_border_width (GTK_CONTAINER (window), 10);
5872 /* Create an aspect_frame and add it to our toplevel window */
5874 aspect_frame = gtk_aspect_frame_new ("2x1", /* label */
5877 2, /* xsize/ysize = 2 */
5878 FALSE /* ignore child's aspect */);
5880 gtk_container_add (GTK_CONTAINER(window), aspect_frame);
5881 gtk_widget_show (aspect_frame);
5883 /* Now add a child widget to the aspect frame */
5885 drawing_area = gtk_drawing_area_new ();
5887 /* Ask for a 200x200 window, but the AspectFrame will give us a 200x100
5888 * window since we are forcing a 2x1 aspect ratio */
5889 gtk_widget_set_usize (drawing_area, 200, 200);
5890 gtk_container_add (GTK_CONTAINER(aspect_frame), drawing_area);
5891 gtk_widget_show (drawing_area);
5893 gtk_widget_show (window);
5900 <!-- ***************************************************************** -->
5902 <!-- ***************************************************************** -->
5904 <!-- ----------------------------------------------------------------- -->
5906 The GtkCList widget has replaced the GtkList widget (which is still
5909 The GtkCList widget is a multi-column list widget that is capable of
5910 handling literally thousands of rows of information. Each column can
5911 optionally have a title, which itself is optionally active, allowing
5912 us to bind a function to its selection.
5914 <!-- ----------------------------------------------------------------- -->
5915 <sect1>Creating a GtkCList widget
5917 Creating a GtkCList is quite straightforward, once you have learned about
5918 widgets in general. It provides the almost standard two ways, that is the
5919 hard way, and the easy way. But before we create it, there is one thing we
5920 should figure out beforehand: how many columns should it have?
5922 Not all columns have to be visible and can be used to store data that is
5923 related to a certain cell in the list.
5926 GtkWidget *gtk_clist_new ( gint columns );
5928 GtkWidget *gtk_clist_new_with_titles( gint columns,
5932 The first form is very straight forward, the second might require some
5933 explanation. Each column can have a title associated with it, and this
5934 title can be a label or a button that reacts when we click on it. If we
5935 use the second form, we must provide pointers to the title texts, and the
5936 number of pointers should equal the number of columns specified. Of course
5937 we can always use the first form, and manually add titles later.
5939 <!-- ----------------------------------------------------------------- -->
5940 <sect1>Modes of operation
5942 There are several attributes that can be used to alter the behaviour of
5943 a GtkCList. First there is
5946 void gtk_clist_set_selection_mode( GtkCList *clist,
5947 GtkSelectionMode mode );
5950 which, as the name implies, sets the selection mode of the GtkCList. The first
5951 argument is the GtkCList widget, and the second specifies the cell selection
5952 mode (they are defined in gtkenums.h). At the time of this writing, the following
5953 modes are available to us:
5956 <item> GTK_SELECTION_SINGLE - The selection is either NULL or contains a GList
5957 pointer for a single selected item.
5959 <item> GTK_SELECTION_BROWSE - The selection is NULL if the list contains no
5960 widgets or insensitive ones only, otherwise it contains a GList pointer for
5961 one GList structure, and therefore exactly one list item.
5963 <item> GTK_SELECTION_MULTIPLE - The selection is NULL if no list items are
5964 selected or a GList pointer for the first selected item. That in turn points
5965 to a GList structure for the second selected item and so on. This is currently
5966 the <bf>default</bf> for the GtkCList widget.
5968 <item> GTK_SELECTION_EXTENDED - The selection is always NULL.
5971 Others might be added in later revisions of GTK.
5976 void gtk_clist_set_policy (GtkCList * clist,
5977 GtkPolicyType vscrollbar_policy,
5978 GtkPolicyType hscrollbar_policy);
5981 which defines what happens to the scrollbars. The following values are possible
5982 for both the vertical and the horizontal scrollbar:
5985 <item> GTK_POLICY_ALWAYS - The scrollbar will always be there.
5987 <item> GTK_POLICY_AUTOMATIC - The scrollbar will be there only when the number
5988 of items in the GtkCList exceeds the number that can be shown in the widget.
5991 We can also define what the border of the GtkCList widget should look like. It is
5995 void gtk_clist_set_border( GtkCList *clist,
5996 GtkShadowType border );
5999 And the possible values for the second argument are
6002 <item> GTK_SHADOW_NONE
6004 <item> GTK_SHADOW_IN
6006 <item> GTK_SHADOW_OUT
6008 <item> GTK_SHADOW_ETCHED_IN
6010 <item> GTK_SHADOW_ETCHED_OUT
6013 <!-- ----------------------------------------------------------------- -->
6014 <sect1>Working with titles
6016 When you create a GtkCList widget, you will also get a set of title buttons
6017 automatically. They live in the top of the CList window, and can act either
6018 as normal buttons that respond to being pressed, or they can be passive,
6019 in which case they are nothing more than a title. There are four different
6020 calls that aid us in setting the status of the title buttons.
6023 void gtk_clist_column_title_active( GtkCList *clist,
6026 void gtk_clist_column_title_passive( GtkCList *clist,
6029 void gtk_clist_column_titles_active( GtkCList *clist );
6031 void gtk_clist_column_titles_passive( GtkCList *clist );
6034 An active title is one which acts as a normal button, a passive one is just
6035 a label. The first two calls above will activate/deactivate the title button
6036 above the specific column, while the last two calls activate/deactivate all
6037 title buttons in the supplied clist widget.
6039 But of course there are those cases when we don't want them at all, and so
6040 they can be hidden and shown at will using the following two calls.
6043 void gtk_clist_column_titles_show( GtkCList *clist );
6045 void gtk_clist_column_titles_hide( GtkCList *clist );
6048 For titles to be really useful we need a mechanism to set and change them,
6049 and this is done using
6052 void gtk_clist_set_column_title( GtkCList *clist,
6057 Note that only the title of one column can be set at a time, so if all the
6058 titles are known from the beginning, then I really suggest using
6059 gtk_clist_new_with_titles (as described above) to set them. Saves you
6060 coding time, and makes your program smaller. There are some cases where
6061 getting the job done the manual way is better, and that's when not all
6062 titles will be text. GtkCList provides us with title buttons that can in fact
6063 incorporate whole widgets, for example a pixmap. It's all done through
6066 void gtk_clist_set_column_widget( GtkCList *clist,
6068 GtkWidget *widget );
6071 which should require no special explanation.
6073 <!-- ----------------------------------------------------------------- -->
6074 <sect1>Manipulating the list itself
6076 It is possible to change the justification for a column, and it is done through
6079 void gtk_clist_set_column_justification( GtkCList *clist,
6081 GtkJustification justification );
6084 The GtkJustification type can take the following values:
6087 <item>GTK_JUSTIFY_LEFT - The text in the column will begin from the left edge.
6089 <item>GTK_JUSTIFY_RIGHT - The text in the column will begin from the right edge.
6091 <item>GTK_JUSTIFY_CENTER - The text is placed in the center of the column.
6093 <item>GTK_JUSTIFY_FILL - The text will use up all available space in the
6094 column. It is normally done by inserting extra blank spaces between words
6095 (or between individual letters if it's a single word). Much in the same way as
6096 any ordinary WYSIWYG text editor.
6099 The next function is a very important one, and should be standard in the setup
6100 of all GtkCList widgets. When the list is created, the width of the various
6101 columns are chosen to match their titles, and since this is seldom the right
6102 width we have to set it using
6105 void gtk_clist_set_column_width( GtkCList *clist,
6110 Note that the width is given in pixels and not letters. The same goes for the
6111 height of the cells in the columns, but as the default value is the height of
6112 the current font this isn't as critical to the application. Still, it is done through
6115 void gtk_clist_set_row_height( GtkCList *clist,
6119 Again, note that the height is given in pixels.
6121 We can also move the list around without user interaction, however, it does
6122 require that we know what we are looking for. Or in other words, we need the row
6123 and column of the item we want to scroll to.
6126 void gtk_clist_moveto( GtkCList *clist,
6133 The gfloat row_align is pretty important to understand. It's a value between 0.0 and
6134 1.0, where 0.0 means that we should scroll the list so the row appears at the top,
6135 while if the value of row_align is 1.0, the row will appear at the bottom instead. All
6136 other values between 0.0 and 1.0 are also valid and will place the row between the top
6137 and the bottom. The last argument, gfloat col_align works in the same way, though 0.0
6138 marks left and 1.0 marks right instead.
6140 Depending on the application's needs, we don't have to scroll to an item that is
6141 already visible to us. So how do we know if it is visible? As usual, there is a function
6142 to find that out as well.
6145 GtkVisibility gtk_clist_row_is_visible( GtkCList *clist,
6149 The return value is is one of the following:
6152 <item>GTK_VISIBILITY_NONE
6154 <item>GTK_VISIBILITY_PARTIAL
6156 <item>GTK_VISIBILITY_FULL
6159 Note that it will only tell us if a row is visible. Currently there is no way to
6160 determine this for a column. We can get partial information though, because if
6161 the return is GTK_VISIBILITY_PARTIAL, then some of it is hidden, but we don't know if
6162 it is the row that is being cut by the lower edge of the listbox, or if the row has
6163 columns that are outside.
6165 We can also change both the foreground and background colors of a particular
6166 row. This is useful for marking the row selected by the user, and the two functions
6167 that is used to do it are
6170 void gtk_clist_set_foreground( GtkCList *clist,
6174 void gtk_clist_set_background( GtkCList *clist,
6179 Please note that the colors must have been previously allocated.
6181 <!-- ----------------------------------------------------------------- -->
6182 <sect1>Adding rows to the list
6184 We can add rows in two ways. They can be appended at the end to the list using
6187 gint gtk_clist_append( GtkCList *clist,
6191 or we can insert a row at a given place using
6194 void gtk_clist_insert( GtkCList *clist,
6199 In both calls we have to provide a collection of pointers that are the texts
6200 we want to put in the columns. The number of pointers should equal the number
6201 of columns in the list. If the text[] argument is NULL, then there will be no
6202 text in the columns of the row. This is useful, for example, if we want to
6203 add pixmaps instead (something that has to be done manually).
6205 Also, please note that the numbering of both rows and columns start at 0.
6207 To remove an individual row we use
6210 void gtk_clist_remove( GtkCList *clist,
6214 There is also a call that removes all rows in the list. This is a lot faster
6215 than calling gtk_clist_remove once for each row, which is the only alternative.
6218 void gtk_clist_clear( GtkCList *clist );
6221 There are also two convenience functions that should be used when a lot of
6222 changes have to be made to the list. This is to prevent the list flickering while
6223 being repeatedly updated, which may be highly annoying to the user. So instead it
6224 is a good idea to freeze the list, do the updates to it, and finally thaw it which
6225 causes the list to be updated on the screen.
6228 void gtk_clist_freeze( GtkCList * clist );
6230 void gtk_clist_thaw( GtkCList * clist );
6233 <!-- ----------------------------------------------------------------- -->
6234 <sect1>Setting text and pixmaps in the cells
6236 A cell can contain a pixmap, text or both. To set them the following
6240 void gtk_clist_set_text( GtkCList *clist,
6245 void gtk_clist_set_pixmap( GtkCList *clist,
6251 void gtk_clist_set_pixtext( GtkCList *clist,
6260 It's quite straightforward. All the calls have the GtkCList as the first
6261 argument, followed by the row and column of the cell, followed by the data to be
6262 set. The gint8 spacing argument in gtk_clist_set_pixtext is the number of pixels
6263 between the pixmap and the beginning of the text.
6265 To read back the data, we instead use
6268 gint gtk_clist_get_text( GtkCList *clist,
6273 gint gtk_clist_get_pixmap( GtkCList *clist,
6279 gint gtk_clist_get_pixtext( GtkCList *clist,
6288 It isn't necessary to read it all back in case you aren't interested. Any
6289 of the pointers that are meant for return values (all except the clist) can
6290 be NULL. So if we want to read back only the text from a cell that is of
6291 type pixtext, then we would do the following, assuming that clist, row and
6292 column already exist:
6297 gtk_clist_get_pixtext(clist, row, column, &mytext, NULL, NULL, NULL);
6300 There is one more call that is related to what's inside a cell in the
6304 GtkCellType gtk_clist_get_cell_type( GtkCList *clist,
6309 which returns the type of data in a cell. The return value is one of
6312 <item>GTK_CELL_EMPTY
6316 <item>GTK_CELL_PIXMAP
6318 <item>GTK_CELL_PIXTEXT
6320 <item>GTK_CELL_WIDGET
6323 There is also a function that will let us set the indentation, both
6324 vertical and horizontal, of a cell. The indentation value is of type gint,
6325 given in pixels, and can be both positive and negative.
6328 void gtk_clist_set_shift( GtkCList *clist,
6335 <!-- ----------------------------------------------------------------- -->
6336 <sect1>Storing data pointers
6338 With a GtkCList it is possible to set a data pointer for a row. This
6339 pointer will not be visible for the user, but is merely a convenience for
6340 the programmer to associate a row with a pointer to some additional data.
6342 The functions should be fairly self-explanatory by now
6345 void gtk_clist_set_row_data( GtkCList *clist,
6349 void gtk_clist_set_row_data_full( GtkCList *clist,
6352 GtkDestroyNotify destroy );
6354 gpointer gtk_clist_get_row_data( GtkCList *clist,
6357 gint gtk_clist_find_row_from_data( GtkCList *clist,
6361 <!-- ----------------------------------------------------------------- -->
6362 <sect1>Working with selections
6364 There are also functions available that let us force the (un)selection
6368 void gtk_clist_select_row( GtkCList *clist,
6372 void gtk_clist_unselect_row( GtkCList *clist,
6377 And also a function that will take x and y coordinates (for example, read from
6378 the mousepointer), and map that onto the list, returning the
6379 corresponding row and column.
6382 gint gtk_clist_get_selection_info( GtkCList *clist,
6389 When we detect something of interest, it might be movement of the pointer, a
6390 click somewhere in the list, we can read the pointer coordinates and find out
6391 where in the list the pointer is. Cumbersome? Luckily, there is a more simple way...
6393 <!-- ----------------------------------------------------------------- -->
6394 <sect1>The signals that bring it together
6396 As with all other widgets, there are a few signals that can be used. The
6397 GtkCList widget is derived from the GtkContainer widget, and so has all the
6398 same signals, but also the adds following:
6401 <item>select_row - This signal will send the following information, in
6402 order: GtkCList *clist, gint row, gint column, GtkEventButton *event
6404 <item>unselect_row - When the user unselects a row, this signal is activated. It
6405 sends the same information as select_row
6407 <item>click_column - Send GtkCList *clist, gint column
6410 So if we want to connect a callback to select_row, the callback function would
6411 be declared like this
6414 void select_row_callback(GtkWidget *widget,
6417 GdkEventButton *event,
6421 The callback is connected as usual with
6424 gtk_signal_connect(GTK_OBJECT( clist),
6426 GTK_SIGNAL_FUNC(select_row_callback),
6430 <!-- ----------------------------------------------------------------- -->
6431 <sect1>A GtkCList example
6435 /* example-start clist clist.c */
6437 #include <gtk/gtk.h>
6440 /* These are just the prototypes of the various callbacks */
6441 void button_add_clicked( GtkWidget *button, gpointer data);
6442 void button_clear_clicked( GtkWidget *button, gpointer data);
6443 void button_hide_show_clicked( GtkWidget *button, gpointer data);
6444 void selection_made( GtkWidget *clist, gint row, gint column,
6445 GdkEventButton *event, gpointer data);
6447 gint main (int argc, gchar *argv[])
6450 GtkWidget *vbox, *hbox;
6452 GtkWidget *button_add, *button_clear, *button_hide_show;
6453 gchar *titles[2] = {"Ingredients","Amount"};
6455 gtk_init(&argc, &argv);
6458 window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
6459 gtk_widget_set_usize(GTK_WIDGET(window), 300, 150);
6461 gtk_window_set_title(GTK_WINDOW(window), "GtkCList Example");
6462 gtk_signal_connect(GTK_OBJECT(window),
6464 GTK_SIGNAL_FUNC(gtk_main_quit),
6467 vbox=gtk_vbox_new(FALSE, 5);
6468 gtk_container_border_width(GTK_CONTAINER(vbox), 5);
6469 gtk_container_add(GTK_CONTAINER(window), vbox);
6470 gtk_widget_show(vbox);
6472 /* Create the GtkCList. For this example we use 2 columns */
6473 clist = gtk_clist_new_with_titles( 2, titles);
6475 /* When a selection is made, we want to know about it. The callback
6476 * used is selection_made, and its code can be found further down */
6477 gtk_signal_connect(GTK_OBJECT(clist), "select_row",
6478 GTK_SIGNAL_FUNC(selection_made),
6481 /* It isn't necessary to shadow the border, but it looks nice :) */
6482 gtk_clist_set_border(GTK_CLIST(clist), GTK_SHADOW_OUT);
6484 /* What however is important, is that we set the column widths as
6485 * they will never be right otherwise. Note that the columns are
6486 * numbered from 0 and up (to 1 in this case).
6488 gtk_clist_set_column_width (GTK_CLIST(clist), 0, 150);
6490 /* Scollbars _only when needed_ */
6491 gtk_clist_set_policy(GTK_CLIST(clist), GTK_POLICY_AUTOMATIC,
6492 GTK_POLICY_AUTOMATIC);
6494 /* Add the GtkCList widget to the vertical box and show it. */
6495 gtk_box_pack_start(GTK_BOX(vbox), clist, TRUE, TRUE, 0);
6496 gtk_widget_show(clist);
6498 /* Create the buttons and add them to the window. See the button
6499 * tutorial for more examples and comments on this.
6501 hbox = gtk_hbox_new(FALSE, 0);
6502 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
6503 gtk_widget_show(hbox);
6505 button_add = gtk_button_new_with_label("Add List");
6506 button_clear = gtk_button_new_with_label("Clear List");
6507 button_hide_show = gtk_button_new_with_label("Hide/Show titles");
6509 gtk_box_pack_start(GTK_BOX(hbox), button_add, TRUE, TRUE, 0);
6510 gtk_box_pack_start(GTK_BOX(hbox), button_clear, TRUE, TRUE, 0);
6511 gtk_box_pack_start(GTK_BOX(hbox), button_hide_show, TRUE, TRUE, 0);
6513 /* Connect our callbacks to the three buttons */
6514 gtk_signal_connect_object(GTK_OBJECT(button_add), "clicked",
6515 GTK_SIGNAL_FUNC(button_add_clicked),
6517 gtk_signal_connect_object(GTK_OBJECT(button_clear), "clicked",
6518 GTK_SIGNAL_FUNC(button_clear_clicked),
6520 gtk_signal_connect_object(GTK_OBJECT(button_hide_show), "clicked",
6521 GTK_SIGNAL_FUNC(button_hide_show_clicked),
6524 gtk_widget_show(button_add);
6525 gtk_widget_show(button_clear);
6526 gtk_widget_show(button_hide_show);
6528 /* The interface is completely set up so we show the window and
6529 * enter the gtk_main loop.
6531 gtk_widget_show(window);
6537 /* User clicked the "Add List" button. */
6538 void button_add_clicked( GtkWidget *button, gpointer data)
6542 /* Something silly to add to the list. 4 rows of 2 columns each */
6543 gchar *drink[4][2] = {{"Milk", "3 Oz"},
6548 /* Here we do the actual adding of the text. It's done once for
6551 for( indx=0; indx < 4; indx++)
6552 gtk_clist_append( (GtkCList*) data, drink[indx]);
6557 /* User clicked the "Clear List" button. */
6558 void button_clear_clicked( GtkWidget *button, gpointer data)
6560 /* Clear the list using gtk_clist_clear. This is much faster than
6561 * calling gtk_clist_remove once for each row.
6563 gtk_clist_clear((GtkCList*) data);
6568 /* The user clicked the "Hide/Show titles" button. */
6569 void button_hide_show_clicked( GtkWidget *button, gpointer data)
6571 /* Just a flag to remember the status. 0 = currently visible */
6572 static short int flag = 0;
6576 /* Hide the titles and set the flag to 1 */
6577 gtk_clist_column_titles_hide((GtkCList*) data);
6582 /* Show the titles and reset flag to 0 */
6583 gtk_clist_column_titles_show((GtkCList*) data);
6590 /* If we come here, then the user has selected a row in the list. */
6591 void selection_made( GtkWidget *clist, gint row, gint column,
6592 GdkEventButton *event, gpointer data)
6596 /* Get the text that is stored in the selected row and column
6597 * which was clicked in. We will receive it as a pointer in the
6600 gtk_clist_get_text(GTK_CLIST(clist), row, column, &text);
6602 /* Just prints some information about the selected row */
6603 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);
6610 <!-- ***************************************************************** -->
6612 <!-- ***************************************************************** -->
6614 NOTE: The GtkList widget has been superseded by the GtkCList widget.
6616 The GtkList widget is designed to act as a vertical container for widgets
6617 that should be of the type GtkListItem.
6619 A GtkList widget has its own window to receive events and its own
6620 background color which is usually white. As it is directly derived from a
6621 GtkContainer it can be treated as such by using the GTK_CONTAINER(List)
6622 macro, see the GtkContainer widget for more on this.
6623 One should already be familiar with the usage of a GList and its
6624 related functions g_list_*() to be able to use the GtkList widget to
6627 There is one field inside the structure definition of the GtkList widget
6628 that will be of greater interest to us, this is:
6635 guint selection_mode;
6640 The selection field of a GtkList points to a linked list of all items
6641 that are currently selected, or NULL if the selection is empty.
6642 So to learn about the current selection we read the GTK_LIST()->selection
6643 field, but do not modify it since the internal fields are maintained by
6644 the gtk_list_*() functions.
6646 The selection_mode of the GtkList determines the selection facilities
6647 of a GtkList and therefore the contents of the GTK_LIST()->selection
6648 field. The selection_mode may be one of the following:
6651 <item> GTK_SELECTION_SINGLE - The selection is either NULL
6652 or contains a GList pointer
6653 for a single selected item.
6655 <item> GTK_SELECTION_BROWSE - The selection is NULL if the list
6656 contains no widgets or insensitive
6657 ones only, otherwise it contains
6658 a GList pointer for one GList
6659 structure, and therefore exactly
6662 <item> GTK_SELECTION_MULTIPLE - The selection is NULL if no list
6663 items are selected or a GList pointer
6664 for the first selected item. That
6665 in turn points to a GList structure
6666 for the second selected item and so
6669 <item> GTK_SELECTION_EXTENDED - The selection is always NULL.
6672 The default is GTK_SELECTION_MULTIPLE.
6674 <!-- ----------------------------------------------------------------- -->
6678 void selection_changed( GtkList *list );
6681 This signal will be invoked whenever the selection field
6682 of a GtkList has changed. This happens when a child of
6683 the GtkList got selected or deselected.
6686 void select_child( GtkList *list,
6690 This signal is invoked when a child of the GtkList is about
6691 to get selected. This happens mainly on calls to
6692 gtk_list_select_item(), gtk_list_select_child(), button presses
6693 and sometimes indirectly triggered on some else occasions where
6694 children get added to or removed from the GtkList.
6697 void unselect_child( GtkList *list,
6701 This signal is invoked when a child of the GtkList is about
6702 to get deselected. This happens mainly on calls to
6703 gtk_list_unselect_item(), gtk_list_unselect_child(), button presses
6704 and sometimes indirectly triggered on some else occasions where
6705 children get added to or removed from the GtkList.
6707 <!-- ----------------------------------------------------------------- -->
6711 guint gtk_list_get_type( void );
6714 Returns the `GtkList' type identifier.
6717 GtkWidget *gtk_list_new( void );
6720 Create a new GtkList object. The new widget is returned as a pointer to a
6721 GtkWidget object. NULL is returned on failure.
6724 void gtk_list_insert_items( GtkList *list,
6729 Insert list items into the list, starting at <tt/position/.
6730 <tt/items/ is a doubly linked list where each nodes data
6731 pointer is expected to point to a newly created GtkListItem.
6732 The GList nodes of <tt/items/ are taken over by the list.
6735 void gtk_list_append_items( GtkList *list,
6739 Insert list items just like gtk_list_insert_items() at the end
6740 of the list. The GList nodes of <tt/items/ are taken over by the list.
6743 void gtk_list_prepend_items( GtkList *list,
6747 Insert list items just like gtk_list_insert_items() at the very
6748 beginning of the list. The GList nodes of <tt/items/ are taken over
6752 void gtk_list_remove_items( GtkList *list,
6756 Remove list items from the list. <tt/items/ is a doubly linked
6757 list where each nodes data pointer is expected to point to a
6758 direct child of list. It is the callers responsibility to make a
6759 call to g_list_free(items) afterwards. Also the caller has to
6760 destroy the list items himself.
6763 void gtk_list_clear_items( GtkList *list,
6768 Remove and destroy list items from the list. A widget is affected if
6769 its current position within the list is in the range specified by
6770 <tt/start/ and <tt/end/.
6773 void gtk_list_select_item( GtkList *list,
6777 Invoke the select_child signal for a list item
6778 specified through its current position within the list.
6781 void gtk_list_unselect_item( GtkList *list,
6785 Invoke the unselect_child signal for a list item
6786 specified through its current position within the list.
6789 void gtk_list_select_child( GtkList *list,
6793 Invoke the select_child signal for the specified child.
6796 void gtk_list_unselect_child( GtkList *list,
6800 Invoke the unselect_child signal for the specified child.
6803 gint gtk_list_child_position( GtkList *list,
6807 Return the position of <tt/child/ within the list. "-1" is returned on failure.
6810 void gtk_list_set_selection_mode( GtkList *list,
6811 GtkSelectionMode mode );
6814 Set the selection mode MODE which can be of GTK_SELECTION_SINGLE,
6815 GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE or GTK_SELECTION_EXTENDED.
6818 GtkList *GTK_LIST( gpointer obj );
6821 Cast a generic pointer to `GtkList *'. *Note Standard Macros::, for
6825 GtkListClass *GTK_LIST_CLASS( gpointer class);
6828 Cast a generic pointer to `GtkListClass*'. *Note Standard Macros::,
6832 gint GTK_IS_LIST( gpointer obj);
6835 Determine if a generic pointer refers to a `GtkList' object. *Note
6836 Standard Macros::, for more info.
6838 <!-- ----------------------------------------------------------------- -->
6841 Following is an example program that will print out the changes
6842 of the selection of a GtkList, and lets you "arrest" list items
6843 into a prison by selecting them with the rightmost mouse button.
6846 /* example-start list list.c */
6848 /* include the gtk+ header files
6849 * include stdio.h, we need that for the printf() function
6851 #include <gtk/gtk.h>
6854 /* this is our data identification string to store
6855 * data in list items
6857 const gchar *list_item_data_key="list_item_data";
6860 /* prototypes for signal handler that we are going to connect
6861 * to the GtkList widget
6863 static void sigh_print_selection (GtkWidget *gtklist,
6864 gpointer func_data);
6865 static void sigh_button_event (GtkWidget *gtklist,
6866 GdkEventButton *event,
6870 /* main function to set up the user interface */
6872 gint main (int argc, gchar *argv[])
6874 GtkWidget *separator;
6877 GtkWidget *scrolled_window;
6881 GtkWidget *list_item;
6887 /* initialize gtk+ (and subsequently gdk) */
6889 gtk_init(&argc, &argv);
6892 /* create a window to put all the widgets in
6893 * connect gtk_main_quit() to the "destroy" event of
6894 * the window to handle window manager close-window-events
6896 window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
6897 gtk_window_set_title(GTK_WINDOW(window), "GtkList Example");
6898 gtk_signal_connect(GTK_OBJECT(window),
6900 GTK_SIGNAL_FUNC(gtk_main_quit),
6904 /* inside the window we need a box to arrange the widgets
6906 vbox=gtk_vbox_new(FALSE, 5);
6907 gtk_container_border_width(GTK_CONTAINER(vbox), 5);
6908 gtk_container_add(GTK_CONTAINER(window), vbox);
6909 gtk_widget_show(vbox);
6911 /* this is the scrolled window to put the GtkList widget inside */
6912 scrolled_window=gtk_scrolled_window_new(NULL, NULL);
6913 gtk_widget_set_usize(scrolled_window, 250, 150);
6914 gtk_container_add(GTK_CONTAINER(vbox), scrolled_window);
6915 gtk_widget_show(scrolled_window);
6917 /* create the GtkList widget
6918 * connect the sigh_print_selection() signal handler
6919 * function to the "selection_changed" signal of the GtkList
6920 * to print out the selected items each time the selection
6922 gtklist=gtk_list_new();
6923 gtk_container_add(GTK_CONTAINER(scrolled_window), gtklist);
6924 gtk_widget_show(gtklist);
6925 gtk_signal_connect(GTK_OBJECT(gtklist),
6926 "selection_changed",
6927 GTK_SIGNAL_FUNC(sigh_print_selection),
6930 /* we create a "Prison" to put a list item in ;)
6932 frame=gtk_frame_new("Prison");
6933 gtk_widget_set_usize(frame, 200, 50);
6934 gtk_container_border_width(GTK_CONTAINER(frame), 5);
6935 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
6936 gtk_container_add(GTK_CONTAINER(vbox), frame);
6937 gtk_widget_show(frame);
6939 /* connect the sigh_button_event() signal handler to the GtkList
6940 * which will handle the "arresting" of list items
6942 gtk_signal_connect(GTK_OBJECT(gtklist),
6943 "button_release_event",
6944 GTK_SIGNAL_FUNC(sigh_button_event),
6947 /* create a separator
6949 separator=gtk_hseparator_new();
6950 gtk_container_add(GTK_CONTAINER(vbox), separator);
6951 gtk_widget_show(separator);
6953 /* finally create a button and connect it´s "clicked" signal
6954 * to the destruction of the window
6956 button=gtk_button_new_with_label("Close");
6957 gtk_container_add(GTK_CONTAINER(vbox), button);
6958 gtk_widget_show(button);
6959 gtk_signal_connect_object(GTK_OBJECT(button),
6961 GTK_SIGNAL_FUNC(gtk_widget_destroy),
6962 GTK_OBJECT(window));
6965 /* now we create 5 list items, each having it´s own
6966 * label and add them to the GtkList using gtk_container_add()
6967 * also we query the text string from the label and
6968 * associate it with the list_item_data_key for each list item
6970 for (i=0; i<5; i++) {
6974 sprintf(buffer, "ListItemContainer with Label #%d", i);
6975 label=gtk_label_new(buffer);
6976 list_item=gtk_list_item_new();
6977 gtk_container_add(GTK_CONTAINER(list_item), label);
6978 gtk_widget_show(label);
6979 gtk_container_add(GTK_CONTAINER(gtklist), list_item);
6980 gtk_widget_show(list_item);
6981 gtk_label_get(GTK_LABEL(label), &string);
6982 gtk_object_set_data(GTK_OBJECT(list_item),
6986 /* here, we are creating another 5 labels, this time
6987 * we use gtk_list_item_new_with_label() for the creation
6988 * we can´t query the text string from the label because
6989 * we don´t have the labels pointer and therefore
6990 * we just associate the list_item_data_key of each
6991 * list item with the same text string
6992 * for adding of the list items we put them all into a doubly
6993 * linked list (GList), and then add them by a single call to
6994 * gtk_list_append_items()
6995 * because we use g_list_prepend() to put the items into the
6996 * doubly linked list, their order will be descending (instead
6997 * of ascending when using g_list_append())
7001 sprintf(buffer, "List Item with Label %d", i);
7002 list_item=gtk_list_item_new_with_label(buffer);
7003 dlist=g_list_prepend(dlist, list_item);
7004 gtk_widget_show(list_item);
7005 gtk_object_set_data(GTK_OBJECT(list_item),
7007 "ListItem with integrated Label");
7009 gtk_list_append_items(GTK_LIST(gtklist), dlist);
7011 /* finally we want to see the window, don't we? ;)
7013 gtk_widget_show(window);
7015 /* fire up the main event loop of gtk
7019 /* we get here after gtk_main_quit() has been called which
7020 * happens if the main window gets destroyed
7025 /* this is the signal handler that got connected to button
7026 * press/release events of the GtkList
7029 sigh_button_event (GtkWidget *gtklist,
7030 GdkEventButton *event,
7033 /* we only do something if the third (rightmost mouse button
7036 if (event->type==GDK_BUTTON_RELEASE &&
7038 GList *dlist, *free_list;
7039 GtkWidget *new_prisoner;
7041 /* fetch the currently selected list item which
7042 * will be our next prisoner ;)
7044 dlist=GTK_LIST(gtklist)->selection;
7046 new_prisoner=GTK_WIDGET(dlist->data);
7050 /* look for already imprisoned list items, we
7051 * will put them back into the list
7052 * remember to free the doubly linked list that
7053 * gtk_container_children() returns
7055 dlist=gtk_container_children(GTK_CONTAINER(frame));
7058 GtkWidget *list_item;
7060 list_item=dlist->data;
7062 gtk_widget_reparent(list_item, gtklist);
7066 g_list_free(free_list);
7068 /* if we have a new prisoner, remove him from the
7069 * GtkList and put him into the frame "Prison"
7070 * we need to unselect the item before
7075 static_dlist.data=new_prisoner;
7076 static_dlist.next=NULL;
7077 static_dlist.prev=NULL;
7079 gtk_list_unselect_child(GTK_LIST(gtklist),
7081 gtk_widget_reparent(new_prisoner, frame);
7086 /* this is the signal handler that gets called if GtkList
7087 * emits the "selection_changed" signal
7090 sigh_print_selection (GtkWidget *gtklist,
7095 /* fetch the doubly linked list of selected items
7096 * of the GtkList, remember to treat this as read-only!
7098 dlist=GTK_LIST(gtklist)->selection;
7100 /* if there are no selected items there is nothing more
7101 * to do than just telling the user so
7104 g_print("Selection cleared\n");
7107 /* ok, we got a selection and so we print it
7109 g_print("The selection is a ");
7111 /* get the list item from the doubly linked list
7112 * and then query the data associated with list_item_data_key
7113 * we then just print it
7116 GtkObject *list_item;
7117 gchar *item_data_string;
7119 list_item=GTK_OBJECT(dlist->data);
7120 item_data_string=gtk_object_get_data(list_item,
7121 list_item_data_key);
7122 g_print("%s ", item_data_string);
7131 <!-- ----------------------------------------------------------------- -->
7132 <sect1> List Item Widget
7134 The GtkListItem widget is designed to act as a container holding up
7135 to one child, providing functions for selection/deselection just like
7136 the GtkList widget requires them for its children.
7138 A GtkListItem has its own window to receive events and has its own
7139 background color which is usually white.
7141 As it is directly derived from a
7142 GtkItem it can be treated as such by using the GTK_ITEM(ListItem)
7143 macro, see the GtkItem widget for more on this.
7144 Usually a GtkListItem just holds a label to identify e.g. a filename
7145 within a GtkList -- therefore the convenience function
7146 gtk_list_item_new_with_label() is provided. The same effect can be
7147 achieved by creating a GtkLabel on its own, setting its alignment
7148 to xalign=0 and yalign=0.5 with a subsequent container addition
7151 As one is not forced to add a GtkLabel to a GtkListItem, you could
7152 also add a GtkVBox or a GtkArrow etc. to the GtkListItem.
7154 <!-- ----------------------------------------------------------------- -->
7157 A GtkListItem does not create new signals on its own, but inherits
7158 the signals of a GtkItem. *Note GtkItem::, for more info.
7160 <!-- ----------------------------------------------------------------- -->
7164 guint gtk_list_item_get_type( void );
7167 Returns the `GtkListItem' type identifier.
7170 GtkWidget *gtk_list_item_new( void );
7173 Create a new GtkListItem object. The new widget is returned as a pointer
7174 to a GtkWidget object. NULL is returned on failure.
7177 GtkWidget *gtk_list_item_new_with_label( gchar *label );
7180 Create a new GtkListItem object, having a single GtkLabel as
7181 the sole child. The new widget is returned as a pointer to a
7182 GtkWidget object. NULL is returned on failure.
7185 void gtk_list_item_select( GtkListItem *list_item );
7188 This function is basically a wrapper around a call to
7189 gtk_item_select (GTK_ITEM (list_item)) which will emit the
7191 *Note GtkItem::, for more info.
7194 void gtk_list_item_deselect( GtkListItem *list_item );
7197 This function is basically a wrapper around a call to
7198 gtk_item_deselect (GTK_ITEM (list_item)) which will emit the
7200 *Note GtkItem::, for more info.
7203 GtkListItem *GTK_LIST_ITEM( gpointer obj );
7206 Cast a generic pointer to `GtkListItem*'. *Note Standard Macros::,
7210 GtkListItemClass *GTK_LIST_ITEM_CLASS( gpointer class );
7213 Cast a generic pointer to GtkListItemClass*. *Note Standard
7214 Macros::, for more info.
7217 gint GTK_IS_LIST_ITEM( gpointer obj );
7220 Determine if a generic pointer refers to a `GtkListItem' object.
7221 *Note Standard Macros::, for more info.
7223 <!-- ----------------------------------------------------------------- -->
7226 Please see the GtkList example on this, which covers the usage of a
7227 GtkListItem as well.
7229 <!-- ***************************************************************** -->
7230 <sect> Tree Widget<label id="sec_Tree_Widgets">
7231 <!-- ***************************************************************** -->
7234 The purpose of tree widgets is to display hierarchically-organized
7235 data. The GtkTree widget itself is a vertical container for widgets
7236 of type GtkTreeItem. GtkTree itself is not terribly different from
7237 GtkList - both are derived directly from GtkContainer, and the
7238 GtkContainer methods work in the same way on GtkTree widgets as on
7239 GtkList widgets. The difference is that GtkTree widgets can be nested
7240 within other GtkTree widgets. We'll see how to do this shortly.
7242 The GtkTree widget has its own window, and defaults to a white
7243 background, as does GtkList. Also, most of the GtkTree methods work
7244 in the same way as the corresponding GtkList ones. However, GtkTree
7245 is not derived from GtkList, so you cannot use them interchangeably.
7247 <sect1> Creating a Tree
7249 A GtkTree is created in the usual way, using:
7252 GtkWidget* gtk_tree_new( void );
7255 Like the GtkList widget, a GtkTree will simply keep growing as more
7256 items are added to it, as well as when subtrees are expanded.
7257 For this reason, they are almost always packed into a
7258 GtkScrolledWindow. You might want to use gtk_widget_set_usize() on
7259 the scrolled window to ensure that it is big enough to see the tree's
7260 items, as the default size for GtkScrolledWindow is quite small.
7262 Now that you have a tree, you'll probably want to add some items to
7263 it. <ref id="sec_Tree_Item_Widget" name="The Tree Item Widget"> below
7264 explains the gory details of GtkTreeItem. For now, it'll suffice to
7268 GtkWidget* gtk_tree_item_new_with_label( gchar *label );
7271 You can then add it to the tree using one of the following (see
7272 <ref id="sec_GtkTree_Functions" name="Functions and Macros">
7273 below for more options):
7276 void gtk_tree_append( GtkTree *tree,
7277 GtkWidget *tree_item );
7279 void gtk_tree_prepend( GtkTree *tree,
7280 GtkWidget *tree_item );
7283 Note that you must add items to a GtkTree one at a time - there is no
7284 equivalent to gtk_list_*_items().
7286 <sect1> Adding a Subtree
7288 A subtree is created like any other GtkTree widget. A subtree is added
7289 to another tree beneath a tree item, using:
7292 void gtk_tree_item_set_subtree( GtkTreeItem *tree_item,
7293 GtkWidget *subtree );
7296 You do not need to call gtk_widget_show() on a subtree before or after
7297 adding it to a GtkTreeItem. However, you <em>must</em> have added the
7298 GtkTreeItem in question to a parent tree before calling
7299 gtk_tree_item_set_subtree(). This is because, technically, the parent
7300 of the subtree is <em>not</em> the GtkTreeItem which "owns" it, but
7301 rather the GtkTree which holds that GtkTreeItem.
7303 When you add a subtree to a GtkTreeItem, a plus or minus sign appears
7304 beside it, which the user can click on to "expand" or "collapse" it,
7305 meaning, to show or hide its subtree. GtkTreeItems are collapsed by
7306 default. Note that when you collapse a GtkTreeItem, any selected
7307 items in its subtree remain selected, which may not be what the user
7310 <sect1> Handling the Selection List
7312 As with GtkList, the GtkTree type has a <tt>selection</tt> field, and
7313 it is possible to control the behaviour of the tree (somewhat) by
7314 setting the selection type using:
7317 void gtk_tree_set_selection_mode( GtkTree *tree,
7318 GtkSelectionMode mode );
7321 The semantics associated with the various selection modes are
7322 described in the section on the GtkList widget. As with the GtkList
7323 widget, the "select_child", "unselect_child" (not really - see <ref
7324 id="sec_GtkTree_Signals" name="Signals"> below for an explanation),
7325 and "selection_changed" signals are emitted when list items are
7326 selected or unselected. However, in order to take advantage of these
7327 signals, you need to know <em>which</em> GtkTree widget they will be
7328 emitted by, and where to find the list of selected items.
7330 This is a source of potential confusion. The best way to explain this
7331 is that though all GtkTree widgets are created equal, some are more
7332 equal than others. All GtkTree widgets have their own X window, and
7333 can therefore receive events such as mouse clicks (if their
7334 GtkTreeItems or their children don't catch them first!). However, to
7335 make GTK_SELECTION_SINGLE and GTK_SELECTION_BROWSE selection types
7336 behave in a sane manner, the list of selected items is specific to the
7337 topmost GtkTree widget in a hierarchy, known as the "root tree".
7339 Thus, accessing the <tt>selection</tt>field directly in an arbitrary
7340 GtkTree widget is not a good idea unless you <em>know</em> it's the
7341 root tree. Instead, use the GTK_TREE_SELECTION (Tree) macro, which
7342 gives the root tree's selection list as a GList pointer. Of course,
7343 this list can include items that are not in the subtree in question if
7344 the selection type is GTK_SELECTION_MULTIPLE.
7346 Finally, the "select_child" (and "unselect_child", in theory) signals
7347 are emitted by all trees, but the "selection_changed" signal is only
7348 emitted by the root tree. Consequently, if you want to handle the
7349 "select_child" signal for a tree and all its subtrees, you will have
7350 to call gtk_signal_connect() for every subtree.
7352 <sect1> Tree Widget Internals
7354 The GtkTree's struct definition looks like this:
7359 GtkContainer container;
7363 GtkTree* root_tree; /* owner of selection list */
7364 GtkWidget* tree_owner;
7368 guint current_indent;
7369 guint selection_mode : 2;
7370 guint view_mode : 1;
7371 guint view_line : 1;
7375 The perils associated with accessing the <tt>selection</tt> field
7376 directly have already been mentioned. The other important fields of
7377 the struct can also be accessed with handy macros or class functions.
7378 GTK_TREE_IS_ROOT_TREE (Tree) returns a boolean value which indicates
7379 whether a tree is the root tree in a GtkTree hierarchy, while
7380 GTK_TREE_ROOT_TREE (Tree) returns the root tree, an object of type
7381 GtkTree (so, remember to cast it using GTK_WIDGET (Tree) if you want
7382 to use one of the gtk_widget_*() functions on it).
7384 Instead of directly accessing the children field of a GtkTree widget,
7385 it's probably best to cast it using GTK_CONTAINER (Tree), and pass it
7386 to the gtk_container_children() function. This creates a duplicate of
7387 the original list, so it's advisable to free it up using g_list_free()
7388 after you're done with it, or to iterate on it destructively, like
7392 children = gtk_container_children (GTK_CONTAINER (tree));
7394 do_something_nice (GTK_TREE_ITEM (children->data));
7395 children = g_list_remove_link (children, children);
7399 The <tt>tree_owner</tt> field is defined only in subtrees, where it
7400 points to the GtkTreeItem widget which holds the tree in question.
7401 The <tt>level</tt> field indicates how deeply nested a particular tree
7402 is; root trees have level 0, and each successive level of subtrees has
7403 a level one greater than the parent level. This field is set only
7404 after a GtkTree widget is actually mapped (i.e. drawn on the screen).
7406 <sect2> Signals<label id="sec_GtkTree_Signals">
7409 void selection_changed( GtkTree *tree );
7412 This signal will be emitted whenever the <tt>selection</tt> field of a
7413 GtkTree has changed. This happens when a child of the GtkTree is
7414 selected or deselected.
7417 void select_child( GtkTree *tree,
7421 This signal is emitted when a child of the GtkTree is about to get
7422 selected. This happens on calls to gtk_tree_select_item(),
7423 gtk_tree_select_child(), on <em>all</em> button presses and calls to
7424 gtk_tree_item_toggle() and gtk_item_toggle(). It may sometimes be
7425 indirectly triggered on other occasions where children get added to or
7426 removed from the GtkTree.
7429 void unselect_child (GtkTree *tree,
7433 This signal is emitted when a child of the GtkTree is about to get
7434 deselected. As of GTK+ 1.0.4, this seems to only occur on calls to
7435 gtk_tree_unselect_item() or gtk_tree_unselect_child(), and perhaps on
7436 other occasions, but <em>not</em> when a button press deselects a
7437 child, nor on emission of the "toggle" signal by gtk_item_toggle().
7439 <sect2> Functions and Macros<label id="sec_GtkTree_Functions">
7442 guint gtk_tree_get_type( void );
7445 Returns the `GtkTree' type identifier.
7448 GtkWidget* gtk_tree_new( void );
7451 Create a new GtkTree object. The new widget is returned as a pointer to a
7452 GtkWidget object. NULL is returned on failure.
7455 void gtk_tree_append( GtkTree *tree,
7456 GtkWidget *tree_item );
7459 Append a tree item to a GtkTree.
7462 void gtk_tree_prepend( GtkTree *tree,
7463 GtkWidget *tree_item );
7466 Prepend a tree item to a GtkTree.
7469 void gtk_tree_insert( GtkTree *tree,
7470 GtkWidget *tree_item,
7474 Insert a tree item into a GtkTree at the position in the list
7475 specified by <tt>position.</tt>
7478 void gtk_tree_remove_items( GtkTree *tree,
7482 Remove a list of items (in the form of a GList *) from a GtkTree.
7483 Note that removing an item from a tree dereferences (and thus usually)
7484 destroys it <em>and</em> its subtree, if it has one, <em>and</em> all
7485 subtrees in that subtree. If you want to remove only one item, you
7486 can use gtk_container_remove().
7489 void gtk_tree_clear_items( GtkTree *tree,
7494 Remove the items from position <tt>start</tt> to position <tt>end</tt>
7495 from a GtkTree. The same warning about dereferencing applies here, as
7496 gtk_tree_clear_items() simply constructs a list and passes it to
7497 gtk_tree_remove_items().
7500 void gtk_tree_select_item( GtkTree *tree,
7504 Emits the "select_item" signal for the child at position
7505 <tt>item</tt>, thus selecting the child (unless you unselect it in a
7509 void gtk_tree_unselect_item( GtkTree *tree,
7513 Emits the "unselect_item" signal for the child at position
7514 <tt>item</tt>, thus unselecting the child.
7517 void gtk_tree_select_child( GtkTree *tree,
7518 GtkWidget *tree_item );
7521 Emits the "select_item" signal for the child <tt>tree_item</tt>, thus
7525 void gtk_tree_unselect_child( GtkTree *tree,
7526 GtkWidget *tree_item );
7529 Emits the "unselect_item" signal for the child <tt>tree_item</tt>,
7530 thus unselecting it.
7533 gint gtk_tree_child_position( GtkTree *tree,
7537 Returns the position in the tree of <tt>child</tt>, unless
7538 <tt>child</tt> is not in the tree, in which case it returns -1.
7541 void gtk_tree_set_selection_mode( GtkTree *tree,
7542 GtkSelectionMode mode );
7545 Sets the selection mode, which can be one of GTK_SELECTION_SINGLE (the
7546 default), GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE, or
7547 GTK_SELECTION_EXTENDED. This is only defined for root trees, which
7548 makes sense, since the root tree "owns" the selection. Setting it for
7549 subtrees has no effect at all; the value is simply ignored.
7552 void gtk_tree_set_view_mode( GtkTree *tree,
7553 GtkTreeViewMode mode );
7556 Sets the "view mode", which can be either GTK_TREE_VIEW_LINE (the
7557 default) or GTK_TREE_VIEW_ITEM. The view mode propagates from a tree
7558 to its subtrees, and can't be set exclusively to a subtree (this is
7559 not exactly true - see the example code comments).
7561 The term "view mode" is rather ambiguous - basically, it controls the
7562 way the highlight is drawn when one of a tree's children is selected.
7563 If it's GTK_TREE_VIEW_LINE, the entire GtkTreeItem widget is
7564 highlighted, while for GTK_TREE_VIEW_ITEM, only the child widget
7565 (i.e. usually the label) is highlighted.
7568 void gtk_tree_set_view_lines( GtkTree *tree,
7572 Controls whether connecting lines between tree items are drawn.
7573 <tt>flag</tt> is either TRUE, in which case they are, or FALSE, in
7574 which case they aren't.
7577 GtkTree *GTK_TREE (gpointer obj);
7580 Cast a generic pointer to `GtkTree *'.
7583 GtkTreeClass *GTK_TREE_CLASS (gpointer class);
7586 Cast a generic pointer to `GtkTreeClass*'.
7589 gint GTK_IS_TREE (gpointer obj);
7592 Determine if a generic pointer refers to a `GtkTree' object.
7595 gint GTK_IS_ROOT_TREE (gpointer obj)
7598 Determine if a generic pointer refers to a `GtkTree' object
7599 <em>and</em> is a root tree. Though this will accept any pointer, the
7600 results of passing it a pointer that does not refer to a GtkTree are
7601 undefined and possibly harmful.
7604 GtkTree *GTK_TREE_ROOT_TREE (gpointer obj)
7607 Return the root tree of a pointer to a `GtkTree' object. The above
7611 GList *GTK_TREE_SELECTION( gpointer obj)
7614 Return the selection list of the root tree of a `GtkTree' object. The
7615 above warning applies here, too.
7617 <sect1> Tree Item Widget<label id="sec_Tree_Item_Widget">
7619 The GtkTreeItem widget, like GtkListItem, is derived from GtkItem,
7620 which in turn is derived from GtkBin. Therefore, the item itself is a
7621 generic container holding exactly one child widget, which can be of
7622 any type. The GtkTreeItem widget has a number of extra fields, but
7623 the only one we need be concerned with is the <tt>subtree</tt> field.
7625 The definition for the GtkTreeItem struct looks like this:
7633 GtkWidget *pixmaps_box;
7634 GtkWidget *plus_pix_widget, *minus_pix_widget;
7636 GList *pixmaps; /* pixmap node for this items color depth */
7642 The <tt>pixmaps_box</tt> field is a GtkEventBox which catches clicks
7643 on the plus/minus symbol which controls expansion and collapsing. The
7644 <tt>pixmaps</tt> field points to an internal data structure. Since
7645 you can always obtain the subtree of a GtkTreeItem in a (relatively)
7646 type-safe manner with the GTK_TREE_ITEM_SUBTREE (Item) macro, it's
7647 probably advisable never to touch the insides of a GtkTreeItem unless
7648 you <em>really</em> know what you're doing.
7650 Since it is directly derived from a GtkItem it can be treated as such
7651 by using the GTK_ITEM (TreeItem) macro. A GtkTreeItem usually holds a
7652 label, so the convenience function gtk_list_item_new_with_label() is
7653 provided. The same effect can be achieved using code like the
7654 following, which is actually copied verbatim from
7655 gtk_tree_item_new_with_label():
7658 tree_item = gtk_tree_item_new ();
7659 label_widget = gtk_label_new (label);
7660 gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
7662 gtk_container_add (GTK_CONTAINER (tree_item), label_widget);
7663 gtk_widget_show (label_widget);
7666 As one is not forced to add a GtkLabel to a GtkTreeItem, you could
7667 also add a GtkHBox or a GtkArrow, or even a GtkNotebook (though your
7668 app will likely be quite unpopular in this case) to the GtkTreeItem.
7670 If you remove all the items from a subtree, it will be destroyed and
7671 unparented, unless you reference it beforehand, and the GtkTreeItem
7672 which owns it will be collapsed. So, if you want it to stick around,
7673 do something like the following:
7676 gtk_widget_ref (tree);
7677 owner = GTK_TREE(tree)->tree_owner;
7678 gtk_container_remove (GTK_CONTAINER(tree), item);
7679 if (tree->parent == NULL){
7680 gtk_tree_item_expand (GTK_TREE_ITEM(owner));
7681 gtk_tree_item_set_subtree (GTK_TREE_ITEM(owner), tree);
7684 gtk_widget_unref (tree);
7687 Finally, drag-n-drop <em>does</em> work with GtkTreeItems. You just
7688 have to make sure that the GtkTreeItem you want to make into a drag
7689 item or a drop site has not only been added to a GtkTree, but that
7690 each successive parent widget has a parent itself, all the way back to
7691 a toplevel or dialog window, when you call gtk_widget_dnd_drag_set()
7692 or gtk_widget_dnd_drop_set(). Otherwise, strange things will happen.
7696 GtkTreeItem inherits the "select", "deselect", and "toggle" signals
7697 from GtkItem. In addition, it adds two signals of its own, "expand"
7701 void select( GtkItem *tree_item );
7704 This signal is emitted when an item is about to be selected, either
7705 after it has been clicked on by the user, or when the program calls
7706 gtk_tree_item_select(), gtk_item_select(), or gtk_tree_select_child().
7709 void deselect( GtkItem *tree_item );
7712 This signal is emitted when an item is about to be unselected, either
7713 after it has been clicked on by the user, or when the program calls
7714 gtk_tree_item_deselect() or gtk_item_deselect(). In the case of
7715 GtkTreeItems, it is also emitted by gtk_tree_unselect_child(), and
7716 sometimes gtk_tree_select_child().
7719 void toggle( GtkItem *tree_item );
7722 This signal is emitted when the program calls gtk_item_toggle(). The
7723 effect it has when emitted on a GtkTreeItem is to call
7724 gtk_tree_select_child() (and never gtk_tree_unselect_child()) on the
7725 item's parent tree, if the item has a parent tree. If it doesn't,
7726 then the highlight is reversed on the item.
7729 void expand( GtkTreeItem *tree_item );
7732 This signal is emitted when the tree item's subtree is about to be
7733 expanded, that is, when the user clicks on the plus sign next to the
7734 item, or when the program calls gtk_tree_item_expand().
7737 void collapse( GtkTreeItem *tree_item );
7740 This signal is emitted when the tree item's subtree is about to be
7741 collapsed, that is, when the user clicks on the minus sign next to the
7742 item, or when the program calls gtk_tree_item_collapse().
7744 <sect2> Functions and Macros
7747 guint gtk_tree_item_get_type( void );
7750 Returns the `GtkTreeItem' type identifier.
7753 GtkWidget* gtk_tree_item_new( void );
7756 Create a new GtkTreeItem object. The new widget is returned as a pointer
7757 to a GtkWidget object. NULL is returned on failure.
7760 GtkWidget* gtk_tree_item_new_with_label (gchar *label);
7763 Create a new GtkTreeItem object, having a single GtkLabel as
7764 the sole child. The new widget is returned as a pointer to a
7765 GtkWidget object. NULL is returned on failure.
7768 void gtk_tree_item_select( GtkTreeItem *tree_item );
7771 This function is basically a wrapper around a call to
7772 gtk_item_select (GTK_ITEM (tree_item)) which will emit the
7776 void gtk_tree_item_deselect( GtkTreeItem *tree_item );
7779 This function is basically a wrapper around a call to
7780 gtk_item_deselect (GTK_ITEM (tree_item)) which will emit the
7784 void gtk_tree_item_set_subtree( GtkTreeItem *tree_item,
7785 GtkWidget *subtree );
7788 This function adds subtree to tree_item, showing it if tree_item is
7789 expanded, or hiding it if tree_item is collapsed. Again, remember
7790 that the tree_item must have already been added to a tree for this to
7794 void gtk_tree_item_remove_subtree( GtkTreeItem *tree_item );
7797 This removes all of tree_item's subtree's children (thus unreferencing
7798 and destroying it, any of its children's subtrees, and so on...), then
7799 removes the subtree itself, and hides the plus/minus sign.
7802 void gtk_tree_item_expand( GtkTreeItem *tree_item );
7805 This emits the "expand" signal on tree_item, which expands it.
7808 void gtk_tree_item_collapse( GtkTreeItem *tree_item );
7811 This emits the "collapse" signal on tree_item, which collapses it.
7814 GtkTreeItem *GTK_TREE_ITEM (gpointer obj)
7817 Cast a generic pointer to `GtkTreeItem*'.
7820 GtkTreeItemClass *GTK_TREE_ITEM_CLASS (gpointer obj)
7823 Cast a generic pointer to `GtkTreeItemClass'.
7826 gint GTK_IS_TREE_ITEM (gpointer obj)
7829 Determine if a generic pointer refers to a `GtkTreeItem' object.
7832 GtkWidget GTK_TREE_ITEM_SUBTREE (gpointer obj)
7835 Returns a tree item's subtree (obj should point to a `GtkTreeItem'
7838 <sect1> Tree Example
7840 This is somewhat like the tree example in testgtk.c, but a lot less
7841 complete (although much better commented). It puts up a window with a
7842 tree, and connects all the signals for the relevant objects, so you
7843 can see when they are emitted.
7846 /* example-start tree tree.c */
7848 #include <gtk/gtk.h>
7850 /* for all the GtkItem:: and GtkTreeItem:: signals */
7851 static void cb_itemsignal (GtkWidget *item, gchar *signame)
7856 /* It's a GtkBin, so it has one child, which we know to be a
7857 label, so get that */
7858 label = GTK_LABEL (GTK_BIN (item)->child);
7859 /* Get the text of the label */
7860 gtk_label_get (label, &name);
7861 /* Get the level of the tree which the item is in */
7862 g_print ("%s called for item %s->%p, level %d\n", signame, name,
7863 item, GTK_TREE (item->parent)->level);
7866 /* Note that this is never called */
7867 static void cb_unselect_child (GtkWidget *root_tree, GtkWidget *child,
7870 g_print ("unselect_child called for root tree %p, subtree %p, child %p\n",
7871 root_tree, subtree, child);
7874 /* Note that this is called every time the user clicks on an item,
7875 whether it is already selected or not. */
7876 static void cb_select_child (GtkWidget *root_tree, GtkWidget *child,
7879 g_print ("select_child called for root tree %p, subtree %p, child %p\n",
7880 root_tree, subtree, child);
7883 static void cb_selection_changed (GtkWidget *tree)
7887 g_print ("selection_change called for tree %p\n", tree);
7888 g_print ("selected objects are:\n");
7890 i = GTK_TREE_SELECTION(tree);
7896 /* Get a GtkWidget pointer from the list node */
7897 item = GTK_WIDGET (i->data);
7898 label = GTK_LABEL (GTK_BIN (item)->child);
7899 gtk_label_get (label, &name);
7900 g_print ("\t%s on level %d\n", name, GTK_TREE
7901 (item->parent)->level);
7906 int main (int argc, char *argv[])
7908 GtkWidget *window, *scrolled_win, *tree;
7909 static gchar *itemnames[] = {"Foo", "Bar", "Baz", "Quux",
7913 gtk_init (&argc, &argv);
7915 /* a generic toplevel window */
7916 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
7917 gtk_signal_connect (GTK_OBJECT(window), "delete_event",
7918 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
7919 gtk_container_border_width (GTK_CONTAINER(window), 5);
7921 /* A generic scrolled window */
7922 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
7923 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
7924 GTK_POLICY_AUTOMATIC,
7925 GTK_POLICY_AUTOMATIC);
7926 gtk_widget_set_usize (scrolled_win, 150, 200);
7927 gtk_container_add (GTK_CONTAINER(window), scrolled_win);
7928 gtk_widget_show (scrolled_win);
7930 /* Create the root tree */
7931 tree = gtk_tree_new();
7932 g_print ("root tree is %p\n", tree);
7933 /* connect all GtkTree:: signals */
7934 gtk_signal_connect (GTK_OBJECT(tree), "select_child",
7935 GTK_SIGNAL_FUNC(cb_select_child), tree);
7936 gtk_signal_connect (GTK_OBJECT(tree), "unselect_child",
7937 GTK_SIGNAL_FUNC(cb_unselect_child), tree);
7938 gtk_signal_connect (GTK_OBJECT(tree), "selection_changed",
7939 GTK_SIGNAL_FUNC(cb_selection_changed), tree);
7940 /* Add it to the scrolled window */
7941 gtk_container_add (GTK_CONTAINER(scrolled_win), tree);
7942 /* Set the selection mode */
7943 gtk_tree_set_selection_mode (GTK_TREE(tree),
7944 GTK_SELECTION_MULTIPLE);
7946 gtk_widget_show (tree);
7948 for (i = 0; i < 5; i++){
7949 GtkWidget *subtree, *item;
7952 /* Create a tree item */
7953 item = gtk_tree_item_new_with_label (itemnames[i]);
7954 /* Connect all GtkItem:: and GtkTreeItem:: signals */
7955 gtk_signal_connect (GTK_OBJECT(item), "select",
7956 GTK_SIGNAL_FUNC(cb_itemsignal), "select");
7957 gtk_signal_connect (GTK_OBJECT(item), "deselect",
7958 GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
7959 gtk_signal_connect (GTK_OBJECT(item), "toggle",
7960 GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
7961 gtk_signal_connect (GTK_OBJECT(item), "expand",
7962 GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
7963 gtk_signal_connect (GTK_OBJECT(item), "collapse",
7964 GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
7965 /* Add it to the parent tree */
7966 gtk_tree_append (GTK_TREE(tree), item);
7967 /* Show it - this can be done at any time */
7968 gtk_widget_show (item);
7969 /* Create this item's subtree */
7970 subtree = gtk_tree_new();
7971 g_print ("-> item %s->%p, subtree %p\n", itemnames[i], item,
7974 /* This is still necessary if you want these signals to be called
7975 for the subtree's children. Note that selection_change will be
7976 signalled for the root tree regardless. */
7977 gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
7978 GTK_SIGNAL_FUNC(cb_select_child), subtree);
7979 gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
7980 GTK_SIGNAL_FUNC(cb_unselect_child), subtree);
7981 /* This has absolutely no effect, because it is completely ignored
7983 gtk_tree_set_selection_mode (GTK_TREE(subtree),
7984 GTK_SELECTION_SINGLE);
7985 /* Neither does this, but for a rather different reason - the
7986 view_mode and view_line values of a tree are propagated to
7987 subtrees when they are mapped. So, setting it later on would
7988 actually have a (somewhat unpredictable) effect */
7989 gtk_tree_set_view_mode (GTK_TREE(subtree), GTK_TREE_VIEW_ITEM);
7990 /* Set this item's subtree - note that you cannot do this until
7991 AFTER the item has been added to its parent tree! */
7992 gtk_tree_item_set_subtree (GTK_TREE_ITEM(item), subtree);
7994 for (j = 0; j < 5; j++){
7997 /* Create a subtree item, in much the same way */
7998 subitem = gtk_tree_item_new_with_label (itemnames[j]);
7999 /* Connect all GtkItem:: and GtkTreeItem:: signals */
8000 gtk_signal_connect (GTK_OBJECT(subitem), "select",
8001 GTK_SIGNAL_FUNC(cb_itemsignal), "select");
8002 gtk_signal_connect (GTK_OBJECT(subitem), "deselect",
8003 GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
8004 gtk_signal_connect (GTK_OBJECT(subitem), "toggle",
8005 GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
8006 gtk_signal_connect (GTK_OBJECT(subitem), "expand",
8007 GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
8008 gtk_signal_connect (GTK_OBJECT(subitem), "collapse",
8009 GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
8010 g_print ("-> -> item %s->%p\n", itemnames[j], subitem);
8011 /* Add it to its parent tree */
8012 gtk_tree_append (GTK_TREE(subtree), subitem);
8014 gtk_widget_show (subitem);
8018 /* Show the window and loop endlessly */
8019 gtk_widget_show (window);
8026 <!-- ***************************************************************** -->
8028 <!-- ***************************************************************** -->
8030 There are two ways to create menus, there's the easy way, and there's the
8031 hard way. Both have their uses, but you can usually use the menufactory
8032 (the easy way). The "hard" way is to create all the menus using the calls
8033 directly. The easy way is to use the gtk_menu_factory calls. This is
8034 much simpler, but there are advantages and disadvantages to each approach.
8036 The menufactory is much easier to use, and to add new menus to, although
8037 writing a few wrapper functions to create menus using the manual method
8038 could go a long way towards usability. With the menufactory, it is not
8039 possible to add images or the character '/' to the menus.
8041 <!-- ----------------------------------------------------------------- -->
8042 <sect1>Manual Menu Creation
8044 In the true tradition of teaching, we'll show you the hard
8045 way first. <tt>:)</>
8047 There are three widgets that go into making a menubar and submenus:
8049 <item>a menu item, which is what the user wants to select, e.g. 'Save'
8050 <item>a menu, which acts as a container for the menu items, and
8051 <item>a menubar, which is a container for each of the individual menus,
8054 This is slightly complicated by the fact that menu item widgets are used
8055 for two different things. They are both the widgets that are packed into
8056 the menu, and the widget that is packed into the menubar, which,
8057 when selected, activates the menu.
8059 Let's look at the functions that are used to create menus and menubars.
8060 This first function is used to create a new menubar.
8063 GtkWidget *gtk_menu_bar_new( void );
8066 This rather self explanatory function creates a new menubar. You use
8067 gtk_container_add to pack this into a window, or the box_pack functions to
8068 pack it into a box - the same as buttons.
8071 GtkWidget *gtk_menu_new( void );
8074 This function returns a pointer to a new menu, it is never actually shown
8075 (with gtk_widget_show), it is just a container for the menu items. Hopefully this will
8076 become more clear when you look at the example below.
8078 The next two calls are used to create menu items that are packed into
8079 the menu (and menubar).
8082 GtkWidget *gtk_menu_item_new( void );
8088 GtkWidget *gtk_menu_item_new_with_label( const char *label );
8091 These calls are used to create the menu items that are to be displayed.
8092 Remember to differentiate between a "menu" as created with gtk_menu_new
8093 and a "menu item" as created by the gtk_menu_item_new functions. The
8094 menu item will be an actual button with an associated action,
8095 whereas a menu will be a container holding menu items.
8097 The gtk_menu_new_with_label and gtk_menu_new functions are just as you'd expect after
8098 reading about the buttons. One creates a new menu item with a label
8099 already packed into it, and the other just creates a blank menu item.
8101 Once you've created a menu item you have to put it into a menu. This is
8102 done using the function gtk_menu_append. In order to capture when the item
8103 is selected by the user, we need to connect to the <tt/activate/ signal in
8104 the usual way. So, if we wanted to create a standard <tt/File/ menu, with
8105 the options <tt/Open/, <tt/Save/ and <tt/Quit/ the code would look something like
8108 file_menu = gtk_menu_new(); /* Don't need to show menus */
8110 /* Create the menu items */
8111 open_item = gtk_menu_item_new_with_label("Open");
8112 save_item = gtk_menu_item_new_with_label("Save");
8113 quit_item = gtk_menu_item_new_with_label("Quit");
8115 /* Add them to the menu */
8116 gtk_menu_append( GTK_MENU(file_menu), open_item);
8117 gtk_menu_append( GTK_MENU(file_menu), save_item);
8118 gtk_menu_append( GTK_MENU(file_menu), quit_item);
8120 /* Attach the callback functions to the activate signal */
8121 gtk_signal_connect_object( GTK_OBJECT(open_items), "activate",
8122 GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.open");
8123 gtk_signal_connect_object( GTK_OBJECT(save_items), "activate",
8124 GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.save");
8126 /* We can attach the Quit menu item to our exit function */
8127 gtk_signal_connect_object( GTK_OBJECT(quit_items), "activate",
8128 GTK_SIGNAL_FUNC(destroy), (gpointer) "file.quit");
8130 /* We do need to show menu items */
8131 gtk_widget_show( open_item );
8132 gtk_widget_show( save_item );
8133 gtk_widget_show( quit_item );
8136 At this point we have our menu. Now we need to create a menubar and a menu
8137 item for the <tt/File/ entry, to which we add our menu. The code looks like this
8140 menu_bar = gtk_menu_bar_new();
8141 gtk_container_add( GTK_CONTAINER(window), menu_bar);
8142 gtk_widget_show( menu_bar );
8144 file_item = gtk_menu_item_new_with_label("File");
8145 gtk_widget_show(file_item);
8148 Now we need to associate the menu with <tt/file_item/. This is done with the
8152 void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
8153 GtkWidget *submenu );
8156 So, our example would continue with
8159 gtk_menu_item_set_submenu( GTK_MENU_ITEM(file_item), file_menu );
8162 All that is left to do is to add the menu to the menubar, which is accomplished
8166 void gtk_menu_bar_append( GtkMenuBar *menu_bar, GtkWidget *menu_item);
8169 which in our case looks like this:
8172 gtk_menu_bar_append( GTK_MENU_BAR (menu_bar), file_item );
8175 If we wanted the menu right justified on the menubar, such as help menus
8176 often are, we can use the following function (again on <tt/file_item/
8177 in the current example) before attaching it to the menubar.
8180 void gtk_menu_item_right_justify( GtkMenuItem *menu_item );
8183 Here is a summary of the steps needed to create a menu bar with menus attached:
8186 <item> Create a new menu using gtk_menu_new()
8187 <item> Use multiple calls to gtk_menu_item_new() for each item you wish to have
8188 on your menu. And use gtk_menu_append() to put each of these new items on
8190 <item> Create a menu item using gtk_menu_item_new(). This will be the root of
8191 the menu, the text appearing here will be on the menubar itself.
8192 <item>Use gtk_menu_item_set_submenu() to attach the menu to the root menu
8193 item (the one created in the above step).
8194 <item> Create a new menubar using gtk_menu_bar_new. This step only needs
8195 to be done once when creating a series of menus on one menu bar.
8196 <item> Use gtk_menu_bar_append to put the root menu onto the menubar.
8199 Creating a popup menu is nearly the same. The difference is that the
8200 menu is not posted `automatically' by a menubar, but explicitly by calling
8201 the function gtk_menu_popup() from a button-press event, for example.
8205 <item>Create an event handling function. It needs to have the prototype
8207 static gint handler( GtkWidget *widget,
8210 and it will use the event to find out where to pop up the menu.
8211 <item>In the event handler, if the event is a mouse button press, treat
8212 <tt>event</tt> as a button event (which it is) and use it as
8213 shown in the sample code to pass information to gtk_menu_popup().
8214 <item>Bind that event handler to a widget with
8216 gtk_signal_connect_object(GTK_OBJECT(widget), "event",
8217 GTK_SIGNAL_FUNC (handler), GTK_OBJECT(menu));
8219 where <tt>widget</tt> is the widget you are binding to, <tt>handler</tt>
8220 is the handling function, and <tt>menu</tt> is a menu created with
8221 gtk_menu_new(). This can be a menu which is also posted by a menu bar,
8222 as shown in the sample code.
8225 <!-- ----------------------------------------------------------------- -->
8226 <sect1>Manual Menu Example
8228 That should about do it. Let's take a look at an example to help clarify.
8231 /* example-start menu menu.c */
8233 #include <gtk/gtk.h>
8235 static gint button_press (GtkWidget *, GdkEvent *);
8236 static void menuitem_response (gchar *);
8238 int main (int argc, char *argv[])
8243 GtkWidget *menu_bar;
8244 GtkWidget *root_menu;
8245 GtkWidget *menu_items;
8251 gtk_init (&argc, &argv);
8253 /* create a new window */
8254 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
8255 gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
8256 gtk_window_set_title(GTK_WINDOW (window), "GTK Menu Test");
8257 gtk_signal_connect(GTK_OBJECT (window), "delete_event",
8258 (GtkSignalFunc) gtk_main_quit, NULL);
8260 /* Init the menu-widget, and remember -- never
8261 * gtk_show_widget() the menu widget!!
8262 * This is the menu that holds the menu items, the one that
8263 * will pop up when you click on the "Root Menu" in the app */
8264 menu = gtk_menu_new();
8266 /* Next we make a little loop that makes three menu-entries for "test-menu".
8267 * Notice the call to gtk_menu_append. Here we are adding a list of
8268 * menu items to our menu. Normally, we'd also catch the "clicked"
8269 * signal on each of the menu items and setup a callback for it,
8270 * but it's omitted here to save space. */
8272 for(i = 0; i < 3; i++)
8274 /* Copy the names to the buf. */
8275 sprintf(buf, "Test-undermenu - %d", i);
8277 /* Create a new menu-item with a name... */
8278 menu_items = gtk_menu_item_new_with_label(buf);
8280 /* ...and add it to the menu. */
8281 gtk_menu_append(GTK_MENU (menu), menu_items);
8283 /* Do something interesting when the menuitem is selected */
8284 gtk_signal_connect_object(GTK_OBJECT(menu_items), "activate",
8285 GTK_SIGNAL_FUNC(menuitem_response), (gpointer) g_strdup(buf));
8287 /* Show the widget */
8288 gtk_widget_show(menu_items);
8291 /* This is the root menu, and will be the label
8292 * displayed on the menu bar. There won't be a signal handler attached,
8293 * as it only pops up the rest of the menu when pressed. */
8294 root_menu = gtk_menu_item_new_with_label("Root Menu");
8296 gtk_widget_show(root_menu);
8298 /* Now we specify that we want our newly created "menu" to be the menu
8299 * for the "root menu" */
8300 gtk_menu_item_set_submenu(GTK_MENU_ITEM (root_menu), menu);
8302 /* A vbox to put a menu and a button in: */
8303 vbox = gtk_vbox_new(FALSE, 0);
8304 gtk_container_add(GTK_CONTAINER(window), vbox);
8305 gtk_widget_show(vbox);
8307 /* Create a menu-bar to hold the menus and add it to our main window */
8308 menu_bar = gtk_menu_bar_new();
8309 gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 2);
8310 gtk_widget_show(menu_bar);
8312 /* Create a button to which to attach menu as a popup */
8313 button = gtk_button_new_with_label("press me");
8314 gtk_signal_connect_object(GTK_OBJECT(button), "event",
8315 GTK_SIGNAL_FUNC (button_press), GTK_OBJECT(menu));
8316 gtk_box_pack_end(GTK_BOX(vbox), button, TRUE, TRUE, 2);
8317 gtk_widget_show(button);
8319 /* And finally we append the menu-item to the menu-bar -- this is the
8320 * "root" menu-item I have been raving about =) */
8321 gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), root_menu);
8323 /* always display the window as the last step so it all splashes on
8324 * the screen at once. */
8325 gtk_widget_show(window);
8332 /* Respond to a button-press by posting a menu passed in as widget.
8334 * Note that the "widget" argument is the menu being posted, NOT
8335 * the button that was pressed.
8338 static gint button_press (GtkWidget *widget, GdkEvent *event)
8341 if (event->type == GDK_BUTTON_PRESS) {
8342 GdkEventButton *bevent = (GdkEventButton *) event;
8343 gtk_menu_popup (GTK_MENU(widget), NULL, NULL, NULL, NULL,
8344 bevent->button, bevent->time);
8345 /* Tell calling code that we have handled this event; the buck
8350 /* Tell calling code that we have not handled this event; pass it on. */
8355 /* Print a string when a menu item is selected */
8357 static void menuitem_response (gchar *string)
8359 printf("%s\n", string);
8364 You may also set a menu item to be insensitive and, using an accelerator
8365 table, bind keys to menu functions.
8367 <!-- ----------------------------------------------------------------- -->
8368 <sect1>Using GtkMenuFactory
8370 Now that we've shown you the hard way, here's how you do it using the
8371 gtk_menu_factory calls.
8373 <!-- ----------------------------------------------------------------- -->
8374 <sect1>Menu Factory Example
8376 Here is an example using the GTK menu factory. This is the first file,
8377 menufactory.h. We keep a separate menufactory.c and mfmain.c because
8378 of the global variables used in the menufactory.c file.
8381 /* example-start menu menufactory.h */
8383 #ifndef __MENUFACTORY_H__
8384 #define __MENUFACTORY_H__
8388 #endif /* __cplusplus */
8390 void get_main_menu (GtkWidget *, GtkWidget **menubar);
8394 #endif /* __cplusplus */
8396 #endif /* __MENUFACTORY_H__ */
8401 And here is the menufactory.c file.
8404 /* example-start menu menufactory.c */
8406 #include <gtk/gtk.h>
8407 #include <strings.h>
8411 static void print_hello(GtkWidget *widget, gpointer data);
8414 /* this is the GtkMenuEntry structure used to create new menus. The
8415 * first member is the menu definition string. The second, the
8416 * default accelerator key used to access this menu function with
8417 * the keyboard. The third is the callback function to call when
8418 * this menu item is selected (by the accelerator key, or with the
8419 * mouse.) The last member is the data to pass to your callback function.
8422 static GtkMenuEntry menu_items[] =
8424 {"<Main>/File/New", "<control>N", print_hello, NULL},
8425 {"<Main>/File/Open", "<control>O", print_hello, NULL},
8426 {"<Main>/File/Save", "<control>S", print_hello, NULL},
8427 {"<Main>/File/Save as", NULL, NULL, NULL},
8428 {"<Main>/File/<separator>", NULL, NULL, NULL},
8429 {"<Main>/File/Quit", "<control>Q", file_quit_cmd_callback, "OK, I'll quit"},
8430 {"<Main>/Options/Test", NULL, NULL, NULL}
8435 print_hello(GtkWidget *widget, gpointer data)
8440 void get_main_menu(GtkWidget *window, GtkWidget ** menubar)
8442 int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
8443 GtkMenuFactory *factory;
8444 GtkMenuFactory *subfactory;
8446 factory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
8447 subfactory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
8449 gtk_menu_factory_add_subfactory(factory, subfactory, "<Main>");
8450 gtk_menu_factory_add_entries(factory, menu_items, nmenu_items);
8451 gtk_window_add_accelerator_table(GTK_WINDOW(window), subfactory->table);
8454 *menubar = subfactory->widget;
8460 And here's the mfmain.h
8463 /* example-start menu mfmain.h */
8465 #ifndef __MFMAIN_H__
8466 #define __MFMAIN_H__
8471 #endif /* __cplusplus */
8473 void file_quit_cmd_callback(GtkWidget *widget, gpointer data);
8477 #endif /* __cplusplus */
8479 #endif /* __MFMAIN_H__ */
8487 /* example-start menu mfmain.c */
8489 #include <gtk/gtk.h>
8492 #include "menufactory.h"
8494 int main(int argc, char *argv[])
8497 GtkWidget *main_vbox;
8500 gtk_init(&argc, &argv);
8502 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
8503 gtk_signal_connect(GTK_OBJECT(window), "destroy",
8504 GTK_SIGNAL_FUNC(file_quit_cmd_callback),
8506 gtk_window_set_title(GTK_WINDOW(window), "Menu Factory");
8507 gtk_widget_set_usize(GTK_WIDGET(window), 300, 200);
8509 main_vbox = gtk_vbox_new(FALSE, 1);
8510 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
8511 gtk_container_add(GTK_CONTAINER(window), main_vbox);
8512 gtk_widget_show(main_vbox);
8514 get_main_menu(window, &menubar);
8515 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
8516 gtk_widget_show(menubar);
8518 gtk_widget_show(window);
8524 /* This is just to demonstrate how callbacks work when using the
8525 * menufactory. Often, people put all the callbacks from the menus
8526 * in a separate file, and then have them call the appropriate functions
8527 * from there. Keeps it more organized. */
8528 void file_quit_cmd_callback (GtkWidget *widget, gpointer data)
8530 g_print ("%s\n", (char *) data);
8537 And a makefile so it'll be easier to compile it.
8544 C_FLAGS = -Wall $(PROF) -L/usr/local/include -DDEBUG
8545 L_FLAGS = $(PROF) -L/usr/X11R6/lib -L/usr/local/lib
8546 L_POSTFLAGS = -lgtk -lgdk -lglib -lXext -lX11 -lm
8547 PROGNAME = menufactory
8549 O_FILES = menufactory.o mfmain.o
8551 $(PROGNAME): $(O_FILES)
8553 $(CC) $(L_FLAGS) -o $(PROGNAME) $(O_FILES) $(L_POSTFLAGS)
8556 $(CC) -c $(C_FLAGS) $<
8559 rm -f core *.o $(PROGNAME) nohup.out
8564 For now, there's only this example. An explanation and lots 'o' comments
8567 <!-- ***************************************************************** -->
8569 <!-- ***************************************************************** -->
8571 The Text widget allows multiple lines of text to be displayed and edited.
8572 It supports both multi-colored and multi-font text, allowing them to be
8573 mixed in any way we wish. It also has a wide set of key based text editing
8574 commands, which are compatible with Emacs.
8576 The text widget supports full cut-and-paste facilities, including the use
8577 of double- and triple-click to select a word and a whole line, respectively.
8579 <!-- ----------------------------------------------------------------- -->
8580 <sect1>Creating and Configuring a Text box
8582 There is only one function for creating a new Text widget.
8584 GtkWidget *gtk_text_new( GtkAdjustment *hadj,
8585 GtkAdjustment *vadj );
8588 The arguments allow us to give the Text widget pointers to Adjustments
8589 that can be used to track the viewing position of the widget. Passing NULL
8590 values to either or both of these arguments will cause the gtk_text_new
8591 function to create its own.
8594 void gtk_text_set_adjustments( GtkText *text,
8595 GtkAdjustment *hadj,
8596 GtkAdjustment *vadj );
8599 The above function allows the horizontal and vertical adjustments of a
8600 Text widget to be changed at any time.
8602 The text widget will not automatically create its own scrollbars when
8603 the amount of text to be displayed is too long for the display window. We
8604 therefore have to create and add them to the display layout ourselves.
8607 vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
8608 gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, FALSE, 0);
8609 gtk_widget_show (vscrollbar);
8612 The above code snippet creates a new vertical scrollbar, and attaches
8613 it to the vertical adjustment of the text widget, <tt/text/. It then packs
8614 it into a box in the normal way.
8616 Note, currently the GtkText widget does not support horizontal scrollbars.
8618 There are two main ways in which a Text widget can be used: to allow the
8619 user to edit a body of text, or to allow us to display multiple lines of
8620 text to the user. In order for us to switch between these modes of
8621 operation, the text widget has the following function:
8624 void gtk_text_set_editable( GtkText *text,
8628 The <tt/editable/ argument is a TRUE or FALSE value that specifies whether
8629 the user is permitted to edit the contents of the Text widget. When the
8630 text widget is editable, it will display a cursor at the current insertion
8633 You are not, however, restricted to just using the text widget in these
8634 two modes. You can toggle the editable state of the text widget at any
8635 time, and can insert text at any time.
8637 The text widget wraps lines of text that are too long to
8638 fit onto a single line of the display window. Its default behaviour is
8639 to break words across line breaks. This can be changed using the next
8643 void gtk_text_set_word_wrap( GtkText *text,
8647 Using this function allows us to specify that the text widget should
8648 wrap long lines on word boundaries. The <tt/word_wrap/ argument is a
8649 TRUE or FALSE value.
8651 <!-- ----------------------------------------------------------------- -->
8652 <sect1>Text Manipulation
8654 The current insertion point of a Text widget can be set using
8656 void gtk_text_set_point( GtkText *text,
8660 where <tt/index/ is the position to set the insertion point.
8662 Analogous to this is the function for getting the current insertion point:
8665 guint gtk_text_get_point( GtkText *text );
8668 A function that is useful in combination with the above two functions is
8671 guint gtk_text_get_length( GtkText *text );
8674 which returns the current length of the Text widget. The length is the
8675 number of characters that are within the text block of the widget,
8676 including characters such as carriage-return, which marks the end of lines.
8678 In order to insert text at the current insertion point of a Text
8679 widget, the function gtk_text_insert is used, which also allows us to
8680 specify background and foreground colors and a font for the text.
8683 void gtk_text_insert( GtkText *text,
8691 Passing a value of <tt/NULL/ in as the value for the foreground color,
8692 background colour or font will result in the values set within the widget
8693 style to be used. Using a value of <tt/-1/ for the length parameter will
8694 result in the whole of the text string given being inserted.
8696 The text widget is one of the few within GTK that redraws itself
8697 dynamically, outside of the gtk_main function. This means that all changes
8698 to the contents of the text widget take effect immediately. This may be
8699 undesirable when performing multiple changes to the text widget. In order
8700 to allow us to perform multiple updates to the text widget without it
8701 continuously redrawing, we can freeze the widget, which temporarily stops
8702 it from automatically redrawing itself every time it is changed. We can
8703 then thaw the widget after our updates are complete.
8705 The following two functions perform this freeze and thaw action:
8708 void gtk_text_freeze( GtkText *text );
8710 void gtk_text_thaw( GtkText *text );
8713 Text is deleted from the text widget relative to the current insertion
8714 point by the following two functions. The return value is a TRUE or
8715 FALSE indicator of whether the operation was successful.
8718 gint gtk_text_backward_delete( GtkText *text,
8721 gint gtk_text_forward_delete ( GtkText *text,
8725 If you want to retrieve the contents of the text widget, then the macro
8726 <tt/GTK_TEXT_INDEX(t, index)/ allows you to retrieve the character at
8727 position <tt/index/ within the text widget <tt/t/.
8729 To retrieve larger blocks of text, we can use the function
8732 gchar *gtk_editable_get_chars( GtkEditable *editable,
8737 This is a function of the parent class of the text widget. A value of -1 as
8738 <tt/end_pos/ signifies the end of the text. The index of the text starts at 0.
8740 The function allocates a new chunk of memory for the text block, so don't forget
8741 to free it with a call to g_free when you have finished with it.
8743 <!-- ----------------------------------------------------------------- -->
8744 <sect1>Keyboard Shortcuts
8746 The text widget has a number of pre-installed keyboard shortcuts for common
8747 editing, motion and selection functions. These are accessed using Control
8748 and Alt key combinations.
8750 In addition to these, holding down the Control key whilst using cursor key
8751 movement will move the cursor by words rather than characters. Holding down
8752 Shift whilst using cursor movement will extend the selection.
8754 <sect2>Motion Shortcuts
8757 <item> Ctrl-A Beginning of line
8758 <item> Ctrl-E End of line
8759 <item> Ctrl-N Next Line
8760 <item> Ctrl-P Previous Line
8761 <item> Ctrl-B Backward one character
8762 <item> Ctrl-F Forward one character
8763 <item> Alt-B Backward one word
8764 <item> Alt-F Forward one word
8767 <sect2>Editing Shortcuts
8770 <item> Ctrl-H Delete Backward Character (Backspace)
8771 <item> Ctrl-D Delete Forward Character (Delete)
8772 <item> Ctrl-W Delete Backward Word
8773 <item> Alt-D Delete Forward Word
8774 <item> Ctrl-K Delete to end of line
8775 <item> Ctrl-U Delete line
8778 <sect2>Selection Shortcuts
8781 <item> Ctrl-X Cut to clipboard
8782 <item> Ctrl-C Copy to clipboard
8783 <item> Ctrl-V Paste from clipboard
8786 <!-- ----------------------------------------------------------------- -->
8787 <sect1>A GtkText Example
8790 /* example-start text text.c */
8795 #include <gtk/gtk.h>
8797 void text_toggle_editable (GtkWidget *checkbutton,
8800 gtk_text_set_editable(GTK_TEXT(text),
8801 GTK_TOGGLE_BUTTON(checkbutton)->active);
8804 void text_toggle_word_wrap (GtkWidget *checkbutton,
8807 gtk_text_set_word_wrap(GTK_TEXT(text),
8808 GTK_TOGGLE_BUTTON(checkbutton)->active);
8811 void close_application( GtkWidget *widget, gpointer data )
8816 int main (int argc, char *argv[])
8824 GtkWidget *separator;
8826 GtkWidget *vscrollbar;
8830 GdkFont *fixed_font;
8834 gtk_init (&argc, &argv);
8836 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
8837 gtk_widget_set_usize (window, 600, 500);
8838 gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, FALSE);
8839 gtk_signal_connect (GTK_OBJECT (window), "destroy",
8840 GTK_SIGNAL_FUNC(close_application),
8842 gtk_window_set_title (GTK_WINDOW (window), "Text Widget Example");
8843 gtk_container_border_width (GTK_CONTAINER (window), 0);
8846 box1 = gtk_vbox_new (FALSE, 0);
8847 gtk_container_add (GTK_CONTAINER (window), box1);
8848 gtk_widget_show (box1);
8851 box2 = gtk_vbox_new (FALSE, 10);
8852 gtk_container_border_width (GTK_CONTAINER (box2), 10);
8853 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
8854 gtk_widget_show (box2);
8857 table = gtk_table_new (2, 2, FALSE);
8858 gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
8859 gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
8860 gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
8861 gtk_widget_show (table);
8863 /* Create the GtkText widget */
8864 text = gtk_text_new (NULL, NULL);
8865 gtk_text_set_editable (GTK_TEXT (text), TRUE);
8866 gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
8867 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
8868 GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
8869 gtk_widget_show (text);
8871 /* Add a vertical scrollbar to the GtkText widget */
8872 vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
8873 gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
8874 GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
8875 gtk_widget_show (vscrollbar);
8877 /* Get the system colour map and allocate the colour red */
8878 cmap = gdk_colormap_get_system();
8879 colour.red = 0xffff;
8882 if (!gdk_color_alloc(cmap, &colour)) {
8883 g_error("couldn't allocate colour");
8886 /* Load a fixed font */
8887 fixed_font = gdk_font_load ("-misc-fixed-medium-r-*-*-*-140-*-*-*-*-*-*");
8889 /* Realizing a widget creates a window for it, ready for us to insert some text */
8890 gtk_widget_realize (text);
8892 /* Freeze the text widget, ready for multiple updates */
8893 gtk_text_freeze (GTK_TEXT (text));
8895 /* Insert some coloured text */
8896 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
8898 gtk_text_insert (GTK_TEXT (text), NULL, &colour, NULL,
8900 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
8901 "text and different ", -1);
8902 gtk_text_insert (GTK_TEXT (text), fixed_font, &text->style->black, NULL,
8905 /* Load the file text.c into the text window */
8907 infile = fopen("text.c", "r");
8915 nchars = fread(buffer, 1, 1024, infile);
8916 gtk_text_insert (GTK_TEXT (text), fixed_font, NULL,
8917 NULL, buffer, nchars);
8926 /* Thaw the text widget, allowing the updates to become visible */
8927 gtk_text_thaw (GTK_TEXT (text));
8929 hbox = gtk_hbutton_box_new ();
8930 gtk_box_pack_start (GTK_BOX (box2), hbox, FALSE, FALSE, 0);
8931 gtk_widget_show (hbox);
8933 check = gtk_check_button_new_with_label("Editable");
8934 gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, FALSE, 0);
8935 gtk_signal_connect (GTK_OBJECT(check), "toggled",
8936 GTK_SIGNAL_FUNC(text_toggle_editable), text);
8937 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
8938 gtk_widget_show (check);
8939 check = gtk_check_button_new_with_label("Wrap Words");
8940 gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, TRUE, 0);
8941 gtk_signal_connect (GTK_OBJECT(check), "toggled",
8942 GTK_SIGNAL_FUNC(text_toggle_word_wrap), text);
8943 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), FALSE);
8944 gtk_widget_show (check);
8946 separator = gtk_hseparator_new ();
8947 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
8948 gtk_widget_show (separator);
8950 box2 = gtk_vbox_new (FALSE, 10);
8951 gtk_container_border_width (GTK_CONTAINER (box2), 10);
8952 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
8953 gtk_widget_show (box2);
8955 button = gtk_button_new_with_label ("close");
8956 gtk_signal_connect (GTK_OBJECT (button), "clicked",
8957 GTK_SIGNAL_FUNC(close_application),
8959 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
8960 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
8961 gtk_widget_grab_default (button);
8962 gtk_widget_show (button);
8964 gtk_widget_show (window);
8974 <!-- ***************************************************************** -->
8975 <sect> Undocumented Widgets
8976 <!-- ***************************************************************** -->
8978 These all require authors! :) Please consider contributing to our tutorial.
8980 If you must use one of these widgets that are undocumented, I strongly
8981 suggest you take a look at their respective header files in the GTK
8982 distribution. GTK's function names are very descriptive. Once you have an
8983 understanding of how things work, it's not difficult to figure out how to
8984 use a widget simply by looking at its function declarations. This, along
8985 with a few examples from others' code, and it should be no problem.
8987 When you do come to understand all the functions of a new undocumented
8988 widget, please consider writing a tutorial on it so others may benefit
8991 <!-- ----------------------------------------------------------------- -->
8992 <sect1> Fixed Container
8994 <!-- ----------------------------------------------------------------- -->
8997 <!-- ----------------------------------------------------------------- -->
9001 (This may need to be rewritten to follow the style of the rest of the tutorial)
9005 Previews serve a number of purposes in GIMP/GTK. The most important one is
9006 this. High quality images may take up to tens of megabytes of memory - easy!
9007 Any operation on an image that big is bound to take a long time. If it takes
9008 you 5-10 trial-and-errors (i.e. 10-20 steps, since you have to revert after
9009 you make an error) to choose the desired modification, it make take you
9010 literally hours to make the right one - if you don't run out of memory
9011 first. People who have spent hours in color darkrooms know the feeling.
9012 Previews to the rescue!
9014 But the annoyance of the delay is not the only issue. Oftentimes it is
9015 helpful to compare the Before and After versions side-by-side or at least
9016 back-to-back. If you're working with big images and 10 second delays,
9017 obtaining the Before and After impressions is, to say the least, difficult.
9018 For 30M images (4"x6", 600dpi, 24 bit) the side-by-side comparison is right
9019 out for most people, while back-to-back is more like back-to-1001, 1002,
9020 ..., 1010-back! Previews to the rescue!
9022 But there's more. Previews allow for side-by-side pre-previews. In other
9023 words, you write a plug-in (e.g. the filterpack simulation) which would have
9024 a number of here's-what-it-would-look-like-if-you-were-to-do-this previews.
9025 An approach like this acts as a sort of a preview palette and is very
9026 effective for subtle changes. Let's go previews!
9028 There's more. For certain plug-ins real-time image-specific human
9029 intervention maybe necessary. In the SuperNova plug-in, for example, the
9030 user is asked to enter the coordinates of the center of the future
9031 supernova. The easiest way to do this, really, is to present the user with a
9032 preview and ask him to interactively select the spot. Let's go previews!
9034 Finally, a couple of misc uses. One can use previews even when not working
9035 with big images. For example, they are useful when rendering complicated
9036 patterns. (Just check out the venerable Diffraction plug-in + many other
9037 ones!) As another example, take a look at the colormap rotation plug-in
9038 (work in progress). You can also use previews for little logos inside you
9039 plug-ins and even for an image of yourself, The Author. Let's go previews!
9041 When Not to Use Previews
9043 Don't use previews for graphs, drawing etc. GDK is much faster for that. Use
9044 previews only for rendered images!
9048 You can stick a preview into just about anything. In a vbox, an hbox, a
9049 table, a button, etc. But they look their best in tight frames around them.
9050 Previews by themselves do not have borders and look flat without them. (Of
9051 course, if the flat look is what you want...) Tight frames provide the
9056 Previews in many ways are like any other widgets in GTK (whatever that
9057 means) except they possess an additional feature: they need to be filled with
9058 some sort of an image! First, we will deal exclusively with the GTK aspect
9059 of previews and then we'll discuss how to fill them.
9065 /* Create a preview widget,
9066 set its size, an show it */
9068 preview=gtk_preview_new(GTK_PREVIEW_COLOR)
9070 GTK_PREVIEW_GRAYSCALE);*/
9071 gtk_preview_size (GTK_PREVIEW (preview), WIDTH, HEIGHT);
9072 gtk_widget_show(preview);
9073 my_preview_rendering_function(preview);
9075 Oh yeah, like I said, previews look good inside frames, so how about:
9077 GtkWidget *create_a_preview(int Width,
9084 frame = gtk_frame_new(NULL);
9085 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
9086 gtk_container_border_width (GTK_CONTAINER(frame),0);
9087 gtk_widget_show(frame);
9089 preview=gtk_preview_new (Colorfulness?GTK_PREVIEW_COLOR
9090 :GTK_PREVIEW_GRAYSCALE);
9091 gtk_preview_size (GTK_PREVIEW (preview), Width, Height);
9092 gtk_container_add(GTK_CONTAINER(frame),preview);
9093 gtk_widget_show(preview);
9095 my_preview_rendering_function(preview);
9099 That's my basic preview. This routine returns the "parent" frame so you can
9100 place it somewhere else in your interface. Of course, you can pass the
9101 parent frame to this routine as a parameter. In many situations, however,
9102 the contents of the preview are changed continually by your application. In
9103 this case you may want to pass a pointer to the preview to a
9104 "create_a_preview()" and thus have control of it later.
9106 One more important note that may one day save you a lot of time. Sometimes
9107 it is desirable to label you preview. For example, you may label the preview
9108 containing the original image as "Original" and the one containing the
9109 modified image as "Less Original". It might occur to you to pack the
9110 preview along with the appropriate label into a vbox. The unexpected caveat
9111 is that if the label is wider than the preview (which may happen for a
9112 variety of reasons unforseeable to you, from the dynamic decision on the
9113 size of the preview to the size of the font) the frame expands and no longer
9114 fits tightly over the preview. The same problem can probably arise in other
9119 The solution is to place the preview and the label into a 2x1 table and by
9120 attaching them with the following parameters (this is one possible variations
9121 of course. The key is no GTK_FILL in the second attachment):
9123 gtk_table_attach(GTK_TABLE(table),label,0,1,0,1,
9125 GTK_EXPAND|GTK_FILL,
9127 gtk_table_attach(GTK_TABLE(table),frame,0,1,1,2,
9133 And here's the result:
9139 Making a preview clickable is achieved most easily by placing it in a
9140 button. It also adds a nice border around the preview and you may not even
9141 need to place it in a frame. See the Filter Pack Simulation plug-in for an
9144 This is pretty much it as far as GTK is concerned.
9146 Filling In a Preview
9148 In order to familiarize ourselves with the basics of filling in previews,
9149 let's create the following pattern (contrived by trial and error):
9154 my_preview_rendering_function(GtkWidget *preview)
9157 #define HALF (SIZE/2)
9159 guchar *row=(guchar *) malloc(3*SIZE); /* 3 bits per dot */
9160 gint i, j; /* Coordinates */
9161 double r, alpha, x, y;
9163 if (preview==NULL) return; /* I usually add this when I want */
9164 /* to avoid silly crashes. You */
9165 /* should probably make sure that */
9166 /* everything has been nicely */
9168 for (j=0; j < ABS(cos(2*alpha)) ) { /* Are we inside the shape? */
9169 /* glib.h contains ABS(x). */
9170 row[i*3+0] = sqrt(1-r)*255; /* Define Red */
9171 row[i*3+1] = 128; /* Define Green */
9172 row[i*3+2] = 224; /* Define Blue */
9173 } /* "+0" is for alignment! */
9176 row[i*3+1] = ABS(sin((float)i/SIZE*2*PI))*255;
9177 row[i*3+2] = ABS(sin((float)j/SIZE*2*PI))*255;
9180 gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,j,SIZE);
9181 /* Insert "row" into "preview" starting at the point with */
9182 /* coordinates (0,j) first column, j_th row extending SIZE */
9183 /* pixels to the right */
9186 free(row); /* save some space */
9187 gtk_widget_draw(preview,NULL); /* what does this do? */
9188 gdk_flush(); /* or this? */
9191 Non-GIMP users can have probably seen enough to do a lot of things already.
9192 For the GIMP users I have a few pointers to add.
9196 It is probably wise to keep a reduced version of the image around with just
9197 enough pixels to fill the preview. This is done by selecting every n'th
9198 pixel where n is the ratio of the size of the image to the size of the
9199 preview. All further operations (including filling in the previews) are then
9200 performed on the reduced number of pixels only. The following is my
9201 implementation of reducing the image. (Keep in mind that I've had only basic
9204 (UNTESTED CODE ALERT!!!)
9216 SELECTION_IN_CONTEXT,
9220 ReducedImage *Reduce_The_Image(GDrawable *drawable,
9225 /* This function reduced the image down to the the selected preview size */
9226 /* The preview size is determine by LongerSize, i.e. the greater of the */
9227 /* two dimensions. Works for RGB images only! */
9228 gint RH, RW; /* Reduced height and reduced width */
9229 gint width, height; /* Width and Height of the area being reduced */
9230 gint bytes=drawable->bpp;
9231 ReducedImage *temp=(ReducedImage *)malloc(sizeof(ReducedImage));
9233 guchar *tempRGB, *src_row, *tempmask, *src_mask_row,R,G,B;
9234 gint i, j, whichcol, whichrow, x1, x2, y1, y2;
9235 GPixelRgn srcPR, srcMask;
9236 gint NoSelectionMade=TRUE; /* Assume that we're dealing with the entire */
9239 gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
9242 /* If there's a SELECTION, we got its bounds!)
9244 if (width != drawable->width && height != drawable->height)
9245 NoSelectionMade=FALSE;
9246 /* Become aware of whether the user has made an active selection */
9247 /* This will become important later, when creating a reduced mask. */
9249 /* If we want to preview the entire image, overrule the above! */
9250 /* Of course, if no selection has been made, this does nothing! */
9251 if (Selection==ENTIRE_IMAGE) {
9255 y2=drawable->height;
9258 /* If we want to preview a selection with some surrounding area we */
9259 /* have to expand it a little bit. Consider it a bit of a riddle. */
9260 if (Selection==SELECTION_IN_CONTEXT) {
9261 x1=MAX(0, x1-width/2.0);
9262 x2=MIN(drawable->width, x2+width/2.0);
9263 y1=MAX(0, y1-height/2.0);
9264 y2=MIN(drawable->height, y2+height/2.0);
9267 /* How we can determine the width and the height of the area being */
9272 /* The lines below determine which dimension is to be the longer */
9273 /* side. The idea borrowed from the supernova plug-in. I suspect I */
9274 /* could've thought of it myself, but the truth must be told. */
9275 /* Plagiarism stinks! */
9278 RH=(float) height * (float) LongerSize/ (float) width;
9282 RW=(float)width * (float) LongerSize/ (float) height;
9285 /* The entire image is stretched into a string! */
9286 tempRGB = (guchar *) malloc(RW*RH*bytes);
9287 tempmask = (guchar *) malloc(RW*RH);
9289 gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height, FALSE, FALSE);
9290 gimp_pixel_rgn_init (&srcMask, mask, x1, y1, width, height, FALSE, FALSE);
9292 /* Grab enough to save a row of image and a row of mask. */
9293 src_row = (guchar *) malloc (width*bytes);
9294 src_mask_row = (guchar *) malloc (width);
9296 for (i=0; i < RH; i++) {
9297 whichrow=(float)i*(float)height/(float)RH;
9298 gimp_pixel_rgn_get_row (&srcPR, src_row, x1, y1+whichrow, width);
9299 gimp_pixel_rgn_get_row (&srcMask, src_mask_row, x1, y1+whichrow, width);
9301 for (j=0; j < RW; j++) {
9302 whichcol=(float)j*(float)width/(float)RW;
9304 /* No selection made = each point is completely selected! */
9305 if (NoSelectionMade)
9306 tempmask[i*RW+j]=255;
9308 tempmask[i*RW+j]=src_mask_row[whichcol];
9310 /* Add the row to the one long string which now contains the image! */
9311 tempRGB[i*RW*bytes+j*bytes+0]=src_row[whichcol*bytes+0];
9312 tempRGB[i*RW*bytes+j*bytes+1]=src_row[whichcol*bytes+1];
9313 tempRGB[i*RW*bytes+j*bytes+2]=src_row[whichcol*bytes+2];
9315 /* Hold on to the alpha as well */
9317 tempRGB[i*RW*bytes+j*bytes+3]=src_row[whichcol*bytes+3];
9324 temp->mask=tempmask;
9328 The following is a preview function which used the same ReducedImage type!
9329 Note that it uses fakes transparency (if one is present by means of
9330 fake_transparency which is defined as follows:
9332 gint fake_transparency(gint i, gint j)
9334 if ( ((i%20)- 10) * ((j%20)- 10)>0 )
9340 Now here's the preview function:
9343 my_preview_render_function(GtkWidget *preview,
9347 gint Inten, bytes=drawable->bpp;
9350 gint RW=reduced->width;
9351 gint RH=reduced->height;
9352 guchar *row=malloc(bytes*RW);;
9355 for (i=0; i < RH; i++) {
9356 for (j=0; j < RW; j++) {
9358 row[j*3+0] = reduced->rgb[i*RW*bytes + j*bytes + 0];
9359 row[j*3+1] = reduced->rgb[i*RW*bytes + j*bytes + 1];
9360 row[j*3+2] = reduced->rgb[i*RW*bytes + j*bytes + 2];
9363 for (k=0; k<3; k++) {
9364 float transp=reduced->rgb[i*RW*bytes+j*bytes+3]/255.0;
9365 row[3*j+k]=transp*a[3*j+k]+(1-transp)*fake_transparency(i,j);
9368 gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,i,RW);
9372 gtk_widget_draw(preview,NULL);
9378 guint gtk_preview_get_type (void);
9380 void gtk_preview_uninit (void);
9382 GtkWidget* gtk_preview_new (GtkPreviewType type);
9383 /* Described above */
9384 void gtk_preview_size (GtkPreview *preview,
9387 /* Allows you to resize an existing preview. */
9388 /* Apparently there's a bug in GTK which makes */
9389 /* this process messy. A way to clean up a mess */
9390 /* is to manually resize the window containing */
9391 /* the preview after resizing the preview. */
9393 void gtk_preview_put (GtkPreview *preview,
9404 void gtk_preview_put_row (GtkPreview *preview,
9412 void gtk_preview_draw_row (GtkPreview *preview,
9417 /* Described in the text */
9419 void gtk_preview_set_expand (GtkPreview *preview,
9423 /* No clue for any of the below but */
9424 /* should be standard for most widgets */
9425 void gtk_preview_set_gamma (double gamma);
9426 void gtk_preview_set_color_cube (guint nred_shades,
9427 guint ngreen_shades,
9429 guint ngray_shades);
9430 void gtk_preview_set_install_cmap (gint install_cmap);
9431 void gtk_preview_set_reserved (gint nreserved);
9432 GdkVisual* gtk_preview_get_visual (void);
9433 GdkColormap* gtk_preview_get_cmap (void);
9434 GtkPreviewInfo* gtk_preview_get_info (void);
9440 <!-- ***************************************************************** -->
9441 <sect>The EventBox Widget<label id="sec_EventBox">
9442 <!-- ***************************************************************** -->
9444 Some gtk widgets don't have associated X windows, so they just draw on
9445 their parents. Because of this, they cannot receive events
9446 and if they are incorrectly sized, they don't clip so you can get
9447 messy overwriting etc. If you require more from these widgets, the
9448 EventBox is for you.
9450 At first glance, the EventBox widget might appear to be totally
9451 useless. It draws nothing on the screen and responds to no
9452 events. However, it does serve a function - it provides an X window for
9453 its child widget. This is important as many GTK widgets do not
9454 have an associated X window. Not having an X window saves memory and
9455 improves performance, but also has some drawbacks. A widget without an
9456 X window cannot receive events, and does not perform any clipping on
9457 its contents. Although the name <em/EventBox/ emphasizes the
9458 event-handling function, the widget can also be used for clipping.
9459 (And more ... see the example below.)
9461 To create a new EventBox widget, use:
9464 GtkWidget *gtk_event_box_new( void );
9467 A child widget can then be added to this EventBox:
9470 gtk_container_add( GTK_CONTAINER(event_box), widget );
9473 The following example demonstrates both uses of an EventBox - a label
9474 is created that is clipped to a small box, and set up so that a
9475 mouse-click on the label causes the program to exit.
9478 /* example-start eventbox eventbox.c */
9480 #include <gtk/gtk.h>
9483 main (int argc, char *argv[])
9486 GtkWidget *event_box;
9489 gtk_init (&argc, &argv);
9491 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9493 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
9495 gtk_signal_connect (GTK_OBJECT (window), "destroy",
9496 GTK_SIGNAL_FUNC (gtk_exit), NULL);
9498 gtk_container_border_width (GTK_CONTAINER (window), 10);
9500 /* Create an EventBox and add it to our toplevel window */
9502 event_box = gtk_event_box_new ();
9503 gtk_container_add (GTK_CONTAINER(window), event_box);
9504 gtk_widget_show (event_box);
9506 /* Create a long label */
9508 label = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
9509 gtk_container_add (GTK_CONTAINER (event_box), label);
9510 gtk_widget_show (label);
9512 /* Clip it short. */
9513 gtk_widget_set_usize (label, 110, 20);
9515 /* And bind an action to it */
9516 gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
9517 gtk_signal_connect (GTK_OBJECT(event_box), "button_press_event",
9518 GTK_SIGNAL_FUNC (gtk_exit), NULL);
9520 /* Yet one more thing you need an X window for ... */
9522 gtk_widget_realize (event_box);
9523 gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1));
9525 gtk_widget_show (window);
9534 <!-- ***************************************************************** -->
9535 <sect>Setting Widget Attributes<label id="sec_setting_widget_attributes">
9536 <!-- ***************************************************************** -->
9538 This describes the functions used to operate on widgets. These can be used
9539 to set style, padding, size etc.
9541 (Maybe I should make a whole section on accelerators.)
9544 void gtk_widget_install_accelerator( GtkWidget *widget,
9545 GtkAcceleratorTable *table,
9550 void gtk_widget_remove_accelerator ( GtkWidget *widget,
9551 GtkAcceleratorTable *table,
9552 gchar *signal_name);
9554 void gtk_widget_activate( GtkWidget *widget );
9556 void gtk_widget_set_name( GtkWidget *widget,
9559 gchar *gtk_widget_get_name( GtkWidget *widget );
9561 void gtk_widget_set_sensitive( GtkWidget *widget,
9564 void gtk_widget_set_style( GtkWidget *widget,
9567 GtkStyle *gtk_widget_get_style( GtkWidget *widget );
9569 GtkStyle *gtk_widget_get_default_style( void );
9571 void gtk_widget_set_uposition( GtkWidget *widget,
9575 void gtk_widget_set_usize( GtkWidget *widget,
9579 void gtk_widget_grab_focus( GtkWidget *widget );
9581 void gtk_widget_show( GtkWidget *widget );
9583 void gtk_widget_hide( GtkWidget *widget );
9586 <!-- ***************************************************************** -->
9587 <sect>Timeouts, IO and Idle Functions<label id="sec_timeouts">
9588 <!-- ***************************************************************** -->
9590 <!-- ----------------------------------------------------------------- -->
9593 You may be wondering how you make GTK do useful work when in gtk_main.
9594 Well, you have several options. Using the following functions you can
9595 create a timeout function that will be called every "interval"
9599 gint gtk_timeout_add( guint32 interval,
9600 GtkFunction function,
9604 The first argument is the number of milliseconds between calls to your
9605 function. The second argument is the function you wish to have called, and
9606 the third, the data passed to this callback function. The return value is
9607 an integer "tag" which may be used to stop the timeout by calling:
9610 void gtk_timeout_remove( gint tag );
9613 You may also stop the timeout function by returning zero or FALSE from
9614 your callback function. Obviously this means if you want your function to
9615 continue to be called, it should return a non-zero value, i.e. TRUE.
9617 The declaration of your callback should look something like this:
9620 gint timeout_callback( gpointer data );
9623 <!-- ----------------------------------------------------------------- -->
9624 <sect1>Monitoring IO
9626 Another nifty feature of GTK, is the ability to have it check for data on a
9627 file descriptor for you (as returned by open(2) or socket(2)). This is
9628 especially useful for networking applications. The function:
9631 gint gdk_input_add( gint source,
9632 GdkInputCondition condition,
9633 GdkInputFunction function,
9637 Where the first argument is the file descriptor you wish to have watched,
9638 and the second specifies what you want GDK to look for. This may be one of:
9641 <item>GDK_INPUT_READ - Call your function when there is data ready for
9642 reading on your file descriptor.
9644 <item>GDK_INPUT_WRITE - Call your function when the file descriptor is
9648 As I'm sure you've figured out already, the third argument is the function
9649 you wish to have called when the above conditions are satisfied, and the
9650 fourth is the data to pass to this function.
9652 The return value is a tag that may be used to stop GDK from monitoring this
9653 file descriptor using the following function.
9656 void gdk_input_remove( gint tag );
9659 The callback function should be declared as:
9662 void input_callback( gpointer data,
9664 GdkInputCondition condition );
9667 Where <tt/source/ and <tt/condition/ are as specified above.
9669 <!-- ----------------------------------------------------------------- -->
9670 <sect1>Idle Functions
9672 <!-- Need to check on idle priorities - TRG -->
9673 What if you have a function you want called when nothing else is
9677 gint gtk_idle_add( GtkFunction function,
9681 This causes GTK to call the specified function whenever nothing else is
9685 void gtk_idle_remove( gint tag );
9688 I won't explain the meaning of the arguments as they follow very much like
9689 the ones above. The function pointed to by the first argument to
9690 gtk_idle_add will be called whenever the opportunity arises. As with the
9691 others, returning FALSE will stop the idle function from being called.
9693 <!-- ***************************************************************** -->
9694 <sect>Advanced Event and Signal Handling<label id="sec_Adv_Events_and_Signals">
9695 <!-- ***************************************************************** -->
9697 <!-- ----------------------------------------------------------------- -->
9698 <sect1>Signal Functions
9700 <!-- ----------------------------------------------------------------- -->
9701 <sect2>Connecting and Disconnecting Signal Handlers
9705 guint gtk_signal_connect( GtkObject *object,
9708 gpointer func_data );
9710 guint gtk_signal_connect_after( GtkObject *object,
9713 gpointer func_data );
9715 guint gtk_signal_connect_object( GtkObject *object,
9718 GtkObject *slot_object );
9720 guint gtk_signal_connect_object_after( GtkObject *object,
9723 GtkObject *slot_object );
9725 guint gtk_signal_connect_full( GtkObject *object,
9728 GtkCallbackMarshal marshal,
9730 GtkDestroyNotify destroy_func,
9734 guint gtk_signal_connect_interp( GtkObject *object,
9736 GtkCallbackMarshal func,
9738 GtkDestroyNotify destroy_func,
9741 void gtk_signal_connect_object_while_alive( GtkObject *object,
9742 const gchar *signal,
9744 GtkObject *alive_object );
9746 void gtk_signal_connect_while_alive( GtkObject *object,
9747 const gchar *signal,
9750 GtkObject *alive_object );
9752 void gtk_signal_disconnect( GtkObject *object,
9755 void gtk_signal_disconnect_by_func( GtkObject *object,
9760 <!-- ----------------------------------------------------------------- -->
9761 <sect2>Blocking and Unblocking Signal Handlers
9764 void gtk_signal_handler_block( GtkObject *object,
9767 void gtk_signal_handler_block_by_func( GtkObject *object,
9771 void gtk_signal_handler_block_by_data( GtkObject *object,
9774 void gtk_signal_handler_unblock( GtkObject *object,
9777 void gtk_signal_handler_unblock_by_func( GtkObject *object,
9781 void gtk_signal_handler_unblock_by_data( GtkObject *object,
9785 <!-- ----------------------------------------------------------------- -->
9786 <sect2>Emitting and Stopping Signals
9789 void gtk_signal_emit( GtkObject *object,
9793 void gtk_signal_emit_by_name( GtkObject *object,
9797 void gtk_signal_emitv( GtkObject *object,
9801 void gtk_signal_emitv_by_name( GtkObject *object,
9805 guint gtk_signal_n_emissions( GtkObject *object,
9808 guint gtk_signal_n_emissions_by_name( GtkObject *object,
9809 const gchar *name );
9811 void gtk_signal_emit_stop( GtkObject *object,
9814 void gtk_signal_emit_stop_by_name( GtkObject *object,
9815 const gchar *name );
9818 <!-- ----------------------------------------------------------------- -->
9819 <sect1>Signal Emission and Propagation
9821 Signal emission is the process wherby GTK+ runs all handlers for a
9822 specific object and signal.
9824 First, note that the return value from a signal emission is the
9825 return value of the <em>last</em> handler executed. Since event signals
9826 are all of type GTK_RUN_LAST, this will be the default (GTK+ supplied)
9827 default handler, unless you connect with gtk_signal_connect_after().
9829 The way an event (say GTK_BUTTON_PRESS) is handled, is:
9831 <item>Start with the widget where the event occured.
9833 <item>Emit the generic "event" signal. If that signal handler returns
9834 a value of TRUE, stop all processing.
9836 <item>Otherwise, emit a specific, "button_press_event" signal. If that
9837 returns TRUE, stop all processing.
9839 <item>Otherwise, go to the widget's parent, and repeat the above steps.
9841 <item>Contimue until some signal handler returns TRUE, or until the
9842 top-level widget is reached.
9845 Some consequences of the above are:
9847 <item>Your handler's return value will have no effect if there is a
9848 default handler, unless you connect with gtk_signal_connect_after().
9850 <item>To prevent the default handler from being run, you need to connect
9851 with gtk_signal_connect() and use gtk_signal_emit_stop_by_name() - the
9852 return value only affects whether the signal is propagated, not the
9856 <!-- ***************************************************************** -->
9857 <sect>Managing Selections
9858 <!-- ***************************************************************** -->
9860 <!-- ----------------------------------------------------------------- -->
9863 One type of interprocess communication supported by GTK is
9864 <em>selections</em>. A selection identifies a chunk of data, for
9865 instance, a portion of text, selected by the user in some fashion, for
9866 instance, by dragging with the mouse. Only one application on a
9867 display, (the <em>owner</em> can own a particular selection at one
9868 time, so when a selection is claimed by one application, the previous
9869 owner must indicate to the user that selection has been
9870 relinquished. Other applications can request the contents of a
9871 selection in different forms, called <em>targets</em>. There can be
9872 any number of selections, but most X applications only handle one, the
9873 <em>primary selection</em>.
9875 In most cases, it isn't necessary for a GTK application to deal with
9876 selections itself. The standard widgets, such as the Entry widget,
9877 already have the capability to claim the selection when appropriate
9878 (e.g., when the user drags over text), and to retrieve the contents of
9879 the selection owned by another widget, or another application (e.g.,
9880 when the user clicks the second mouse button). However, there may be
9881 cases in which you want to give other widgets the ability to supply
9882 the selection, or you wish to retrieve targets not supported by
9885 A fundamental concept needed to understand selection handling is that
9886 of the <em>atom</em>. An atom is an integer that uniquely identifies a
9887 string (on a certain display). Certain atoms are predefined by the X
9888 server, and in some cases there are constants in <tt>gtk.h</tt>
9889 corresponding to these atoms. For instance the constant
9890 <tt>GDK_PRIMARY_SELECTION</tt> corresponds to the string "PRIMARY".
9891 In other cases, you should use the functions
9892 <tt>gdk_atom_intern()</tt>, to get the atom corresponding to a string,
9893 and <tt>gdk_atom_name()</tt>, to get the name of an atom. Both
9894 selections and targets are identified by atoms.
9896 <!-- ----------------------------------------------------------------- -->
9897 <sect1> Retrieving the selection
9899 Retrieving the selection is an asynchronous process. To start the
9903 gint gtk_selection_convert( GtkWidget *widget,
9909 This <em>converts</em> the selection into the form specified by
9910 <tt/target/. If at all possible, the time field should be the time
9911 from the event that triggered the selection. This helps make sure that
9912 events occur in the order that the user requested them. However, if it
9913 is not available (for instance, if the conversion was triggered by
9914 a "clicked" signal), then you can use the constant
9915 <tt>GDK_CURRENT_TIME</tt>.
9917 When the selection owner responds to the request, a
9918 "selection_received" signal is sent to your application. The handler
9919 for this signal receives a pointer to a <tt>GtkSelectionData</tt>
9920 structure, which is defined as:
9923 struct _GtkSelectionData
9934 <tt>selection</tt> and <tt>target</tt> are the values you gave in your
9935 <tt>gtk_selection_convert()</tt> call. <tt>type</tt> is an atom that
9936 identifies the type of data returned by the selection owner. Some
9937 possible values are "STRING", a string of latin-1 characters, "ATOM",
9938 a series of atoms, "INTEGER", an integer, etc. Most targets can only
9939 return one type. <tt/format/ gives the length of the units (for
9940 instance characters) in bits. Usually, you don't care about this when
9941 receiving data. <tt>data</tt> is a pointer to the returned data, and
9942 <tt>length</tt> gives the length of the returned data, in bytes. If
9943 <tt>length</tt> is negative, then an error occurred and the selection
9944 could not be retrieved. This might happen if no application owned the
9945 selection, or if you requested a target that the application didn't
9946 support. The buffer is actually guaranteed to be one byte longer than
9947 <tt>length</tt>; the extra byte will always be zero, so it isn't
9948 necessary to make a copy of strings just to null terminate them.
9950 In the following example, we retrieve the special target "TARGETS",
9951 which is a list of all targets into which the selection can be
9955 /* example-start selection gettargets.c */
9957 #include <gtk/gtk.h>
9959 void selection_received (GtkWidget *widget,
9960 GtkSelectionData *selection_data,
9963 /* Signal handler invoked when user clicks on the "Get Targets" button */
9965 get_targets (GtkWidget *widget, gpointer data)
9967 static GdkAtom targets_atom = GDK_NONE;
9969 /* Get the atom corresponding to the string "TARGETS" */
9970 if (targets_atom == GDK_NONE)
9971 targets_atom = gdk_atom_intern ("TARGETS", FALSE);
9973 /* And request the "TARGETS" target for the primary selection */
9974 gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
9978 /* Signal handler called when the selections owner returns the data */
9980 selection_received (GtkWidget *widget, GtkSelectionData *selection_data,
9987 /* **** IMPORTANT **** Check to see if retrieval succeeded */
9988 if (selection_data->length < 0)
9990 g_print ("Selection retrieval failed\n");
9993 /* Make sure we got the data in the expected form */
9994 if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
9996 g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
10000 /* Print out the atoms we received */
10001 atoms = (GdkAtom *)selection_data->data;
10004 for (i=0; i<selection_data->length/sizeof(GdkAtom); i++)
10007 name = gdk_atom_name (atoms[i]);
10009 g_print ("%s\n",name);
10011 g_print ("(bad atom)\n");
10018 main (int argc, char *argv[])
10023 gtk_init (&argc, &argv);
10025 /* Create the toplevel window */
10027 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
10028 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
10029 gtk_container_border_width (GTK_CONTAINER (window), 10);
10031 gtk_signal_connect (GTK_OBJECT (window), "destroy",
10032 GTK_SIGNAL_FUNC (gtk_exit), NULL);
10034 /* Create a button the user can click to get targets */
10036 button = gtk_button_new_with_label ("Get Targets");
10037 gtk_container_add (GTK_CONTAINER (window), button);
10039 gtk_signal_connect (GTK_OBJECT(button), "clicked",
10040 GTK_SIGNAL_FUNC (get_targets), NULL);
10041 gtk_signal_connect (GTK_OBJECT(button), "selection_received",
10042 GTK_SIGNAL_FUNC (selection_received), NULL);
10044 gtk_widget_show (button);
10045 gtk_widget_show (window);
10054 <!-- ----------------------------------------------------------------- -->
10055 <sect1> Supplying the selection
10057 Supplying the selection is a bit more complicated. You must register
10058 handlers that will be called when your selection is requested. For
10059 each selection/target pair you will handle, you make a call to:
10062 void gtk_selection_add_handler( GtkWidget *widget,
10065 GtkSelectionFunction function,
10066 GtkRemoveFunction remove_func,
10070 <tt/widget/, <tt/selection/, and <tt/target/ identify the requests
10071 this handler will manage. <tt/remove_func/, if not
10072 NULL, will be called when the signal handler is removed. This is
10073 useful, for instance, for interpreted languages which need to
10074 keep track of a reference count for <tt/data/.
10076 The callback function has the signature:
10079 typedef void (*GtkSelectionFunction)( GtkWidget *widget,
10080 GtkSelectionData *selection_data,
10085 The GtkSelectionData is the same as above, but this time, we're
10086 responsible for filling in the fields <tt/type/, <tt/format/,
10087 <tt/data/, and <tt/length/. (The <tt/format/ field is actually
10088 important here - the X server uses it to figure out whether the data
10089 needs to be byte-swapped or not. Usually it will be 8 - <em/i.e./ a
10090 character - or 32 - <em/i.e./ a. integer.) This is done by calling the
10094 void gtk_selection_data_set( GtkSelectionData *selection_data,
10101 This function takes care of properly making a copy of the data so that
10102 you don't have to worry about keeping it around. (You should not fill
10103 in the fields of the GtkSelectionData structure by hand.)
10105 When prompted by the user, you claim ownership of the selection by
10109 gint gtk_selection_owner_set( GtkWidget *widget,
10114 If another application claims ownership of the selection, you will
10115 receive a "selection_clear_event".
10117 As an example of supplying the selection, the following program adds
10118 selection functionality to a toggle button. When the toggle button is
10119 depressed, the program claims the primary selection. The only target
10120 supported (aside from certain targets like "TARGETS" supplied by GTK
10121 itself), is the "STRING" target. When this target is requested, a
10122 string representation of the time is returned.
10125 /* example-start selection setselection.c */
10127 #include <gtk/gtk.h>
10130 /* Callback when the user toggles the selection */
10132 selection_toggled (GtkWidget *widget, gint *have_selection)
10134 if (GTK_TOGGLE_BUTTON(widget)->active)
10136 *have_selection = gtk_selection_owner_set (widget,
10137 GDK_SELECTION_PRIMARY,
10139 /* if claiming the selection failed, we return the button to
10141 if (!*have_selection)
10142 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
10146 if (*have_selection)
10148 /* Before clearing the selection by setting the owner to NULL,
10149 we check if we are the actual owner */
10150 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
10151 gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
10153 *have_selection = FALSE;
10158 /* Called when another application claims the selection */
10160 selection_clear (GtkWidget *widget, GdkEventSelection *event,
10161 gint *have_selection)
10163 *have_selection = FALSE;
10164 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
10169 /* Supplies the current time as the selection. */
10171 selection_handle (GtkWidget *widget,
10172 GtkSelectionData *selection_data,
10176 time_t current_time;
10178 current_time = time (NULL);
10179 timestr = asctime (localtime(&current_time));
10180 /* When we return a single string, it should not be null terminated.
10181 That will be done for us */
10183 gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
10184 8, timestr, strlen(timestr));
10188 main (int argc, char *argv[])
10192 GtkWidget *selection_button;
10194 static int have_selection = FALSE;
10196 gtk_init (&argc, &argv);
10198 /* Create the toplevel window */
10200 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
10201 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
10202 gtk_container_border_width (GTK_CONTAINER (window), 10);
10204 gtk_signal_connect (GTK_OBJECT (window), "destroy",
10205 GTK_SIGNAL_FUNC (gtk_exit), NULL);
10207 /* Create a toggle button to act as the selection */
10209 selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
10210 gtk_container_add (GTK_CONTAINER (window), selection_button);
10211 gtk_widget_show (selection_button);
10213 gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
10214 GTK_SIGNAL_FUNC (selection_toggled), &have_selection);
10215 gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
10216 GTK_SIGNAL_FUNC (selection_clear), &have_selection);
10218 gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
10219 GDK_SELECTION_TYPE_STRING,
10220 selection_handle, NULL);
10222 gtk_widget_show (selection_button);
10223 gtk_widget_show (window);
10233 <!-- ***************************************************************** -->
10234 <sect>glib<label id="sec_glib">
10235 <!-- ***************************************************************** -->
10237 glib provides many useful functions and definitions available for use
10238 when creating GDK and GTK applications. I will list them all here with
10239 a brief explanation. Many are duplicates of standard libc functions so
10240 I won't go into detail on those. This is mostly to be used as a reference,
10241 so you know what is available for use.
10243 <!-- ----------------------------------------------------------------- -->
10246 Definitions for the extremes of many of the standard types are:
10261 Also, the following typedefs. The ones left unspecified are dynamically set
10262 depending on the architecture. Remember to avoid counting on the size of a
10263 pointer if you want to be portable! E.g., a pointer on an Alpha is 8 bytes, but 4
10273 unsigned char guchar;
10274 unsigned short gushort;
10275 unsigned long gulong;
10276 unsigned int guint;
10280 long double gldouble;
10292 <!-- ----------------------------------------------------------------- -->
10293 <sect1>Doubly Linked Lists
10295 The following functions are used to create, manage, and destroy doubly
10296 linked lists. I assume you know what linked lists are, as it is beyond the scope
10297 of this document to explain them. Of course, it's not required that you
10298 know these for general use of GTK, but they are nice to know.
10301 GList *g_list_alloc( void );
10303 void g_list_free( GList *list );
10305 void g_list_free_1( GList *list );
10307 GList *g_list_append( GList *list,
10310 GList *g_list_prepend( GList *list,
10313 GList *g_list_insert( GList *list,
10317 GList *g_list_remove( GList *list,
10320 GList *g_list_remove_link( GList *list,
10323 GList *g_list_reverse( GList *list );
10325 GList *g_list_nth( GList *list,
10328 GList *g_list_find( GList *list,
10331 GList *g_list_last( GList *list );
10333 GList *g_list_first( GList *list );
10335 gint g_list_length( GList *list );
10337 void g_list_foreach( GList *list,
10339 gpointer user_data );
10342 <!-- ----------------------------------------------------------------- -->
10343 <sect1>Singly Linked Lists
10345 Many of the above functions for singly linked lists are identical to the
10346 above. Here is a complete list:
10348 GSList *g_slist_alloc( void );
10350 void g_slist_free( GSList *list );
10352 void g_slist_free_1( GSList *list );
10354 GSList *g_slist_append( GSList *list,
10357 GSList *g_slist_prepend( GSList *list,
10360 GSList *g_slist_insert( GSList *list,
10364 GSList *g_slist_remove( GSList *list,
10367 GSList *g_slist_remove_link( GSList *list,
10370 GSList *g_slist_reverse( GSList *list );
10372 GSList *g_slist_nth( GSList *list,
10375 GSList *g_slist_find( GSList *list,
10378 GSList *g_slist_last( GSList *list );
10380 gint g_slist_length( GSList *list );
10382 void g_slist_foreach( GSList *list,
10384 gpointer user_data );
10388 <!-- ----------------------------------------------------------------- -->
10389 <sect1>Memory Management
10392 gpointer g_malloc( gulong size );
10395 This is a replacement for malloc(). You do not need to check the return
10396 value as it is done for you in this function.
10399 gpointer g_malloc0( gulong size );
10402 Same as above, but zeroes the memory before returning a pointer to it.
10405 gpointer g_realloc( gpointer mem,
10409 Relocates "size" bytes of memory starting at "mem". Obviously, the
10410 memory should have been previously allocated.
10413 void g_free( gpointer mem );
10416 Frees memory. Easy one.
10419 void g_mem_profile( void );
10422 Dumps a profile of used memory, but requires that you add #define
10423 MEM_PROFILE to the top of glib/gmem.c and re-make and make install.
10426 void g_mem_check( gpointer mem );
10429 Checks that a memory location is valid. Requires you add #define
10430 MEM_CHECK to the top of gmem.c and re-make and make install.
10432 <!-- ----------------------------------------------------------------- -->
10438 GTimer *g_timer_new( void );
10440 void g_timer_destroy( GTimer *timer );
10442 void g_timer_start( GTimer *timer );
10444 void g_timer_stop( GTimer *timer );
10446 void g_timer_reset( GTimer *timer );
10448 gdouble g_timer_elapsed( GTimer *timer,
10449 gulong *microseconds );
10452 <!-- ----------------------------------------------------------------- -->
10453 <sect1>String Handling
10455 A whole mess of string handling functions. They all look very interesting, and
10456 probably better for many purposes than the standard C string functions, but
10457 require documentation.
10460 GString *g_string_new( gchar *init );
10462 void g_string_free( GString *string,
10463 gint free_segment );
10465 GString *g_string_assign( GString *lval,
10468 GString *g_string_truncate( GString *string,
10471 GString *g_string_append( GString *string,
10474 GString *g_string_append_c( GString *string,
10477 GString *g_string_prepend( GString *string,
10480 GString *g_string_prepend_c( GString *string,
10483 void g_string_sprintf( GString *string,
10487 void g_string_sprintfa ( GString *string,
10492 <!-- ----------------------------------------------------------------- -->
10493 <sect1>Utility and Error Functions
10496 gchar *g_strdup( const gchar *str );
10499 Replacement strdup function. Copies the original strings contents to
10500 newly allocated memory, and returns a pointer to it.
10503 gchar *g_strerror( gint errnum );
10506 I recommend using this for all error messages. It's much nicer, and more
10507 portable than perror() or others. The output is usually of the form:
10510 program name:function that failed:file or further description:strerror
10513 Here's an example of one such call used in our hello_world program:
10516 g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
10520 void g_error( gchar *format, ... );
10523 Prints an error message. The format is just like printf, but it
10524 prepends "** ERROR **: " to your message, and exits the program.
10525 Use only for fatal errors.
10528 void g_warning( gchar *format, ... );
10531 Same as above, but prepends "** WARNING **: ", and does not exit the
10535 void g_message( gchar *format, ... );
10538 Prints "message: " prepended to the string you pass in.
10541 void g_print( gchar *format, ... );
10544 Replacement for printf().
10546 And our last function:
10549 gchar *g_strsignal( gint signum );
10552 Prints out the name of the Unix system signal given the signal number.
10553 Useful in generic signal handling functions.
10555 All of the above are more or less just stolen from glib.h. If anyone cares
10556 to document any function, just send me an email!
10558 <!-- ***************************************************************** -->
10559 <sect>GTK's rc Files
10560 <!-- ***************************************************************** -->
10562 GTK has its own way of dealing with application defaults, by using rc
10563 files. These can be used to set the colors of just about any widget, and
10564 can also be used to tile pixmaps onto the background of some widgets.
10566 <!-- ----------------------------------------------------------------- -->
10567 <sect1>Functions For rc Files
10569 When your application starts, you should include a call to:
10572 void gtk_rc_parse( char *filename );
10575 Passing in the filename of your rc file. This will cause GTK to parse this
10576 file, and use the style settings for the widget types defined there.
10578 If you wish to have a special set of widgets that can take on a different
10579 style from others, or any other logical division of widgets, use a call to:
10582 void gtk_widget_set_name( GtkWidget *widget,
10586 Passing your newly created widget as the first argument, and the name
10587 you wish to give it as the second. This will allow you to change the
10588 attributes of this widget by name through the rc file.
10590 If we use a call something like this:
10593 button = gtk_button_new_with_label ("Special Button");
10594 gtk_widget_set_name (button, "special button");
10597 Then this button is given the name "special button" and may be addressed by
10598 name in the rc file as "special button.GtkButton". [<--- Verify ME!]
10600 The example rc file below, sets the properties of the main window, and lets
10601 all children of that main window inherit the style described by the "main
10602 button" style. The code used in the application is:
10605 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
10606 gtk_widget_set_name (window, "main window");
10609 And then the style is defined in the rc file using:
10612 widget "main window.*GtkButton*" style "main_button"
10615 Which sets all the GtkButton widgets in the "main window" to the
10616 "main_buttons" style as defined in the rc file.
10618 As you can see, this is a fairly powerful and flexible system. Use your
10619 imagination as to how best to take advantage of this.
10621 <!-- ----------------------------------------------------------------- -->
10622 <sect1>GTK's rc File Format
10624 The format of the GTK file is illustrated in the example below. This is
10625 the testgtkrc file from the GTK distribution, but I've added a
10626 few comments and things. You may wish to include this explanation
10627 your application to allow the user to fine tune his application.
10629 There are several directives to change the attributes of a widget.
10632 <item>fg - Sets the foreground color of a widget.
10633 <item>bg - Sets the background color of a widget.
10634 <item>bg_pixmap - Sets the background of a widget to a tiled pixmap.
10635 <item>font - Sets the font to be used with the given widget.
10638 In addition to this, there are several states a widget can be in, and you
10639 can set different colors, pixmaps and fonts for each state. These states are:
10642 <item>NORMAL - The normal state of a widget, without the mouse over top of
10643 it, and not being pressed etc.
10644 <item>PRELIGHT - When the mouse is over top of the widget, colors defined
10645 using this state will be in effect.
10646 <item>ACTIVE - When the widget is pressed or clicked it will be active, and
10647 the attributes assigned by this tag will be in effect.
10648 <item>INSENSITIVE - When a widget is set insensitive, and cannot be
10649 activated, it will take these attributes.
10650 <item>SELECTED - When an object is selected, it takes these attributes.
10653 When using the "fg" and "bg" keywords to set the colors of widgets, the
10657 fg[<STATE>] = { Red, Green, Blue }
10660 Where STATE is one of the above states (PRELIGHT, ACTIVE etc), and the Red,
10661 Green and Blue are values in the range of 0 - 1.0, { 1.0, 1.0, 1.0 } being
10662 white. They must be in float form, or they will register as 0, so a straight
10663 "1" will not work, it must be "1.0". A straight "0" is fine because it
10664 doesn't matter if it's not recognized. Unrecognized values are set to 0.
10666 bg_pixmap is very similar to the above, except the colors are replaced by a
10669 pixmap_path is a list of paths separated by ":"'s. These paths will be
10670 searched for any pixmap you specify.
10672 The font directive is simply:
10674 font = "<font name>"
10677 Where the only hard part is figuring out the font string. Using xfontsel or
10678 similar utility should help.
10680 The "widget_class" sets the style of a class of widgets. These classes are
10681 listed in the widget overview on the class hierarchy.
10683 The "widget" directive sets a specifically named set of widgets to a
10684 given style, overriding any style set for the given widget class.
10685 These widgets are registered inside the application using the
10686 gtk_widget_set_name() call. This allows you to specify the attributes of a
10687 widget on a per widget basis, rather than setting the attributes of an
10688 entire widget class. I urge you to document any of these special widgets so
10689 users may customize them.
10691 When the keyword <tt>parent</> is used as an attribute, the widget will take on
10692 the attributes of its parent in the application.
10694 When defining a style, you may assign the attributes of a previously defined
10695 style to this new one.
10698 style "main_button" = "button"
10700 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
10701 bg[PRELIGHT] = { 0.75, 0, 0 }
10705 This example takes the "button" style, and creates a new "main_button" style
10706 simply by changing the font and prelight background color of the "button"
10709 Of course, many of these attributes don't apply to all widgets. It's a
10710 simple matter of common sense really. Anything that could apply, should.
10712 <!-- ----------------------------------------------------------------- -->
10713 <sect1>Example rc file
10717 # pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
10719 pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
10721 # style <name> [= <name>]
10726 # widget <widget_set> style <style_name>
10727 # widget_class <widget_class_set> style <style_name>
10730 # Here is a list of all the possible states. Note that some do not apply to
10733 # NORMAL - The normal state of a widget, without the mouse over top of
10734 # it, and not being pressed etc.
10736 # PRELIGHT - When the mouse is over top of the widget, colors defined
10737 # using this state will be in effect.
10739 # ACTIVE - When the widget is pressed or clicked it will be active, and
10740 # the attributes assigned by this tag will be in effect.
10742 # INSENSITIVE - When a widget is set insensitive, and cannot be
10743 # activated, it will take these attributes.
10745 # SELECTED - When an object is selected, it takes these attributes.
10747 # Given these states, we can set the attributes of the widgets in each of
10748 # these states using the following directives.
10750 # fg - Sets the foreground color of a widget.
10751 # fg - Sets the background color of a widget.
10752 # bg_pixmap - Sets the background of a widget to a tiled pixmap.
10753 # font - Sets the font to be used with the given widget.
10756 # This sets a style called "button". The name is not really important, as
10757 # it is assigned to the actual widgets at the bottom of the file.
10761 #This sets the padding around the window to the pixmap specified.
10762 #bg_pixmap[<STATE>] = "<pixmap filename>"
10763 bg_pixmap[NORMAL] = "warning.xpm"
10768 #Sets the foreground color (font color) to red when in the "NORMAL"
10771 fg[NORMAL] = { 1.0, 0, 0 }
10773 #Sets the background pixmap of this widget to that of its parent.
10774 bg_pixmap[NORMAL] = "<parent>"
10779 # This shows all the possible states for a button. The only one that
10780 # doesn't apply is the SELECTED state.
10782 fg[PRELIGHT] = { 0, 1.0, 1.0 }
10783 bg[PRELIGHT] = { 0, 0, 1.0 }
10784 bg[ACTIVE] = { 1.0, 0, 0 }
10785 fg[ACTIVE] = { 0, 1.0, 0 }
10786 bg[NORMAL] = { 1.0, 1.0, 0 }
10787 fg[NORMAL] = { .99, 0, .99 }
10788 bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
10789 fg[INSENSITIVE] = { 1.0, 0, 1.0 }
10792 # In this example, we inherit the attributes of the "button" style and then
10793 # override the font and background color when prelit to create a new
10794 # "main_button" style.
10796 style "main_button" = "button"
10798 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
10799 bg[PRELIGHT] = { 0.75, 0, 0 }
10802 style "toggle_button" = "button"
10804 fg[NORMAL] = { 1.0, 0, 0 }
10805 fg[ACTIVE] = { 1.0, 0, 0 }
10807 # This sets the background pixmap of the toggle_button to that of its
10808 # parent widget (as defined in the application).
10809 bg_pixmap[NORMAL] = "<parent>"
10814 bg_pixmap[NORMAL] = "marble.xpm"
10815 fg[NORMAL] = { 1.0, 1.0, 1.0 }
10820 font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
10823 # pixmap_path "~/.pixmaps"
10825 # These set the widget types to use the styles defined above.
10826 # The widget types are listed in the class hierarchy, but could probably be
10827 # just listed in this document for the users reference.
10829 widget_class "GtkWindow" style "window"
10830 widget_class "GtkDialog" style "window"
10831 widget_class "GtkFileSelection" style "window"
10832 widget_class "*Gtk*Scale" style "scale"
10833 widget_class "*GtkCheckButton*" style "toggle_button"
10834 widget_class "*GtkRadioButton*" style "toggle_button"
10835 widget_class "*GtkButton*" style "button"
10836 widget_class "*Ruler" style "ruler"
10837 widget_class "*GtkText" style "text"
10839 # This sets all the buttons that are children of the "main window" to
10840 # the main_button style. These must be documented to be taken advantage of.
10841 widget "main window.*GtkButton*" style "main_button"
10844 <!-- ***************************************************************** -->
10845 <sect>Writing Your Own Widgets
10846 <!-- ***************************************************************** -->
10848 <!-- ----------------------------------------------------------------- -->
10851 Although the GTK distribution comes with many types of widgets that
10852 should cover most basic needs, there may come a time when you need to
10853 create your own new widget type. Since GTK uses widget inheritance
10854 extensively, and there is already a widget that is close to what you want,
10855 it is often possible to make a useful new widget type in
10856 just a few lines of code. But before starting work on a new widget, check
10857 around first to make sure that someone has not already written
10858 it. This will prevent duplication of effort and keep the number of
10859 GTK widgets out there to a minimum, which will help keep both the code
10860 and the interface of different applications consistent. As a flip side
10861 to this, once you finish your widget, announce it to the world so
10862 other people can benefit. The best place to do this is probably the
10865 Complete sources for the example widgets are available at the place you
10866 got this tutorial, or from:
10868 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
10869 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
10872 <!-- ----------------------------------------------------------------- -->
10873 <sect1> The Anatomy Of A Widget
10875 In order to create a new widget, it is important to have an
10876 understanding of how GTK objects work. This section is just meant as a
10877 brief overview. See the reference documentation for the details.
10879 GTK widgets are implemented in an object oriented fashion. However,
10880 they are implemented in standard C. This greatly improves portability
10881 and stability over using current generation C++ compilers; however,
10882 it does mean that the widget writer has to pay attention to some of
10883 the implementation details. The information common to all instances of
10884 one class of widgets (e.g., to all Button widgets) is stored in the
10885 <em>class structure</em>. There is only one copy of this in
10886 which is stored information about the class's signals
10887 (which act like virtual functions in C). To support inheritance, the
10888 first field in the class structure must be a copy of the parent's
10889 class structure. The declaration of the class structure of GtkButtton
10893 struct _GtkButtonClass
10895 GtkContainerClass parent_class;
10897 void (* pressed) (GtkButton *button);
10898 void (* released) (GtkButton *button);
10899 void (* clicked) (GtkButton *button);
10900 void (* enter) (GtkButton *button);
10901 void (* leave) (GtkButton *button);
10905 When a button is treated as a container (for instance, when it is
10906 resized), its class structure can be cast to GtkContainerClass, and
10907 the relevant fields used to handle the signals.
10909 There is also a structure for each widget that is created on a
10910 per-instance basis. This structure has fields to store information that
10911 is different for each instance of the widget. We'll call this
10912 structure the <em>object structure</em>. For the Button class, it looks
10918 GtkContainer container;
10922 guint in_button : 1;
10923 guint button_down : 1;
10927 Note that, similar to the class structure, the first field is the
10928 object structure of the parent class, so that this structure can be
10929 cast to the parent class's object structure as needed.
10931 <!-- ----------------------------------------------------------------- -->
10932 <sect1> Creating a Composite widget
10934 <!-- ----------------------------------------------------------------- -->
10935 <sect2> Introduction
10937 One type of widget that you may be interested in creating is a
10938 widget that is merely an aggregate of other GTK widgets. This type of
10939 widget does nothing that couldn't be done without creating new
10940 widgets, but provides a convenient way of packaging user interface
10941 elements for reuse. The FileSelection and ColorSelection widgets in
10942 the standard distribution are examples of this type of widget.
10944 The example widget that we'll create in this section is the Tictactoe
10945 widget, a 3x3 array of toggle buttons which triggers a signal when all
10946 three buttons in a row, column, or on one of the diagonals are
10949 <!-- ----------------------------------------------------------------- -->
10950 <sect2> Choosing a parent class
10952 The parent class for a composite widget is typically the container
10953 class that holds all of the elements of the composite widget. For
10954 example, the parent class of the FileSelection widget is the
10955 Dialog class. Since our buttons will be arranged in a table, it
10956 might seem natural to make our parent class the GtkTable
10957 class. Unfortunately, this turns out not to work. The creation of a
10958 widget is divided among two functions - a <tt/WIDGETNAME_new()/
10959 function that the user calls, and a <tt/WIDGETNAME_init()/ function
10960 which does the basic work of initializing the widget which is
10961 independent of the arguments passed to the <tt/_new()/
10962 function. Descendent widgets only call the <tt/_init/ function of
10963 their parent widget. But this division of labor doesn't work well for
10964 tables, which when created, need to know the number of rows and
10965 columns in the table. Unless we want to duplicate most of the
10966 functionality of <tt/gtk_table_new()/ in our Tictactoe widget, we had
10967 best avoid deriving it from GtkTable. For that reason, we derive it
10968 from GtkVBox instead, and stick our table inside the VBox.
10970 <!-- ----------------------------------------------------------------- -->
10971 <sect2> The header file
10973 Each widget class has a header file which declares the object and
10974 class structures for that widget, along with public functions.
10975 A couple of features are worth pointing out. To prevent duplicate
10976 definitions, we wrap the entire header file in:
10979 #ifndef __TICTACTOE_H__
10980 #define __TICTACTOE_H__
10984 #endif /* __TICTACTOE_H__ */
10987 And to keep C++ programs that include the header file happy, in:
10992 #endif /* __cplusplus */
10998 #endif /* __cplusplus */
11001 Along with the functions and structures, we declare three standard
11002 macros in our header file, <tt/TICTACTOE(obj)/,
11003 <tt/TICTACTOE_CLASS(klass)/, and <tt/IS_TICTACTOE(obj)/, which cast a
11004 pointer into a pointer to the object or class structure, and check
11005 if an object is a Tictactoe widget respectively.
11007 Here is the complete header file:
11012 #ifndef __TICTACTOE_H__
11013 #define __TICTACTOE_H__
11015 #include <gdk/gdk.h>
11016 #include <gtk/gtkvbox.h>
11020 #endif /* __cplusplus */
11022 #define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
11023 #define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
11024 #define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
11027 typedef struct _Tictactoe Tictactoe;
11028 typedef struct _TictactoeClass TictactoeClass;
11034 GtkWidget *buttons[3][3];
11037 struct _TictactoeClass
11039 GtkVBoxClass parent_class;
11041 void (* tictactoe) (Tictactoe *ttt);
11044 guint tictactoe_get_type (void);
11045 GtkWidget* tictactoe_new (void);
11046 void tictactoe_clear (Tictactoe *ttt);
11050 #endif /* __cplusplus */
11052 #endif /* __TICTACTOE_H__ */
11056 <!-- ----------------------------------------------------------------- -->
11057 <sect2> The <tt/_get_type()/ function.
11059 We now continue on to the implementation of our widget. A core
11060 function for every widget is the function
11061 <tt/WIDGETNAME_get_type()/. This function, when first called, tells
11062 GTK about the widget class, and gets an ID that uniquely identifies
11063 the widget class. Upon subsequent calls, it just returns the ID.
11067 tictactoe_get_type ()
11069 static guint ttt_type = 0;
11073 GtkTypeInfo ttt_info =
11076 sizeof (Tictactoe),
11077 sizeof (TictactoeClass),
11078 (GtkClassInitFunc) tictactoe_class_init,
11079 (GtkObjectInitFunc) tictactoe_init,
11080 (GtkArgSetFunc) NULL,
11081 (GtkArgGetFunc) NULL
11084 ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
11091 The GtkTypeInfo structure has the following definition:
11094 struct _GtkTypeInfo
11099 GtkClassInitFunc class_init_func;
11100 GtkObjectInitFunc object_init_func;
11101 GtkArgSetFunc arg_set_func;
11102 GtkArgGetFunc arg_get_func;
11106 The fields of this structure are pretty self-explanatory. We'll ignore
11107 the <tt/arg_set_func/ and <tt/arg_get_func/ fields here: they have an important,
11109 unimplemented, role in allowing widget options to be conveniently set
11110 from interpreted languages. Once GTK has a correctly filled in copy of
11111 this structure, it knows how to create objects of a particular widget
11114 <!-- ----------------------------------------------------------------- -->
11115 <sect2> The <tt/_class_init()/ function
11117 The <tt/WIDGETNAME_class_init()/ function initializes the fields of
11118 the widget's class structure, and sets up any signals for the
11119 class. For our Tictactoe widget it looks like:
11128 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
11131 tictactoe_class_init (TictactoeClass *class)
11133 GtkObjectClass *object_class;
11135 object_class = (GtkObjectClass*) class;
11137 tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
11139 object_class->type,
11140 GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
11141 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
11144 gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
11146 class->tictactoe = NULL;
11150 Our widget has just one signal, the <tt/tictactoe/ signal that is
11151 invoked when a row, column, or diagonal is completely filled in. Not
11152 every composite widget needs signals, so if you are reading this for
11153 the first time, you may want to skip to the next section now, as
11154 things are going to get a bit complicated.
11159 gint gtk_signal_new( const gchar *name,
11160 GtkSignalRunType run_type,
11161 GtkType object_type,
11162 gint function_offset,
11163 GtkSignalMarshaller marshaller,
11164 GtkType return_val,
11169 Creates a new signal. The parameters are:
11172 <item> <tt/name/: The name of the signal.
11173 <item> <tt/run_type/: Whether the default handler runs before or after
11174 user handlers. Usually this will be <tt/GTK_RUN_FIRST/, or <tt/GTK_RUN_LAST/,
11175 although there are other possibilities.
11176 <item> <tt/object_type/: The ID of the object that this signal applies
11177 to. (It will also apply to that objects descendents)
11178 <item> <tt/function_offset/: The offset within the class structure of
11179 a pointer to the default handler.
11180 <item> <tt/marshaller/: A function that is used to invoke the signal
11181 handler. For signal handlers that have no arguments other than the
11182 object that emitted the signal and user data, we can use the
11183 pre-supplied marshaller function <tt/gtk_signal_default_marshaller/.
11184 <item> <tt/return_val/: The type of the return val.
11185 <item> <tt/nparams/: The number of parameters of the signal handler
11186 (other than the two default ones mentioned above)
11187 <item> <tt/.../: The types of the parameters.
11190 When specifying types, the <tt/GtkType/ enumeration is used:
11215 /* it'd be great if the next two could be removed eventually */
11217 GTK_TYPE_C_CALLBACK,
11221 } GtkFundamentalType;
11224 <tt/gtk_signal_new()/ returns a unique integer identifier for the
11225 signal, that we store in the <tt/tictactoe_signals/ array, which we
11226 index using an enumeration. (Conventionally, the enumeration elements
11227 are the signal name, uppercased, but here there would be a conflict
11228 with the <tt/TICTACTOE()/ macro, so we called it <tt/TICTACTOE_SIGNAL/
11231 After creating our signals, we need to tell GTK to associate our
11232 signals with the Tictactoe class. We do that by calling
11233 <tt/gtk_object_class_add_signals()/. We then set the pointer which
11234 points to the default handler for the `tictactoe' signal to NULL,
11235 indicating that there is no default action.
11237 <!-- ----------------------------------------------------------------- -->
11238 <sect2> The <tt/_init()/ function.
11240 Each widget class also needs a function to initialize the object
11241 structure. Usually, this function has the fairly limited role of
11242 setting the fields of the structure to default values. For composite
11243 widgets, however, this function also creates the component widgets.
11247 tictactoe_init (Tictactoe *ttt)
11252 table = gtk_table_new (3, 3, TRUE);
11253 gtk_container_add (GTK_CONTAINER(ttt), table);
11254 gtk_widget_show (table);
11259 ttt->buttons[i][j] = gtk_toggle_button_new ();
11260 gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
11262 gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
11263 GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
11264 gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
11265 gtk_widget_show (ttt->buttons[i][j]);
11270 <!-- ----------------------------------------------------------------- -->
11271 <sect2> And the rest...
11273 There is one more function that every widget (except for base widget
11274 types like GtkBin that cannot be instantiated) needs to have - the
11275 function that the user calls to create an object of that type. This is
11276 conventionally called <tt/WIDGETNAME_new()/. In some
11277 widgets, though not for the Tictactoe widgets, this function takes
11278 arguments, and does some setup based on the arguments. The other two
11279 functions are specific to the Tictactoe widget.
11281 <tt/tictactoe_clear()/ is a public function that resets all the
11282 buttons in the widget to the up position. Note the use of
11283 <tt/gtk_signal_handler_block_by_data()/ to keep our signal handler for
11284 button toggles from being triggered unnecessarily.
11286 <tt/tictactoe_toggle()/ is the signal handler that is invoked when the
11287 user clicks on a button. It checks to see if there are any winning
11288 combinations that involve the toggled button, and if so, emits
11289 the "tictactoe" signal.
11295 return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
11299 tictactoe_clear (Tictactoe *ttt)
11306 gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
11307 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
11309 gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
11314 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
11318 static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
11319 { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
11320 { 0, 1, 2 }, { 0, 1, 2 } };
11321 static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
11322 { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
11323 { 0, 1, 2 }, { 2, 1, 0 } };
11325 int success, found;
11327 for (k=0; k<8; k++)
11334 success = success &&
11335 GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
11337 ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
11340 if (success && found)
11342 gtk_signal_emit (GTK_OBJECT (ttt),
11343 tictactoe_signals[TICTACTOE_SIGNAL]);
11350 And finally, an example program using our Tictactoe widget:
11353 #include <gtk/gtk.h>
11354 #include "tictactoe.h"
11356 /* Invoked when a row, column or diagonal is completed */
11358 win (GtkWidget *widget, gpointer data)
11360 g_print ("Yay!\n");
11361 tictactoe_clear (TICTACTOE (widget));
11365 main (int argc, char *argv[])
11370 gtk_init (&argc, &argv);
11372 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11374 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
11376 gtk_signal_connect (GTK_OBJECT (window), "destroy",
11377 GTK_SIGNAL_FUNC (gtk_exit), NULL);
11379 gtk_container_border_width (GTK_CONTAINER (window), 10);
11381 /* Create a new Tictactoe widget */
11382 ttt = tictactoe_new ();
11383 gtk_container_add (GTK_CONTAINER (window), ttt);
11384 gtk_widget_show (ttt);
11386 /* And attach to its "tictactoe" signal */
11387 gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
11388 GTK_SIGNAL_FUNC (win), NULL);
11390 gtk_widget_show (window);
11399 <!-- ----------------------------------------------------------------- -->
11400 <sect1> Creating a widget from scratch.
11402 <!-- ----------------------------------------------------------------- -->
11403 <sect2> Introduction
11405 In this section, we'll learn more about how widgets display themselves
11406 on the screen and interact with events. As an example of this, we'll
11407 create an analog dial widget with a pointer that the user can drag to
11410 <!-- ----------------------------------------------------------------- -->
11411 <sect2> Displaying a widget on the screen
11413 There are several steps that are involved in displaying on the screen.
11414 After the widget is created with a call to <tt/WIDGETNAME_new()/,
11415 several more functions are needed:
11418 <item> <tt/WIDGETNAME_realize()/ is responsible for creating an X
11419 window for the widget if it has one.
11420 <item> <tt/WIDGETNAME_map()/ is invoked after the user calls
11421 <tt/gtk_widget_show()/. It is responsible for making sure the widget
11422 is actually drawn on the screen (<em/mapped/). For a container class,
11423 it must also make calls to <tt/map()/> functions of any child widgets.
11424 <item> <tt/WIDGETNAME_draw()/ is invoked when <tt/gtk_widget_draw()/
11425 is called for the widget or one of its ancestors. It makes the actual
11426 calls to the drawing functions to draw the widget on the screen. For
11427 container widgets, this function must make calls to
11428 <tt/gtk_widget_draw()/ for its child widgets.
11429 <item> <tt/WIDGETNAME_expose()/ is a handler for expose events for the
11430 widget. It makes the necessary calls to the drawing functions to draw
11431 the exposed portion on the screen. For container widgets, this
11432 function must generate expose events for its child widgets which don't
11433 have their own windows. (If they have their own windows, then X will
11434 generate the necessary expose events)
11437 You might notice that the last two functions are quite similar - each
11438 is responsible for drawing the widget on the screen. In fact many
11439 types of widgets don't really care about the difference between the
11440 two. The default <tt/draw()/ function in the widget class simply
11441 generates a synthetic expose event for the redrawn area. However, some
11442 types of widgets can save work by distinguishing between the two
11443 functions. For instance, if a widget has multiple X windows, then
11444 since expose events identify the exposed window, it can redraw only
11445 the affected window, which is not possible for calls to <tt/draw()/.
11447 Container widgets, even if they don't care about the difference for
11448 themselves, can't simply use the default <tt/draw()/ function because
11449 their child widgets might care about the difference. However,
11450 it would be wasteful to duplicate the drawing code between the two
11451 functions. The convention is that such widgets have a function called
11452 <tt/WIDGETNAME_paint()/ that does the actual work of drawing the
11453 widget, that is then called by the <tt/draw()/ and <tt/expose()/
11456 In our example approach, since the dial widget is not a container
11457 widget, and only has a single window, we can take the simplest
11458 approach and use the default <tt/draw()/ function and only implement
11459 an <tt/expose()/ function.
11461 <!-- ----------------------------------------------------------------- -->
11462 <sect2> The origins of the Dial Widget
11464 Just as all land animals are just variants on the first amphibian that
11465 crawled up out of the mud, Gtk widgets tend to start off as variants
11466 of some other, previously written widget. Thus, although this section
11467 is entitled `Creating a Widget from Scratch', the Dial widget really
11468 began with the source code for the Range widget. This was picked as a
11469 starting point because it would be nice if our Dial had the same
11470 interface as the Scale widgets which are just specialized descendents
11471 of the Range widget. So, though the source code is presented below in
11472 finished form, it should not be implied that it was written, <em>deus
11473 ex machina</em> in this fashion. Also, if you aren't yet familiar with
11474 how scale widgets work from the application writer's point of view, it
11475 would be a good idea to look them over before continuing.
11477 <!-- ----------------------------------------------------------------- -->
11480 Quite a bit of our widget should look pretty familiar from the
11481 Tictactoe widget. First, we have a header file:
11484 /* GTK - The GIMP Toolkit
11485 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
11487 * This library is free software; you can redistribute it and/or
11488 * modify it under the terms of the GNU Library General Public
11489 * License as published by the Free Software Foundation; either
11490 * version 2 of the License, or (at your option) any later version.
11492 * This library is distributed in the hope that it will be useful,
11493 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11494 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11495 * Library General Public License for more details.
11497 * You should have received a copy of the GNU Library General Public
11498 * License along with this library; if not, write to the Free
11499 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
11502 #ifndef __GTK_DIAL_H__
11503 #define __GTK_DIAL_H__
11505 #include <gdk/gdk.h>
11506 #include <gtk/gtkadjustment.h>
11507 #include <gtk/gtkwidget.h>
11512 #endif /* __cplusplus */
11515 #define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
11516 #define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
11517 #define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
11520 typedef struct _GtkDial GtkDial;
11521 typedef struct _GtkDialClass GtkDialClass;
11527 /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
11530 /* Button currently pressed or 0 if none */
11533 /* Dimensions of dial components */
11535 gint pointer_width;
11537 /* ID of update timer, or 0 if none */
11540 /* Current angle */
11543 /* Old values from adjustment stored so we know when something changes */
11548 /* The adjustment object that stores the data for this dial */
11549 GtkAdjustment *adjustment;
11552 struct _GtkDialClass
11554 GtkWidgetClass parent_class;
11558 GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
11559 guint gtk_dial_get_type (void);
11560 GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
11561 void gtk_dial_set_update_policy (GtkDial *dial,
11562 GtkUpdateType policy);
11564 void gtk_dial_set_adjustment (GtkDial *dial,
11565 GtkAdjustment *adjustment);
11568 #endif /* __cplusplus */
11571 #endif /* __GTK_DIAL_H__ */
11574 Since there is quite a bit more going on in this widget, than the last
11575 one, we have more fields in the data structure, but otherwise things
11576 are pretty similar.
11578 Next, after including header files, and declaring a few constants,
11579 we have some functions to provide information about the widget
11585 #include <gtk/gtkmain.h>
11586 #include <gtk/gtksignal.h>
11588 #include "gtkdial.h"
11590 #define SCROLL_DELAY_LENGTH 300
11591 #define DIAL_DEFAULT_SIZE 100
11593 /* Forward declarations */
11595 [ omitted to save space ]
11599 static GtkWidgetClass *parent_class = NULL;
11602 gtk_dial_get_type ()
11604 static guint dial_type = 0;
11608 GtkTypeInfo dial_info =
11612 sizeof (GtkDialClass),
11613 (GtkClassInitFunc) gtk_dial_class_init,
11614 (GtkObjectInitFunc) gtk_dial_init,
11615 (GtkArgSetFunc) NULL,
11616 (GtkArgGetFunc) NULL,
11619 dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info);
11626 gtk_dial_class_init (GtkDialClass *class)
11628 GtkObjectClass *object_class;
11629 GtkWidgetClass *widget_class;
11631 object_class = (GtkObjectClass*) class;
11632 widget_class = (GtkWidgetClass*) class;
11634 parent_class = gtk_type_class (gtk_widget_get_type ());
11636 object_class->destroy = gtk_dial_destroy;
11638 widget_class->realize = gtk_dial_realize;
11639 widget_class->expose_event = gtk_dial_expose;
11640 widget_class->size_request = gtk_dial_size_request;
11641 widget_class->size_allocate = gtk_dial_size_allocate;
11642 widget_class->button_press_event = gtk_dial_button_press;
11643 widget_class->button_release_event = gtk_dial_button_release;
11644 widget_class->motion_notify_event = gtk_dial_motion_notify;
11648 gtk_dial_init (GtkDial *dial)
11651 dial->policy = GTK_UPDATE_CONTINUOUS;
11654 dial->pointer_width = 0;
11656 dial->old_value = 0.0;
11657 dial->old_lower = 0.0;
11658 dial->old_upper = 0.0;
11659 dial->adjustment = NULL;
11663 gtk_dial_new (GtkAdjustment *adjustment)
11667 dial = gtk_type_new (gtk_dial_get_type ());
11670 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
11672 gtk_dial_set_adjustment (dial, adjustment);
11674 return GTK_WIDGET (dial);
11678 gtk_dial_destroy (GtkObject *object)
11682 g_return_if_fail (object != NULL);
11683 g_return_if_fail (GTK_IS_DIAL (object));
11685 dial = GTK_DIAL (object);
11687 if (dial->adjustment)
11688 gtk_object_unref (GTK_OBJECT (dial->adjustment));
11690 if (GTK_OBJECT_CLASS (parent_class)->destroy)
11691 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
11695 Note that this <tt/init()/ function does less than for the Tictactoe
11696 widget, since this is not a composite widget, and the <tt/new()/
11697 function does more, since it now has an argument. Also, note that when
11698 we store a pointer to the Adjustment object, we increment its
11699 reference count, (and correspondingly decrement when we no longer use
11700 it) so that GTK can keep track of when it can be safely destroyed.
11703 Also, there are a few function to manipulate the widget's options:
11707 gtk_dial_get_adjustment (GtkDial *dial)
11709 g_return_val_if_fail (dial != NULL, NULL);
11710 g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
11712 return dial->adjustment;
11716 gtk_dial_set_update_policy (GtkDial *dial,
11717 GtkUpdateType policy)
11719 g_return_if_fail (dial != NULL);
11720 g_return_if_fail (GTK_IS_DIAL (dial));
11722 dial->policy = policy;
11726 gtk_dial_set_adjustment (GtkDial *dial,
11727 GtkAdjustment *adjustment)
11729 g_return_if_fail (dial != NULL);
11730 g_return_if_fail (GTK_IS_DIAL (dial));
11732 if (dial->adjustment)
11734 gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
11735 gtk_object_unref (GTK_OBJECT (dial->adjustment));
11738 dial->adjustment = adjustment;
11739 gtk_object_ref (GTK_OBJECT (dial->adjustment));
11741 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
11742 (GtkSignalFunc) gtk_dial_adjustment_changed,
11744 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
11745 (GtkSignalFunc) gtk_dial_adjustment_value_changed,
11748 dial->old_value = adjustment->value;
11749 dial->old_lower = adjustment->lower;
11750 dial->old_upper = adjustment->upper;
11752 gtk_dial_update (dial);
11756 <sect2> <tt/gtk_dial_realize()/
11759 Now we come to some new types of functions. First, we have a function
11760 that does the work of creating the X window. Notice that a mask is
11761 passed to the function <tt/gdk_window_new()/ which specifies which fields of
11762 the GdkWindowAttr structure actually have data in them (the remaining
11763 fields will be given default values). Also worth noting is the way the
11764 event mask of the widget is created. We call
11765 <tt/gtk_widget_get_events()/ to retrieve the event mask that the user
11766 has specified for this widget (with <tt/gtk_widget_set_events()/, and
11767 add the events that we are interested in ourselves.
11770 After creating the window, we set its style and background, and put a
11771 pointer to the widget in the user data field of the GdkWindow. This
11772 last step allows GTK to dispatch events for this window to the correct
11777 gtk_dial_realize (GtkWidget *widget)
11780 GdkWindowAttr attributes;
11781 gint attributes_mask;
11783 g_return_if_fail (widget != NULL);
11784 g_return_if_fail (GTK_IS_DIAL (widget));
11786 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
11787 dial = GTK_DIAL (widget);
11789 attributes.x = widget->allocation.x;
11790 attributes.y = widget->allocation.y;
11791 attributes.width = widget->allocation.width;
11792 attributes.height = widget->allocation.height;
11793 attributes.wclass = GDK_INPUT_OUTPUT;
11794 attributes.window_type = GDK_WINDOW_CHILD;
11795 attributes.event_mask = gtk_widget_get_events (widget) |
11796 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
11797 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
11798 GDK_POINTER_MOTION_HINT_MASK;
11799 attributes.visual = gtk_widget_get_visual (widget);
11800 attributes.colormap = gtk_widget_get_colormap (widget);
11802 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
11803 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
11805 widget->style = gtk_style_attach (widget->style, widget->window);
11807 gdk_window_set_user_data (widget->window, widget);
11809 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
11813 <sect2> Size negotiation
11816 Before the first time that the window containing a widget is
11817 displayed, and whenever the layout of the window changes, GTK asks
11818 each child widget for its desired size. This request is handled by the
11819 function, <tt/gtk_dial_size_request()/. Since our widget isn't a
11820 container widget, and has no real constraints on its size, we just
11821 return a reasonable default value.
11825 gtk_dial_size_request (GtkWidget *widget,
11826 GtkRequisition *requisition)
11828 requisition->width = DIAL_DEFAULT_SIZE;
11829 requisition->height = DIAL_DEFAULT_SIZE;
11834 After all the widgets have requested an ideal size, the layout of the
11835 window is computed and each child widget is notified of its actual
11836 size. Usually, this will at least as large as the requested size, but
11837 if for instance, the user has resized the window, it may occasionally
11838 be smaller than the requested size. The size notification is handled
11839 by the function <tt/gtk_dial_size_allocate()/. Notice that as well as
11840 computing the sizes of some component pieces for future use, this
11841 routine also does the grunt work of moving the widgets X window into
11842 the new position and size.
11846 gtk_dial_size_allocate (GtkWidget *widget,
11847 GtkAllocation *allocation)
11851 g_return_if_fail (widget != NULL);
11852 g_return_if_fail (GTK_IS_DIAL (widget));
11853 g_return_if_fail (allocation != NULL);
11855 widget->allocation = *allocation;
11856 if (GTK_WIDGET_REALIZED (widget))
11858 dial = GTK_DIAL (widget);
11860 gdk_window_move_resize (widget->window,
11861 allocation->x, allocation->y,
11862 allocation->width, allocation->height);
11864 dial->radius = MAX(allocation->width,allocation->height) * 0.45;
11865 dial->pointer_width = dial->radius / 5;
11870 <!-- ----------------------------------------------------------------- -->
11871 <sect2> <tt/gtk_dial_expose()/
11874 As mentioned above, all the drawing of this widget is done in the
11875 handler for expose events. There's not much to remark on here except
11876 the use of the function <tt/gtk_draw_polygon/ to draw the pointer with
11877 three dimensional shading according to the colors stored in the
11882 gtk_dial_expose (GtkWidget *widget,
11883 GdkEventExpose *event)
11886 GdkPoint points[3];
11893 g_return_val_if_fail (widget != NULL, FALSE);
11894 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
11895 g_return_val_if_fail (event != NULL, FALSE);
11897 if (event->count > 0)
11900 dial = GTK_DIAL (widget);
11902 gdk_window_clear_area (widget->window,
11904 widget->allocation.width,
11905 widget->allocation.height);
11907 xc = widget->allocation.width/2;
11908 yc = widget->allocation.height/2;
11912 for (i=0; i<25; i++)
11914 theta = (i*M_PI/18. - M_PI/6.);
11918 tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
11920 gdk_draw_line (widget->window,
11921 widget->style->fg_gc[widget->state],
11922 xc + c*(dial->radius - tick_length),
11923 yc - s*(dial->radius - tick_length),
11924 xc + c*dial->radius,
11925 yc - s*dial->radius);
11930 s = sin(dial->angle);
11931 c = cos(dial->angle);
11934 points[0].x = xc + s*dial->pointer_width/2;
11935 points[0].y = yc + c*dial->pointer_width/2;
11936 points[1].x = xc + c*dial->radius;
11937 points[1].y = yc - s*dial->radius;
11938 points[2].x = xc - s*dial->pointer_width/2;
11939 points[2].y = yc - c*dial->pointer_width/2;
11941 gtk_draw_polygon (widget->style,
11952 <!-- ----------------------------------------------------------------- -->
11953 <sect2> Event handling
11957 The rest of the widget's code handles various types of events, and
11958 isn't too different from what would be found in many GTK
11959 applications. Two types of events can occur - either the user can
11960 click on the widget with the mouse and drag to move the pointer, or
11961 the value of the Adjustment object can change due to some external
11965 When the user clicks on the widget, we check to see if the click was
11966 appropriately near the pointer, and if so, store then button that the
11967 user clicked with in the <tt/button/ field of the widget
11968 structure, and grab all mouse events with a call to
11969 <tt/gtk_grab_add()/. Subsequent motion of the mouse causes the
11970 value of the control to be recomputed (by the function
11971 <tt/gtk_dial_update_mouse/). Depending on the policy that has been
11972 set, "value_changed" events are either generated instantly
11973 (<tt/GTK_UPDATE_CONTINUOUS/), after a delay in a timer added with
11974 <tt/gtk_timeout_add()/ (<tt/GTK_UPDATE_DELAYED/), or only when the
11975 button is released (<tt/GTK_UPDATE_DISCONTINUOUS/).
11979 gtk_dial_button_press (GtkWidget *widget,
11980 GdkEventButton *event)
11986 double d_perpendicular;
11988 g_return_val_if_fail (widget != NULL, FALSE);
11989 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
11990 g_return_val_if_fail (event != NULL, FALSE);
11992 dial = GTK_DIAL (widget);
11994 /* Determine if button press was within pointer region - we
11995 do this by computing the parallel and perpendicular distance of
11996 the point where the mouse was pressed from the line passing through
11999 dx = event->x - widget->allocation.width / 2;
12000 dy = widget->allocation.height / 2 - event->y;
12002 s = sin(dial->angle);
12003 c = cos(dial->angle);
12005 d_parallel = s*dy + c*dx;
12006 d_perpendicular = fabs(s*dx - c*dy);
12008 if (!dial->button &&
12009 (d_perpendicular < dial->pointer_width/2) &&
12010 (d_parallel > - dial->pointer_width))
12012 gtk_grab_add (widget);
12014 dial->button = event->button;
12016 gtk_dial_update_mouse (dial, event->x, event->y);
12023 gtk_dial_button_release (GtkWidget *widget,
12024 GdkEventButton *event)
12028 g_return_val_if_fail (widget != NULL, FALSE);
12029 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
12030 g_return_val_if_fail (event != NULL, FALSE);
12032 dial = GTK_DIAL (widget);
12034 if (dial->button == event->button)
12036 gtk_grab_remove (widget);
12040 if (dial->policy == GTK_UPDATE_DELAYED)
12041 gtk_timeout_remove (dial->timer);
12043 if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
12044 (dial->old_value != dial->adjustment->value))
12045 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
12052 gtk_dial_motion_notify (GtkWidget *widget,
12053 GdkEventMotion *event)
12056 GdkModifierType mods;
12059 g_return_val_if_fail (widget != NULL, FALSE);
12060 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
12061 g_return_val_if_fail (event != NULL, FALSE);
12063 dial = GTK_DIAL (widget);
12065 if (dial->button != 0)
12070 if (event->is_hint || (event->window != widget->window))
12071 gdk_window_get_pointer (widget->window, &x, &y, &mods);
12073 switch (dial->button)
12076 mask = GDK_BUTTON1_MASK;
12079 mask = GDK_BUTTON2_MASK;
12082 mask = GDK_BUTTON3_MASK;
12090 gtk_dial_update_mouse (dial, x,y);
12097 gtk_dial_timer (GtkDial *dial)
12099 g_return_val_if_fail (dial != NULL, FALSE);
12100 g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
12102 if (dial->policy == GTK_UPDATE_DELAYED)
12103 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
12109 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
12114 g_return_if_fail (dial != NULL);
12115 g_return_if_fail (GTK_IS_DIAL (dial));
12117 xc = GTK_WIDGET(dial)->allocation.width / 2;
12118 yc = GTK_WIDGET(dial)->allocation.height / 2;
12120 old_value = dial->adjustment->value;
12121 dial->angle = atan2(yc-y, x-xc);
12123 if (dial->angle < -M_PI/2.)
12124 dial->angle += 2*M_PI;
12126 if (dial->angle < -M_PI/6)
12127 dial->angle = -M_PI/6;
12129 if (dial->angle > 7.*M_PI/6.)
12130 dial->angle = 7.*M_PI/6.;
12132 dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
12133 (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
12135 if (dial->adjustment->value != old_value)
12137 if (dial->policy == GTK_UPDATE_CONTINUOUS)
12139 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
12143 gtk_widget_draw (GTK_WIDGET(dial), NULL);
12145 if (dial->policy == GTK_UPDATE_DELAYED)
12148 gtk_timeout_remove (dial->timer);
12150 dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
12151 (GtkFunction) gtk_dial_timer,
12160 Changes to the Adjustment by external means are communicated to our
12161 widget by the `changed' and `value_changed' signals. The handlers
12162 for these functions call <tt/gtk_dial_update()/ to validate the
12163 arguments, compute the new pointer angle, and redraw the widget (by
12164 calling <tt/gtk_widget_draw()/).
12168 gtk_dial_update (GtkDial *dial)
12172 g_return_if_fail (dial != NULL);
12173 g_return_if_fail (GTK_IS_DIAL (dial));
12175 new_value = dial->adjustment->value;
12177 if (new_value < dial->adjustment->lower)
12178 new_value = dial->adjustment->lower;
12180 if (new_value > dial->adjustment->upper)
12181 new_value = dial->adjustment->upper;
12183 if (new_value != dial->adjustment->value)
12185 dial->adjustment->value = new_value;
12186 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
12189 dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
12190 (dial->adjustment->upper - dial->adjustment->lower);
12192 gtk_widget_draw (GTK_WIDGET(dial), NULL);
12196 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
12201 g_return_if_fail (adjustment != NULL);
12202 g_return_if_fail (data != NULL);
12204 dial = GTK_DIAL (data);
12206 if ((dial->old_value != adjustment->value) ||
12207 (dial->old_lower != adjustment->lower) ||
12208 (dial->old_upper != adjustment->upper))
12210 gtk_dial_update (dial);
12212 dial->old_value = adjustment->value;
12213 dial->old_lower = adjustment->lower;
12214 dial->old_upper = adjustment->upper;
12219 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
12224 g_return_if_fail (adjustment != NULL);
12225 g_return_if_fail (data != NULL);
12227 dial = GTK_DIAL (data);
12229 if (dial->old_value != adjustment->value)
12231 gtk_dial_update (dial);
12233 dial->old_value = adjustment->value;
12238 <!-- ----------------------------------------------------------------- -->
12239 <sect2> Possible Enhancements
12242 The Dial widget as we've described it so far runs about 670 lines of
12243 code. Although that might sound like a fair bit, we've really
12244 accomplished quite a bit with that much code, especially since much of
12245 that length is headers and boilerplate. However, there are quite a few
12246 more enhancements that could be made to this widget:
12249 <item> If you try this widget out, you'll find that there is some
12250 flashing as the pointer is dragged around. This is because the entire
12251 widget is erased every time the pointer is moved before being
12252 redrawn. Often, the best way to handle this problem is to draw to an
12253 offscreen pixmap, then copy the final results onto the screen in one
12254 step. (The ProgressBar widget draws itself in this fashion.)
12256 <item> The user should be able to use the up and down arrow keys to
12257 increase and decrease the value.
12259 <item> It would be nice if the widget had buttons to increase and
12260 decrease the value in small or large steps. Although it would be
12261 possible to use embedded Button widgets for this, we would also like
12262 the buttons to auto-repeat when held down, as the arrows on a
12263 scrollbar do. Most of the code to implement this type of behavior can
12264 be found in the GtkRange widget.
12266 <item> The Dial widget could be made into a container widget with a
12267 single child widget positioned at the bottom between the buttons
12268 mentioned above. The user could then add their choice of a label or
12269 entry widget to display the current value of the dial.
12273 <!-- ----------------------------------------------------------------- -->
12274 <sect1> Learning More
12277 Only a small part of the many details involved in creating widgets
12278 could be described above. If you want to write your own widgets, the
12279 best source of examples is the GTK source itself. Ask yourself some
12280 questions about the widget you want to write: is it a Container
12281 widget? does it have its own window? is it a modification of an
12282 existing widget? Then find a similar widget, and start making changes.
12285 <!-- ***************************************************************** -->
12286 <sect>Scribble, A Simple Example Drawing Program
12287 <!-- ***************************************************************** -->
12289 <!-- ----------------------------------------------------------------- -->
12293 In this section, we will build a simple drawing program. In the
12294 process, we will examine how to handle mouse events, how to draw in a
12295 window, and how to do drawing better by using a backing pixmap. After
12296 creating the simple drawing program, we will extend it by adding
12297 support for XInput devices, such as drawing tablets. GTK provides
12298 support routines which makes getting extended information, such as
12299 pressure and tilt, from such devices quite easy.
12301 <!-- ----------------------------------------------------------------- -->
12302 <sect1> Event Handling
12305 The GTK signals we have already discussed are for high-level actions,
12306 such as a menu item being selected. However, sometimes it is useful to
12307 learn about lower-level occurrences, such as the mouse being moved, or
12308 a key being pressed. There are also GTK signals corresponding to these
12309 low-level <em>events</em>. The handlers for these signals have an
12310 extra parameter which is a pointer to a structure containing
12311 information about the event. For instance, motion events handlers are
12312 passed a pointer to a GdkEventMotion structure which looks (in part)
12316 struct _GdkEventMotion
12329 <tt/type/ will be set to the event type, in this case
12330 <tt/GDK_MOTION_NOTIFY/, window is the window in which the event
12331 occurred. <tt/x/ and <tt/y/ give the coordinates of the event,
12332 and <tt/state/ specifies the modifier state when the event
12333 occurred (that is, it specifies which modifier keys and mouse buttons
12334 were pressed.) It is the bitwise OR of some of the following:
12353 As for other signals, to determine what happens when an event occurs
12354 we call <tt>gtk_signal_connect()</tt>. But we also need let GTK
12355 know which events we want to be notified about. To do this, we call
12359 void gtk_widget_set_events (GtkWidget *widget,
12363 The second field specifies the events we are interested in. It
12364 is the bitwise OR of constants that specify different types
12365 of events. For future reference the event types are:
12369 GDK_POINTER_MOTION_MASK
12370 GDK_POINTER_MOTION_HINT_MASK
12371 GDK_BUTTON_MOTION_MASK
12372 GDK_BUTTON1_MOTION_MASK
12373 GDK_BUTTON2_MOTION_MASK
12374 GDK_BUTTON3_MOTION_MASK
12375 GDK_BUTTON_PRESS_MASK
12376 GDK_BUTTON_RELEASE_MASK
12378 GDK_KEY_RELEASE_MASK
12379 GDK_ENTER_NOTIFY_MASK
12380 GDK_LEAVE_NOTIFY_MASK
12381 GDK_FOCUS_CHANGE_MASK
12383 GDK_PROPERTY_CHANGE_MASK
12384 GDK_PROXIMITY_IN_MASK
12385 GDK_PROXIMITY_OUT_MASK
12388 There are a few subtle points that have to be observed when calling
12389 <tt/gtk_widget_set_events()/. First, it must be called before the X window
12390 for a GTK widget is created. In practical terms, this means you
12391 should call it immediately after creating the widget. Second, the
12392 widget must have an associated X window. For efficiency, many widget
12393 types do not have their own window, but draw in their parent's window.
12416 To capture events for these widgets, you need to use an EventBox
12417 widget. See the section on the <ref id="sec_EventBox"
12418 name="EventBox"> widget for details.
12421 For our drawing program, we want to know when the mouse button is
12422 pressed and when the mouse is moved, so we specify
12423 <tt/GDK_POINTER_MOTION_MASK/ and <tt/GDK_BUTTON_PRESS_MASK/. We also
12424 want to know when we need to redraw our window, so we specify
12425 <tt/GDK_EXPOSURE_MASK/. Although we want to be notified via a
12426 Configure event when our window size changes, we don't have to specify
12427 the corresponding <tt/GDK_STRUCTURE_MASK/ flag, because it is
12428 automatically specified for all windows.
12431 It turns out, however, that there is a problem with just specifying
12432 <tt/GDK_POINTER_MOTION_MASK/. This will cause the server to add a new
12433 motion event to the event queue every time the user moves the mouse.
12434 Imagine that it takes us 0.1 seconds to handle a motion event, but the
12435 X server queues a new motion event every 0.05 seconds. We will soon
12436 get way behind the users drawing. If the user draws for 5 seconds,
12437 it will take us another 5 seconds to catch up after they release
12438 the mouse button! What we would like is to only get one motion
12439 event for each event we process. The way to do this is to
12440 specify <tt/GDK_POINTER_MOTION_HINT_MASK/.
12443 When we specify <tt/GDK_POINTER_MOTION_HINT_MASK/, the server sends
12444 us a motion event the first time the pointer moves after entering
12445 our window, or after a button press or release event. Subsequent
12446 motion events will be suppressed until we explicitly ask for
12447 the position of the pointer using the function:
12450 GdkWindow* gdk_window_get_pointer (GdkWindow *window,
12453 GdkModifierType *mask);
12456 (There is another function, <tt>gtk_widget_get_pointer()</tt> which
12457 has a simpler interface, but turns out not to be very useful, since
12458 it only retrieves the position of the mouse, not whether the buttons
12462 The code to set the events for our window then looks like:
12465 gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
12466 (GtkSignalFunc) expose_event, NULL);
12467 gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
12468 (GtkSignalFunc) configure_event, NULL);
12469 gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
12470 (GtkSignalFunc) motion_notify_event, NULL);
12471 gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
12472 (GtkSignalFunc) button_press_event, NULL);
12474 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
12475 | GDK_LEAVE_NOTIFY_MASK
12476 | GDK_BUTTON_PRESS_MASK
12477 | GDK_POINTER_MOTION_MASK
12478 | GDK_POINTER_MOTION_HINT_MASK);
12481 We'll save the "expose_event" and "configure_event" handlers for
12482 later. The "motion_notify_event" and "button_press_event" handlers
12487 button_press_event (GtkWidget *widget, GdkEventButton *event)
12489 if (event->button == 1 && pixmap != NULL)
12490 draw_brush (widget, event->x, event->y);
12496 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
12499 GdkModifierType state;
12501 if (event->is_hint)
12502 gdk_window_get_pointer (event->window, &x, &y, &state);
12507 state = event->state;
12510 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
12511 draw_brush (widget, x, y);
12517 <!-- ----------------------------------------------------------------- -->
12518 <sect1> The DrawingArea Widget, And Drawing
12521 We know turn to the process of drawing on the screen. The
12522 widget we use for this is the DrawingArea widget. A drawing area
12523 widget is essentially an X window and nothing more. It is a blank
12524 canvas in which we can draw whatever we like. A drawing area
12525 is created using the call:
12528 GtkWidget* gtk_drawing_area_new (void);
12531 A default size for the widget can be specified by calling:
12534 void gtk_drawing_area_size (GtkDrawingArea *darea,
12539 This default size can be overridden, as is true for all widgets,
12540 by calling <tt>gtk_widget_set_usize()</tt>, and that, in turn, can
12541 be overridden if the user manually resizes the the window containing
12545 It should be noted that when we create a DrawingArea widget, we are,
12546 <em>completely</em> responsible for drawing the contents. If our
12547 window is obscured then uncovered, we get an exposure event and must
12548 redraw what was previously hidden.
12551 Having to remember everything that was drawn on the screen so we
12552 can properly redraw it can, to say the least, be a nuisance. In
12553 addition, it can be visually distracting if portions of the
12554 window are cleared, then redrawn step by step. The solution to
12555 this problem is to use an offscreen <em>backing pixmap</em>.
12556 Instead of drawing directly to the screen, we draw to an image
12557 stored in server memory but not displayed, then when the image
12558 changes or new portions of the image are displayed, we copy the
12559 relevant portions onto the screen.
12562 To create an offscreen pixmap, we call the function:
12565 GdkPixmap* gdk_pixmap_new (GdkWindow *window,
12571 The <tt>window</tt> parameter specifies a GDK window that this pixmap
12572 takes some of its properties from. <tt>width</tt> and <tt>height</tt>
12573 specify the size of the pixmap. <tt>depth</tt> specifies the <em>color
12574 depth</em>, that is the number of bits per pixel, for the new window.
12575 If the depth is specified as <tt>-1</tt>, it will match the depth
12576 of <tt>window</tt>.
12579 We create the pixmap in our "configure_event" handler. This event
12580 is generated whenever the window changes size, including when it
12581 is originally created.
12584 /* Backing pixmap for drawing area */
12585 static GdkPixmap *pixmap = NULL;
12587 /* Create a new backing pixmap of the appropriate size */
12589 configure_event (GtkWidget *widget, GdkEventConfigure *event)
12592 gdk_pixmap_unref(pixmap);
12594 pixmap = gdk_pixmap_new(widget->window,
12595 widget->allocation.width,
12596 widget->allocation.height,
12598 gdk_draw_rectangle (pixmap,
12599 widget->style->white_gc,
12602 widget->allocation.width,
12603 widget->allocation.height);
12609 The call to <tt>gdk_draw_rectangle()</tt> clears the pixmap
12610 initially to white. We'll say more about that in a moment.
12613 Our exposure event handler then simply copies the relevant portion
12614 of the pixmap onto the screen (we determine the area we need
12615 to redraw by using the event->area field of the exposure event):
12618 /* Redraw the screen from the backing pixmap */
12620 expose_event (GtkWidget *widget, GdkEventExpose *event)
12622 gdk_draw_pixmap(widget->window,
12623 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
12625 event->area.x, event->area.y,
12626 event->area.x, event->area.y,
12627 event->area.width, event->area.height);
12633 We've now seen how to keep the screen up to date with our pixmap, but
12634 how do we actually draw interesting stuff on our pixmap? There are a
12635 large number of calls in GTK's GDK library for drawing on
12636 <em>drawables</em>. A drawable is simply something that can be drawn
12637 upon. It can be a window, a pixmap, or a bitmap (a black and white
12638 image). We've already seen two such calls above,
12639 <tt>gdk_draw_rectangle()</tt> and <tt>gdk_draw_pixmap()</tt>. The
12644 gdk_draw_rectangle ()
12646 gdk_draw_polygon ()
12653 gdk_draw_segments ()
12656 See the reference documentation or the header file
12657 <tt><gdk/gdk.h></tt> for further details on these functions.
12658 These functions all share the same first two arguments. The first
12659 argument is the drawable to draw upon, the second argument is a
12660 <em>graphics context</em> (GC).
12663 A graphics context encapsulates information about things such as
12664 foreground and background color and line width. GDK has a full set of
12665 functions for creating and modifying graphics contexts, but to keep
12666 things simple we'll just use predefined graphics contexts. Each widget
12667 has an associated style. (Which can be modified in a gtkrc file, see
12668 the section GTK's rc file.) This, among other things, stores a number
12669 of graphics contexts. Some examples of accessing these graphics
12673 widget->style->white_gc
12674 widget->style->black_gc
12675 widget->style->fg_gc[GTK_STATE_NORMAL]
12676 widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
12679 The fields <tt>fg_gc</tt>, <tt>bg_gc</tt>, <tt>dark_gc</tt>, and
12680 <tt>light_gc</tt> are indexed by a parameter of type
12681 <tt>GtkStateType</tt> which can take on the values:
12686 GTK_STATE_PRELIGHT,
12687 GTK_STATE_SELECTED,
12688 GTK_STATE_INSENSITIVE
12691 For instance, the for <tt/GTK_STATE_SELECTED/ the default foreground
12692 color is white and the default background color, dark blue.
12695 Our function <tt>draw_brush()</tt>, which does the actual drawing
12696 on the screen, is then:
12699 /* Draw a rectangle on the screen */
12701 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
12703 GdkRectangle update_rect;
12705 update_rect.x = x - 5;
12706 update_rect.y = y - 5;
12707 update_rect.width = 10;
12708 update_rect.height = 10;
12709 gdk_draw_rectangle (pixmap,
12710 widget->style->black_gc,
12712 update_rect.x, update_rect.y,
12713 update_rect.width, update_rect.height);
12714 gtk_widget_draw (widget, &update_rect);
12718 After we draw the rectangle representing the brush onto the pixmap,
12719 we call the function:
12722 void gtk_widget_draw (GtkWidget *widget,
12723 GdkRectangle *area);
12726 which notifies X that the area given by the <tt>area</tt> parameter
12727 needs to be updated. X will eventually generate an expose event
12728 (possibly combining the areas passed in several calls to
12729 <tt>gtk_widget_draw()</tt>) which will cause our expose event handler
12730 to copy the relevant portions to the screen.
12733 We have now covered the entire drawing program except for a few
12734 mundane details like creating the main window. The complete
12735 source code is available from the location from which you got
12736 this tutorial, or from:
12738 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
12739 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
12742 <!-- ----------------------------------------------------------------- -->
12743 <sect1> Adding XInput support
12747 It is now possible to buy quite inexpensive input devices such
12748 as drawing tablets, which allow drawing with a much greater
12749 ease of artistic expression than does a mouse. The simplest way
12750 to use such devices is simply as a replacement for the mouse,
12751 but that misses out many of the advantages of these devices,
12755 <item> Pressure sensitivity
12756 <item> Tilt reporting
12757 <item> Sub-pixel positioning
12758 <item> Multiple inputs (for example, a stylus with a point and eraser)
12761 For information about the XInput extension, see the <htmlurl
12762 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
12763 name="XInput-HOWTO">.
12766 If we examine the full definition of, for example, the GdkEventMotion
12767 structure, we see that it has fields to support extended device
12771 struct _GdkEventMotion
12783 GdkInputSource source;
12788 <tt/pressure/ gives the pressure as a floating point number between
12789 0 and 1. <tt/xtilt/ and <tt/ytilt/ can take on values between
12790 -1 and 1, corresponding to the degree of tilt in each direction.
12791 <tt/source/ and <tt/deviceid/ specify the device for which the
12792 event occurred in two different ways. <tt/source/ gives some simple
12793 information about the type of device. It can take the enumeration
12803 <tt/deviceid/ specifies a unique numeric ID for the device. This can
12804 be used to find out further information about the device using the
12805 <tt/gdk_input_list_devices()/ call (see below). The special value
12806 <tt/GDK_CORE_POINTER/ is used for the core pointer device. (Usually
12809 <sect2> Enabling extended device information
12812 To let GTK know about our interest in the extended device information,
12813 we merely have to add a single line to our program:
12816 gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
12819 By giving the value <tt/GDK_EXTENSION_EVENTS_CURSOR/ we say that
12820 we are interested in extension events, but only if we don't have
12821 to draw our own cursor. See the section <ref
12822 id="sec_Further_Sophistications" name="Further Sophistications"> below
12823 for more information about drawing the cursor. We could also
12824 give the values <tt/GDK_EXTENSION_EVENTS_ALL/ if we were willing
12825 to draw our own cursor, or <tt/GDK_EXTENSION_EVENTS_NONE/ to revert
12826 back to the default condition.
12829 This is not completely the end of the story however. By default,
12830 no extension devices are enabled. We need a mechanism to allow
12831 users to enable and configure their extension devices. GTK provides
12832 the InputDialog widget to automate this process. The following
12833 procedure manages an InputDialog widget. It creates the dialog if
12834 it isn't present, and raises it to the top otherwise.
12838 input_dialog_destroy (GtkWidget *w, gpointer data)
12840 *((GtkWidget **)data) = NULL;
12844 create_input_dialog ()
12846 static GtkWidget *inputd = NULL;
12850 inputd = gtk_input_dialog_new();
12852 gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
12853 (GtkSignalFunc)input_dialog_destroy, &inputd);
12854 gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
12856 (GtkSignalFunc)gtk_widget_hide,
12857 GTK_OBJECT(inputd));
12858 gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
12860 gtk_widget_show (inputd);
12864 if (!GTK_WIDGET_MAPPED(inputd))
12865 gtk_widget_show(inputd);
12867 gdk_window_raise(inputd->window);
12872 (You might want to take note of the way we handle this dialog. By
12873 connecting to the "destroy" signal, we make sure that we don't keep a
12874 pointer to dialog around after it is destroyed - that could lead to a
12878 The InputDialog has two buttons "Close" and "Save", which by default
12879 have no actions assigned to them. In the above function we make
12880 "Close" hide the dialog, hide the "Save" button, since we don't
12881 implement saving of XInput options in this program.
12883 <sect2> Using extended device information
12886 Once we've enabled the device, we can just use the extended
12887 device information in the extra fields of the event structures.
12888 In fact, it is always safe to use this information since these
12889 fields will have reasonable default values even when extended
12890 events are not enabled.
12893 Once change we do have to make is to call
12894 <tt/gdk_input_window_get_pointer()/ instead of
12895 <tt/gdk_window_get_pointer/. This is necessary because
12896 <tt/gdk_window_get_pointer/ doesn't return the extended device
12900 void gdk_input_window_get_pointer (GdkWindow *window,
12907 GdkModifierType *mask);
12910 When calling this function, we need to specify the device ID as
12911 well as the window. Usually, we'll get the device ID from the
12912 <tt/deviceid/ field of an event structure. Again, this function
12913 will return reasonable values when extension events are not
12914 enabled. (In this case, <tt/event->deviceid/ will have the value
12915 <tt/GDK_CORE_POINTER/).
12917 So the basic structure of our button-press and motion event handlers,
12918 doesn't change much - we just need to add code to deal with the
12919 extended information.
12923 button_press_event (GtkWidget *widget, GdkEventButton *event)
12925 print_button_press (event->deviceid);
12927 if (event->button == 1 && pixmap != NULL)
12928 draw_brush (widget, event->source, event->x, event->y, event->pressure);
12934 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
12938 GdkModifierType state;
12940 if (event->is_hint)
12941 gdk_input_window_get_pointer (event->window, event->deviceid,
12942 &x, &y, &pressure, NULL, NULL, &state);
12947 pressure = event->pressure;
12948 state = event->state;
12951 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
12952 draw_brush (widget, event->source, x, y, pressure);
12958 We also need to do something with the new information. Our new
12959 <tt/draw_brush()/ function draws with a different color for
12960 each <tt/event->source/ and changes the brush size depending
12964 /* Draw a rectangle on the screen, size depending on pressure,
12965 and color on the type of device */
12967 draw_brush (GtkWidget *widget, GdkInputSource source,
12968 gdouble x, gdouble y, gdouble pressure)
12971 GdkRectangle update_rect;
12975 case GDK_SOURCE_MOUSE:
12976 gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
12978 case GDK_SOURCE_PEN:
12979 gc = widget->style->black_gc;
12981 case GDK_SOURCE_ERASER:
12982 gc = widget->style->white_gc;
12985 gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
12988 update_rect.x = x - 10 * pressure;
12989 update_rect.y = y - 10 * pressure;
12990 update_rect.width = 20 * pressure;
12991 update_rect.height = 20 * pressure;
12992 gdk_draw_rectangle (pixmap, gc, TRUE,
12993 update_rect.x, update_rect.y,
12994 update_rect.width, update_rect.height);
12995 gtk_widget_draw (widget, &update_rect);
12999 <sect2> Finding out more about a device
13002 As an example of how to find out more about a device, our program
13003 will print the name of the device that generates each button
13004 press. To find out the name of a device, we call the function:
13007 GList *gdk_input_list_devices (void);
13010 which returns a GList (a linked list type from the glib library)
13011 of GdkDeviceInfo structures. The GdkDeviceInfo structure is defined
13015 struct _GdkDeviceInfo
13019 GdkInputSource source;
13025 GdkDeviceKey *keys;
13029 Most of these fields are configuration information that you
13030 can ignore unless you are implemented XInput configuration
13031 saving. The we are interested in here is <tt/name/ which is
13032 simply the name that X assigns to the device. The other field
13033 that isn't configuration information is <tt/has_cursor/. If
13034 <tt/has_cursor/ is false, then we we need to draw our own
13035 cursor. But since we've specified <tt/GDK_EXTENSION_EVENTS_CURSOR/,
13036 we don't have to worry about this.
13039 Our <tt/print_button_press()/ function simply iterates through
13040 the returned list until it finds a match, then prints out
13041 the name of the device.
13045 print_button_press (guint32 deviceid)
13049 /* gdk_input_list_devices returns an internal list, so we shouldn't
13050 free it afterwards */
13051 tmp_list = gdk_input_list_devices();
13055 GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
13057 if (info->deviceid == deviceid)
13059 printf("Button press on device '%s'\n", info->name);
13063 tmp_list = tmp_list->next;
13068 That completes the changes to `XInputize' our program. As with
13069 the first version, the complete source is available at the location
13070 from which you got this tutorial, or from:
13072 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
13073 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
13076 <sect2> Further sophistications <label id="sec_Further_Sophistications">
13079 Although our program now supports XInput quite well, it lacks some
13080 features we would want in a full-featured application. First, the user
13081 probably doesn't want to have to configure their device each time they
13082 run the program, so we should allow them to save the device
13083 configuration. This is done by iterating through the return of
13084 <tt/gdk_input_list_devices()/ and writing out the configuration to a
13088 To restore the state next time the program is run, GDK provides
13089 functions to change device configuration:
13092 gdk_input_set_extension_events()
13093 gdk_input_set_source()
13094 gdk_input_set_mode()
13095 gdk_input_set_axes()
13096 gdk_input_set_key()
13099 (The list returned from <tt/gdk_input_list_devices()/ should not be
13100 modified directly.) An example of doing this can be found in the
13101 drawing program gsumi. (Available from <htmlurl
13102 url="http://www.msc.cornell.edu/~otaylor/gsumi/"
13103 name="http://www.msc.cornell.edu/~otaylor/gsumi/">) Eventually, it
13104 would be nice to have a standard way of doing this for all
13105 applications. This probably belongs at a slightly higher level than
13106 GTK, perhaps in the GNOME library.
13109 Another major omission that we have mentioned above is the lack of
13110 cursor drawing. Platforms other than XFree86 currently do not allow
13111 simultaneously using a device as both the core pointer and directly by
13112 an application. See the <url
13113 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
13114 name="XInput-HOWTO"> for more information about this. This means that
13115 applications that want to support the widest audience need to draw
13119 An application that draws its own cursor needs to do two things:
13120 determine if the current device needs a cursor drawn or not, and
13121 determine if the current device is in proximity. (If the current
13122 device is a drawing tablet, it's a nice touch to make the cursor
13123 disappear when the stylus is lifted from the tablet. When the
13124 device is touching the stylus, that is called "in proximity.")
13125 The first is done by searching the device list, as we did
13126 to find out the device name. The second is achieved by selecting
13127 "proximity_out" events. An example of drawing one's own cursor is
13128 found in the 'testinput' program found in the GTK distribution.
13130 <!-- ***************************************************************** -->
13131 <sect>Tips For Writing GTK Applications
13132 <!-- ***************************************************************** -->
13135 This section is simply a gathering of wisdom, general style guidelines and hints to
13136 creating good GTK applications. It is totally useless right now cause its
13137 only a topic sentence :)
13139 Use GNU autoconf and automake! They are your friends :) I am planning to
13140 make a quick intro on them here.
13142 <!-- ***************************************************************** -->
13143 <sect>Contributing <label id="sec_Contributing">
13144 <!-- ***************************************************************** -->
13147 This document, like so much other great software out there, was created for
13148 free by volunteers. If you are at all knowledgeable about any aspect of GTK
13149 that does not already have documentation, please consider contributing to
13152 If you do decide to contribute, please mail your text to Tony Gale,
13153 <tt><htmlurl url="mailto:gale@gtk.org"
13154 name="gale@gtk.org"></tt>. Also, be aware that the entirety of this
13155 document is free, and any addition by you provide must also be free. That is,
13156 people may use any portion of your examples in their programs, and copies
13157 of this document may be distributed at will etc.
13161 <!-- ***************************************************************** -->
13163 <!-- ***************************************************************** -->
13165 I would like to thank the following for their contributions to this text.
13168 <item>Bawer Dagdeviren, <tt><htmlurl url="mailto:chamele0n@geocities.com"
13169 name="chamele0n@geocities.com"></tt> for the menus tutorial.
13171 <item>Raph Levien, <tt><htmlurl url="mailto:raph@acm.org"
13172 name="raph@acm.org"></tt>
13173 for hello world ala GTK, widget packing, and general all around wisdom.
13174 He's also generously donated a home for this tutorial.
13176 <item>Peter Mattis, <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
13177 name="petm@xcf.berkeley.edu"></tt> for the simplest GTK program..
13178 and the ability to make it :)
13180 <item>Werner Koch <tt><htmlurl url="mailto:werner.koch@guug.de"
13181 name="werner.koch@guug.de"></tt> for converting the original plain text to
13182 SGML, and the widget class hierarchy.
13184 <item>Mark Crichton <tt><htmlurl url="mailto:crichton@expert.cc.purdue.edu"
13185 name="crichton@expert.cc.purdue.edu"></tt> for the menu factory code, and
13186 the table packing tutorial.
13188 <item>Owen Taylor <tt><htmlurl url="mailto:owt1@cornell.edu"
13189 name="owt1@cornell.edu"></tt> for the EventBox widget section (and
13190 the patch to the distro). He's also responsible for the selections code and
13191 tutorial, as well as the sections on writing your own GTK widgets, and the
13192 example application. Thanks a lot Owen for all you help!
13194 <item>Mark VanderBoom <tt><htmlurl url="mailto:mvboom42@calvin.edu"
13195 name="mvboom42@calvin.edu"></tt> for his wonderful work on the Notebook,
13196 Progress Bar, Dialogs, and File selection widgets. Thanks a lot Mark!
13197 You've been a great help.
13199 <item>Tim Janik <tt><htmlurl url="mailto:timj@gtk.org"
13200 name="timj@psynet.net"></tt> for his great job on the Lists
13201 Widget. His excellent work on automatically extracting the widget tree
13202 and signal information from GTK.
13205 <item>Rajat Datta <tt><htmlurl url="mailto:rajat@ix.netcom.com"
13206 name="rajat@ix.netcom.com"</tt> for the excellent job on the Pixmap tutorial.
13208 <item>Michael K. Johnson <tt><htmlurl url="mailto:johnsonm@redhat.com"
13209 name="johnsonm@redhat.com"></tt> for info and code for popup menus.
13211 <item>David Huggins-Daines <tt><htmlurl url="mailto:bn711@freenet.carleton.ca"
13212 name="bn711@freenet.carleton.ca"></tt> for the Range Widgets and Tree Widget
13215 <item>Stefan Mars <tt><htmlurl url="mailto:mars@lysator.liu.se"
13216 name="mars@lysator.liu.se"></tt> for the GtkCList section
13219 And to all of you who commented and helped refine this document.
13223 <!-- ***************************************************************** -->
13224 <sect> Tutorial Copyright and Permissions Notice
13225 <!-- ***************************************************************** -->
13228 The GTK Tutorial is Copyright (C) 1997 Ian Main.
13230 Copyright (C) 1998 Tony Gale.
13232 Permission is granted to make and distribute verbatim copies of this
13233 manual provided the copyright notice and this permission notice are
13234 preserved on all copies.
13235 <P>Permission is granted to copy and distribute modified versions of
13236 this document under the conditions for verbatim copying, provided that
13237 this copyright notice is included exactly as in the original,
13238 and that the entire resulting derived work is distributed under
13239 the terms of a permission notice identical to this one.
13240 <P>Permission is granted to copy and distribute translations of this
13241 document into another language, under the above conditions for modified
13243 <P>If you are intending to incorporate this document into a published
13244 work, please contact the maintainer, and we will make an effort
13245 to ensure that you have the most up to date information available.
13246 <P>There is no guarantee that this document lives up to its intended
13247 purpose. This is simply provided as a free resource. As such,
13248 the authors and maintainers of the information provided within can
13249 not make any guarantee that the information is even accurate.
13251 <!-- ***************************************************************** -->
13253 <!-- ***************************************************************** -->
13255 <!-- ***************************************************************** -->
13256 <sect> GTK Signals <label id="sec_GTK_Signals">
13257 <!-- ***************************************************************** -->
13259 As GTK is an object oriented widget set, it has a hierarchy of
13260 inheritance. This inheritance mechanism applies for
13261 signals. Therefore, you should refer to the widget hierarchy tree when
13262 using the signals listed in this section.
13264 <!-- ----------------------------------------------------------------- -->
13266 <!-- ----------------------------------------------------------------- -->
13269 void GtkObject::destroy (GtkObject *,
13273 <!-- ----------------------------------------------------------------- -->
13275 <!-- ----------------------------------------------------------------- -->
13279 void GtkWidget::show (GtkWidget *,
13281 void GtkWidget::hide (GtkWidget *,
13283 void GtkWidget::map (GtkWidget *,
13285 void GtkWidget::unmap (GtkWidget *,
13287 void GtkWidget::realize (GtkWidget *,
13289 void GtkWidget::unrealize (GtkWidget *,
13291 void GtkWidget::draw (GtkWidget *,
13294 void GtkWidget::draw-focus (GtkWidget *,
13296 void GtkWidget::draw-default (GtkWidget *,
13298 void GtkWidget::size-request (GtkWidget *,
13301 void GtkWidget::size-allocate (GtkWidget *,
13304 void GtkWidget::state-changed (GtkWidget *,
13307 void GtkWidget::parent-set (GtkWidget *,
13310 void GtkWidget::style-set (GtkWidget *,
13313 void GtkWidget::add-accelerator (GtkWidget *,
13320 void GtkWidget::remove-accelerator (GtkWidget *,
13325 gboolean GtkWidget::event (GtkWidget *,
13328 gboolean GtkWidget::button-press-event (GtkWidget *,
13331 gboolean GtkWidget::button-release-event (GtkWidget *,
13334 gboolean GtkWidget::motion-notify-event (GtkWidget *,
13337 gboolean GtkWidget::delete-event (GtkWidget *,
13340 gboolean GtkWidget::destroy-event (GtkWidget *,
13343 gboolean GtkWidget::expose-event (GtkWidget *,
13346 gboolean GtkWidget::key-press-event (GtkWidget *,
13349 gboolean GtkWidget::key-release-event (GtkWidget *,
13352 gboolean GtkWidget::enter-notify-event (GtkWidget *,
13355 gboolean GtkWidget::leave-notify-event (GtkWidget *,
13358 gboolean GtkWidget::configure-event (GtkWidget *,
13361 gboolean GtkWidget::focus-in-event (GtkWidget *,
13364 gboolean GtkWidget::focus-out-event (GtkWidget *,
13367 gboolean GtkWidget::map-event (GtkWidget *,
13370 gboolean GtkWidget::unmap-event (GtkWidget *,
13373 gboolean GtkWidget::property-notify-event (GtkWidget *,
13376 gboolean GtkWidget::selection-clear-event (GtkWidget *,
13379 gboolean GtkWidget::selection-request-event (GtkWidget *,
13382 gboolean GtkWidget::selection-notify-event (GtkWidget *,
13385 void GtkWidget::selection-get (GtkWidget *,
13386 GtkSelectionData *,
13389 void GtkWidget::selection-received (GtkWidget *,
13390 GtkSelectionData *,
13393 gboolean GtkWidget::proximity-in-event (GtkWidget *,
13396 gboolean GtkWidget::proximity-out-event (GtkWidget *,
13399 void GtkWidget::drag-begin (GtkWidget *,
13402 void GtkWidget::drag-end (GtkWidget *,
13405 void GtkWidget::drag-data-delete (GtkWidget *,
13408 void GtkWidget::drag-leave (GtkWidget *,
13412 gboolean GtkWidget::drag-motion (GtkWidget *,
13418 gboolean GtkWidget::drag-drop (GtkWidget *,
13424 void GtkWidget::drag-data-get (GtkWidget *,
13426 GtkSelectionData *,
13430 void GtkWidget::drag-data-received (GtkWidget *,
13434 GtkSelectionData *,
13438 gboolean GtkWidget::client-event (GtkWidget *,
13441 gboolean GtkWidget::no-expose-event (GtkWidget *,
13444 gboolean GtkWidget::visibility-notify-event (GtkWidget *,
13447 void GtkWidget::debug-msg (GtkWidget *,
13452 <!-- ----------------------------------------------------------------- -->
13454 <!-- ----------------------------------------------------------------- -->
13457 void GtkData::disconnect (GtkData *,
13461 <!-- ----------------------------------------------------------------- -->
13462 <sect1>GtkContainer
13463 <!-- ----------------------------------------------------------------- -->
13466 void GtkContainer::add (GtkContainer *,
13469 void GtkContainer::remove (GtkContainer *,
13472 void GtkContainer::check-resize (GtkContainer *,
13474 GtkDirectionType GtkContainer::focus (GtkContainer *,
13477 void GtkContainer::set-focus-child (GtkContainer *,
13482 <!-- ----------------------------------------------------------------- -->
13484 <!-- ----------------------------------------------------------------- -->
13487 void GtkCalendar::month-changed (GtkCalendar *,
13489 void GtkCalendar::day-selected (GtkCalendar *,
13491 void GtkCalendar::day-selected-double-click (GtkCalendar *,
13493 void GtkCalendar::prev-month (GtkCalendar *,
13495 void GtkCalendar::next-month (GtkCalendar *,
13497 void GtkCalendar::prev-year (GtkCalendar *,
13499 void GtkCalendar::next-year (GtkCalendar *,
13503 <!-- ----------------------------------------------------------------- -->
13505 <!-- ----------------------------------------------------------------- -->
13508 void GtkEditable::changed (GtkEditable *,
13510 void GtkEditable::insert-text (GtkEditable *,
13515 void GtkEditable::delete-text (GtkEditable *,
13519 void GtkEditable::activate (GtkEditable *,
13521 void GtkEditable::set-editable (GtkEditable *,
13524 void GtkEditable::move-cursor (GtkEditable *,
13528 void GtkEditable::move-word (GtkEditable *,
13531 void GtkEditable::move-page (GtkEditable *,
13535 void GtkEditable::move-to-row (GtkEditable *,
13538 void GtkEditable::move-to-column (GtkEditable *,
13541 void GtkEditable::kill-char (GtkEditable *,
13544 void GtkEditable::kill-word (GtkEditable *,
13547 void GtkEditable::kill-line (GtkEditable *,
13550 void GtkEditable::cut-clipboard (GtkEditable *,
13552 void GtkEditable::copy-clipboard (GtkEditable *,
13554 void GtkEditable::paste-clipboard (GtkEditable *,
13558 <!-- ----------------------------------------------------------------- -->
13559 <sect1>GtkTipsQuery
13560 <!-- ----------------------------------------------------------------- -->
13563 void GtkTipsQuery::start-query (GtkTipsQuery *,
13565 void GtkTipsQuery::stop-query (GtkTipsQuery *,
13567 void GtkTipsQuery::widget-entered (GtkTipsQuery *,
13572 gboolean GtkTipsQuery::widget-selected (GtkTipsQuery *,
13580 <!-- ----------------------------------------------------------------- -->
13582 <!-- ----------------------------------------------------------------- -->
13585 void GtkCList::select-row (GtkCList *,
13590 void GtkCList::unselect-row (GtkCList *,
13595 void GtkCList::row-move (GtkCList *,
13599 void GtkCList::click-column (GtkCList *,
13602 void GtkCList::resize-column (GtkCList *,
13606 void GtkCList::toggle-focus-row (GtkCList *,
13608 void GtkCList::select-all (GtkCList *,
13610 void GtkCList::unselect-all (GtkCList *,
13612 void GtkCList::undo-selection (GtkCList *,
13614 void GtkCList::start-selection (GtkCList *,
13616 void GtkCList::end-selection (GtkCList *,
13618 void GtkCList::toggle-add-mode (GtkCList *,
13620 void GtkCList::extend-selection (GtkCList *,
13625 void GtkCList::scroll-vertical (GtkCList *,
13629 void GtkCList::scroll-horizontal (GtkCList *,
13633 void GtkCList::abort-column-resize (GtkCList *,
13637 <!-- ----------------------------------------------------------------- -->
13639 <!-- ----------------------------------------------------------------- -->
13642 void GtkNotebook::switch-page (GtkNotebook *,
13649 <!-- ----------------------------------------------------------------- -->
13651 <!-- ----------------------------------------------------------------- -->
13654 void GtkList::selection-changed (GtkList *,
13656 void GtkList::select-child (GtkList *,
13659 void GtkList::unselect-child (GtkList *,
13664 <!-- ----------------------------------------------------------------- -->
13665 <sect1>GtkMenuShell
13666 <!-- ----------------------------------------------------------------- -->
13669 void GtkMenuShell::deactivate (GtkMenuShell *,
13671 void GtkMenuShell::selection-done (GtkMenuShell *,
13673 void GtkMenuShell::move-current (GtkMenuShell *,
13674 GtkMenuDirectionType,
13676 void GtkMenuShell::activate-current (GtkMenuShell *,
13679 void GtkMenuShell::cancel (GtkMenuShell *,
13683 <!-- ----------------------------------------------------------------- -->
13685 <!-- ----------------------------------------------------------------- -->
13688 void GtkToolbar::orientation-changed (GtkToolbar *,
13691 void GtkToolbar::style-changed (GtkToolbar *,
13696 <!-- ----------------------------------------------------------------- -->
13698 <!-- ----------------------------------------------------------------- -->
13701 void GtkTree::selection-changed (GtkTree *,
13703 void GtkTree::select-child (GtkTree *,
13706 void GtkTree::unselect-child (GtkTree *,
13711 <!-- ----------------------------------------------------------------- -->
13713 <!-- ----------------------------------------------------------------- -->
13716 void GtkButton::pressed (GtkButton *,
13718 void GtkButton::released (GtkButton *,
13720 void GtkButton::clicked (GtkButton *,
13722 void GtkButton::enter (GtkButton *,
13724 void GtkButton::leave (GtkButton *,
13728 <!-- ----------------------------------------------------------------- -->
13730 <!-- ----------------------------------------------------------------- -->
13733 void GtkItem::select (GtkItem *,
13735 void GtkItem::deselect (GtkItem *,
13737 void GtkItem::toggle (GtkItem *,
13741 <!-- ----------------------------------------------------------------- -->
13743 <!-- ----------------------------------------------------------------- -->
13746 void GtkWindow::set-focus (GtkWindow *,
13751 <!-- ----------------------------------------------------------------- -->
13752 <sect1>GtkHandleBox
13753 <!-- ----------------------------------------------------------------- -->
13756 void GtkHandleBox::child-attached (GtkHandleBox *,
13759 void GtkHandleBox::child-detached (GtkHandleBox *,
13764 <!-- ----------------------------------------------------------------- -->
13765 <sect1>GtkToggleButton
13766 <!-- ----------------------------------------------------------------- -->
13769 void GtkToggleButton::toggled (GtkToggleButton *,
13774 <!-- ----------------------------------------------------------------- -->
13776 <!-- ----------------------------------------------------------------- -->
13779 void GtkMenuItem::activate (GtkMenuItem *,
13781 void GtkMenuItem::activate-item (GtkMenuItem *,
13785 <!-- ----------------------------------------------------------------- -->
13787 <!-- ----------------------------------------------------------------- -->
13790 void GtkListItem::toggle-focus-row (GtkListItem *,
13792 void GtkListItem::select-all (GtkListItem *,
13794 void GtkListItem::unselect-all (GtkListItem *,
13796 void GtkListItem::undo-selection (GtkListItem *,
13798 void GtkListItem::start-selection (GtkListItem *,
13800 void GtkListItem::end-selection (GtkListItem *,
13802 void GtkListItem::toggle-add-mode (GtkListItem *,
13804 void GtkListItem::extend-selection (GtkListItem *,
13809 void GtkListItem::scroll-vertical (GtkListItem *,
13813 void GtkListItem::scroll-horizontal (GtkListItem *,
13819 <!-- ----------------------------------------------------------------- -->
13821 <!-- ----------------------------------------------------------------- -->
13824 void GtkTreeItem::collapse (GtkTreeItem *,
13826 void GtkTreeItem::expand (GtkTreeItem *,
13830 <!-- ----------------------------------------------------------------- -->
13831 <sect1>GtkCheckMenuItem
13832 <!-- ----------------------------------------------------------------- -->
13835 void GtkCheckMenuItem::toggled (GtkCheckMenuItem *,
13839 <!-- ----------------------------------------------------------------- -->
13840 <sect1>GtkInputDialog
13841 <!-- ----------------------------------------------------------------- -->
13844 void GtkInputDialog::enable-device (GtkInputDialog *,
13847 void GtkInputDialog::disable-device (GtkInputDialog *,
13852 <!-- ----------------------------------------------------------------- -->
13853 <sect1>GtkColorSelection
13854 <!-- ----------------------------------------------------------------- -->
13857 void GtkColorSelection::color-changed (GtkColorSelection *,
13861 <!-- ----------------------------------------------------------------- -->
13862 <sect1>GtkStatusBar
13863 <!-- ----------------------------------------------------------------- -->
13866 void GtkStatusbar::text-pushed (GtkStatusbar *,
13870 void GtkStatusbar::text-popped (GtkStatusbar *,
13876 <!-- ----------------------------------------------------------------- -->
13878 <!-- ----------------------------------------------------------------- -->
13881 void GtkCTree::tree-select-row (GtkCTree *,
13885 void GtkCTree::tree-unselect-row (GtkCTree *,
13889 void GtkCTree::tree-expand (GtkCTree *,
13892 void GtkCTree::tree-collapse (GtkCTree *,
13895 void GtkCTree::tree-move (GtkCTree *,
13900 void GtkCTree::change-focus-row-expansion (GtkCTree *,
13901 GtkCTreeExpansionType,
13905 <!-- ----------------------------------------------------------------- -->
13907 <!-- ----------------------------------------------------------------- -->
13910 void GtkCurve::curve-type-changed (GtkCurve *,
13914 <!-- ----------------------------------------------------------------- -->
13915 <sect1>GtkAdjustment
13916 <!-- ----------------------------------------------------------------- -->
13919 void GtkAdjustment::changed (GtkAdjustment *,
13921 void GtkAdjustment::value-changed (GtkAdjustment *,
13925 <!-- ***************************************************************** -->
13926 <sect> GDK Event Types<label id="sec_GDK_Event_Types">
13927 <!-- ***************************************************************** -->
13929 The follwing data types are passed into event handlers by GTK+. For
13930 each data type listed, the signals that use this data type are listed.
13935 <item>drag_end_event
13938 <item> GdkEventType
13943 <item>destroy_event
13946 <item>no_expose_event
13949 <item> GdkEventExpose
13954 <item> GdkEventNoExpose
13956 <item> GdkEventVisibility
13958 <item> GdkEventMotion
13960 <item>motion_notify_event
13963 <item> GdkEventButton
13965 <item>button_press_event
13966 <item>button_release_event
13971 <item>key_press_event
13972 <item>key_release_event
13975 <item> GdkEventCrossing
13977 <item>enter_notify_event
13978 <item>leave_notify_event
13981 <item> GdkEventFocus
13983 <item>focus_in_event
13984 <item>focus_out_event
13987 <item> GdkEventConfigure
13989 <item>configure_event
13992 <item> GdkEventProperty
13994 <item>property_notify_event
13997 <item> GdkEventSelection
13999 <item>selection_clear_event
14000 <item>selection_request_event
14001 <item>selection_notify_event
14004 <item> GdkEventProximity
14006 <item>proximity_in_event
14007 <item>proximity_out_event
14010 <item> GdkEventDragBegin
14012 <item>drag_begin_event
14015 <item> GdkEventDragRequest
14017 <item>drag_request_event
14020 <item> GdkEventDropEnter
14022 <item>drop_enter_event
14025 <item> GdkEventDropLeave
14027 <item>drop_leave_event
14030 <item> GdkEventDropDataAvailable
14032 <item>drop_data_available_event
14035 <item> GdkEventClient
14040 <item> GdkEventOther
14046 The data type <tt/GdkEventType/ is a special data type that is used by
14047 all the other data types as an indicator of the data type being passed
14048 to the signal handler. As you will see below, each of the event data
14049 structures has a member of this type. It is defined as an enumeration
14059 GDK_MOTION_NOTIFY = 3,
14060 GDK_BUTTON_PRESS = 4,
14061 GDK_2BUTTON_PRESS = 5,
14062 GDK_3BUTTON_PRESS = 6,
14063 GDK_BUTTON_RELEASE = 7,
14065 GDK_KEY_RELEASE = 9,
14066 GDK_ENTER_NOTIFY = 10,
14067 GDK_LEAVE_NOTIFY = 11,
14068 GDK_FOCUS_CHANGE = 12,
14069 GDK_CONFIGURE = 13,
14072 GDK_PROPERTY_NOTIFY = 16,
14073 GDK_SELECTION_CLEAR = 17,
14074 GDK_SELECTION_REQUEST = 18,
14075 GDK_SELECTION_NOTIFY = 19,
14076 GDK_PROXIMITY_IN = 20,
14077 GDK_PROXIMITY_OUT = 21,
14078 GDK_DRAG_BEGIN = 22,
14079 GDK_DRAG_REQUEST = 23,
14080 GDK_DROP_ENTER = 24,
14081 GDK_DROP_LEAVE = 25,
14082 GDK_DROP_DATA_AVAIL = 26,
14083 GDK_CLIENT_EVENT = 27,
14084 GDK_VISIBILITY_NOTIFY = 28,
14085 GDK_NO_EXPOSE = 29,
14086 GDK_OTHER_EVENT = 9999 /* Deprecated, use filters instead */
14090 The other event type that is different from the others is
14091 <tt/GdkEvent/ itself. This is a union of all the other
14092 data types, which allows it to be cast to a specific
14093 event data type within a signal handler.
14095 <!-- Just a big list for now, needs expanding upon - TRG -->
14096 So, the event data types are defined as follows:
14099 struct _GdkEventAny
14106 struct _GdkEventExpose
14112 gint count; /* If non-zero, how many more events follow. */
14115 struct _GdkEventNoExpose
14120 /* XXX: does anyone need the X major_code or minor_code fields? */
14123 struct _GdkEventVisibility
14128 GdkVisibilityState state;
14131 struct _GdkEventMotion
14144 GdkInputSource source;
14146 gdouble x_root, y_root;
14149 struct _GdkEventButton
14162 GdkInputSource source;
14164 gdouble x_root, y_root;
14167 struct _GdkEventKey
14179 struct _GdkEventCrossing
14184 GdkWindow *subwindow;
14185 GdkNotifyType detail;
14188 struct _GdkEventFocus
14196 struct _GdkEventConfigure
14206 struct _GdkEventProperty
14216 struct _GdkEventSelection
14228 /* This event type will be used pretty rarely. It only is important
14229 for XInput aware programs that are drawing their own cursor */
14231 struct _GdkEventProximity
14237 GdkInputSource source;
14241 struct _GdkEventDragRequest
14249 guint protocol_version:4;
14251 guint willaccept:1;
14252 guint delete_data:1; /* Do *not* delete if link is sent, only
14259 guint8 isdrop; /* This gdk event can be generated by a couple of
14260 X events - this lets the app know whether the
14261 drop really occurred or we just set the data */
14263 GdkPoint drop_coords;
14268 struct _GdkEventDragBegin
14275 guint protocol_version:4;
14282 struct _GdkEventDropEnter
14290 guint protocol_version:4;
14292 guint extended_typelist:1;
14299 struct _GdkEventDropLeave
14307 guint protocol_version:4;
14314 struct _GdkEventDropDataAvailable
14322 guint protocol_version:4;
14328 gchar *data_type; /* MIME type */
14329 gulong data_numbytes;
14335 struct _GdkEventClient
14340 GdkAtom message_type;
14341 gushort data_format;
14349 struct _GdkEventOther
14358 <!-- ***************************************************************** -->
14359 <sect> Code Examples
14360 <!-- ***************************************************************** -->
14362 Below are the code examples that are used in the above text
14363 which are not included in complete form elsewhere.
14365 <!-- ----------------------------------------------------------------- -->
14367 <!-- ----------------------------------------------------------------- -->
14371 /* example-start tictactoe tictactoe.h */
14373 /* GTK - The GIMP Toolkit
14374 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
14376 * This library is free software; you can redistribute it and/or
14377 * modify it under the terms of the GNU Library General Public
14378 * License as published by the Free Software Foundation; either
14379 * version 2 of the License, or (at your option) any later version.
14381 * This library is distributed in the hope that it will be useful,
14382 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14383 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14384 * Library General Public License for more details.
14386 * You should have received a copy of the GNU Library General Public
14387 * License along with this library; if not, write to the
14388 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14389 * Boston, MA 02111-1307, USA.
14391 #ifndef __TICTACTOE_H__
14392 #define __TICTACTOE_H__
14395 #include <gdk/gdk.h>
14396 #include <gtk/gtkvbox.h>
14401 #endif /* __cplusplus */
14403 #define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
14404 #define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
14405 #define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
14408 typedef struct _Tictactoe Tictactoe;
14409 typedef struct _TictactoeClass TictactoeClass;
14415 GtkWidget *buttons[3][3];
14418 struct _TictactoeClass
14420 GtkVBoxClass parent_class;
14422 void (* tictactoe) (Tictactoe *ttt);
14425 guint tictactoe_get_type (void);
14426 GtkWidget* tictactoe_new (void);
14427 void tictactoe_clear (Tictactoe *ttt);
14431 #endif /* __cplusplus */
14433 #endif /* __TICTACTOE_H__ */
14438 <!-- ----------------------------------------------------------------- -->
14442 /* example-start tictactoe tictactoe.c */
14444 /* GTK - The GIMP Toolkit
14445 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
14447 * This library is free software; you can redistribute it and/or
14448 * modify it under the terms of the GNU Library General Public
14449 * License as published by the Free Software Foundation; either
14450 * version 2 of the License, or (at your option) any later version.
14452 * This library is distributed in the hope that it will be useful,
14453 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14454 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14455 * Library General Public License for more details.
14457 * You should have received a copy of the GNU Library General Public
14458 * License along with this library; if not, write to the
14459 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14460 * Boston, MA 02111-1307, USA.
14462 #include "gtk/gtksignal.h"
14463 #include "gtk/gtktable.h"
14464 #include "gtk/gtktogglebutton.h"
14465 #include "tictactoe.h"
14472 static void tictactoe_class_init (TictactoeClass *klass);
14473 static void tictactoe_init (Tictactoe *ttt);
14474 static void tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt);
14476 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
14479 tictactoe_get_type ()
14481 static guint ttt_type = 0;
14485 GtkTypeInfo ttt_info =
14488 sizeof (Tictactoe),
14489 sizeof (TictactoeClass),
14490 (GtkClassInitFunc) tictactoe_class_init,
14491 (GtkObjectInitFunc) tictactoe_init,
14492 (GtkArgSetFunc) NULL,
14493 (GtkArgGetFunc) NULL
14496 ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
14503 tictactoe_class_init (TictactoeClass *class)
14505 GtkObjectClass *object_class;
14507 object_class = (GtkObjectClass*) class;
14509 tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
14511 object_class->type,
14512 GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
14513 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
14516 gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
14518 class->tictactoe = NULL;
14522 tictactoe_init (Tictactoe *ttt)
14527 table = gtk_table_new (3, 3, TRUE);
14528 gtk_container_add (GTK_CONTAINER(ttt), table);
14529 gtk_widget_show (table);
14534 ttt->buttons[i][j] = gtk_toggle_button_new ();
14535 gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
14537 gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
14538 GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
14539 gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
14540 gtk_widget_show (ttt->buttons[i][j]);
14547 return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
14551 tictactoe_clear (Tictactoe *ttt)
14558 gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
14559 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
14561 gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
14566 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
14570 static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
14571 { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
14572 { 0, 1, 2 }, { 0, 1, 2 } };
14573 static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
14574 { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
14575 { 0, 1, 2 }, { 2, 1, 0 } };
14577 int success, found;
14579 for (k=0; k<8; k++)
14586 success = success &&
14587 GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
14589 ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
14592 if (success && found)
14594 gtk_signal_emit (GTK_OBJECT (ttt),
14595 tictactoe_signals[TICTACTOE_SIGNAL]);
14604 <!-- ----------------------------------------------------------------- -->
14608 /* example-start tictactoe ttt_test.c */
14610 #include <gtk/gtk.h>
14611 #include "tictactoe.h"
14614 win (GtkWidget *widget, gpointer data)
14616 g_print ("Yay!\n");
14617 tictactoe_clear (TICTACTOE (widget));
14621 main (int argc, char *argv[])
14626 gtk_init (&argc, &argv);
14628 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
14630 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
14632 gtk_signal_connect (GTK_OBJECT (window), "destroy",
14633 GTK_SIGNAL_FUNC (gtk_exit), NULL);
14635 gtk_container_border_width (GTK_CONTAINER (window), 10);
14637 ttt = tictactoe_new ();
14639 gtk_container_add (GTK_CONTAINER (window), ttt);
14640 gtk_widget_show (ttt);
14642 gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
14643 GTK_SIGNAL_FUNC (win), NULL);
14645 gtk_widget_show (window);
14655 <!-- ----------------------------------------------------------------- -->
14658 <!-- ----------------------------------------------------------------- -->
14662 /* example-start gtkdial gtkdial.h */
14664 /* GTK - The GIMP Toolkit
14665 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
14667 * This library is free software; you can redistribute it and/or
14668 * modify it under the terms of the GNU Library General Public
14669 * License as published by the Free Software Foundation; either
14670 * version 2 of the License, or (at your option) any later version.
14672 * This library is distributed in the hope that it will be useful,
14673 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14674 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14675 * Library General Public License for more details.
14677 * You should have received a copy of the GNU Library General Public
14678 * License along with this library; if not, write to the
14679 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14680 * Boston, MA 02111-1307, USA.
14682 #ifndef __GTK_DIAL_H__
14683 #define __GTK_DIAL_H__
14686 #include <gdk/gdk.h>
14687 #include <gtk/gtkadjustment.h>
14688 #include <gtk/gtkwidget.h>
14693 #endif /* __cplusplus */
14696 #define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
14697 #define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
14698 #define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
14701 typedef struct _GtkDial GtkDial;
14702 typedef struct _GtkDialClass GtkDialClass;
14708 /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
14711 /* Button currently pressed or 0 if none */
14714 /* Dimensions of dial components */
14716 gint pointer_width;
14718 /* ID of update timer, or 0 if none */
14721 /* Current angle */
14724 /* Old values from adjustment stored so we know when something changes */
14729 /* The adjustment object that stores the data for this dial */
14730 GtkAdjustment *adjustment;
14733 struct _GtkDialClass
14735 GtkWidgetClass parent_class;
14739 GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
14740 guint gtk_dial_get_type (void);
14741 GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
14742 void gtk_dial_set_update_policy (GtkDial *dial,
14743 GtkUpdateType policy);
14745 void gtk_dial_set_adjustment (GtkDial *dial,
14746 GtkAdjustment *adjustment);
14749 #endif /* __cplusplus */
14752 #endif /* __GTK_DIAL_H__ */
14756 <!-- ----------------------------------------------------------------- -->
14760 /* example-start gtkdial gtkdial.c */
14762 /* GTK - The GIMP Toolkit
14763 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
14765 * This library is free software; you can redistribute it and/or
14766 * modify it under the terms of the GNU Library General Public
14767 * License as published by the Free Software Foundation; either
14768 * version 2 of the License, or (at your option) any later version.
14770 * This library is distributed in the hope that it will be useful,
14771 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14772 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14773 * Library General Public License for more details.
14775 * You should have received a copy of the GNU Library General Public
14776 * License along with this library; if not, write to the
14777 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14778 * Boston, MA 02111-1307, USA.
14782 #include <gtk/gtkmain.h>
14783 #include <gtk/gtksignal.h>
14785 #include "gtkdial.h"
14787 #define SCROLL_DELAY_LENGTH 300
14788 #define DIAL_DEFAULT_SIZE 100
14790 /* Forward declarations */
14792 static void gtk_dial_class_init (GtkDialClass *klass);
14793 static void gtk_dial_init (GtkDial *dial);
14794 static void gtk_dial_destroy (GtkObject *object);
14795 static void gtk_dial_realize (GtkWidget *widget);
14796 static void gtk_dial_size_request (GtkWidget *widget,
14797 GtkRequisition *requisition);
14798 static void gtk_dial_size_allocate (GtkWidget *widget,
14799 GtkAllocation *allocation);
14800 static gint gtk_dial_expose (GtkWidget *widget,
14801 GdkEventExpose *event);
14802 static gint gtk_dial_button_press (GtkWidget *widget,
14803 GdkEventButton *event);
14804 static gint gtk_dial_button_release (GtkWidget *widget,
14805 GdkEventButton *event);
14806 static gint gtk_dial_motion_notify (GtkWidget *widget,
14807 GdkEventMotion *event);
14808 static gint gtk_dial_timer (GtkDial *dial);
14810 static void gtk_dial_update_mouse (GtkDial *dial, gint x, gint y);
14811 static void gtk_dial_update (GtkDial *dial);
14812 static void gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
14814 static void gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
14819 static GtkWidgetClass *parent_class = NULL;
14822 gtk_dial_get_type ()
14824 static guint dial_type = 0;
14828 GtkTypeInfo dial_info =
14832 sizeof (GtkDialClass),
14833 (GtkClassInitFunc) gtk_dial_class_init,
14834 (GtkObjectInitFunc) gtk_dial_init,
14835 (GtkArgSetFunc) NULL,
14836 (GtkArgGetFunc) NULL,
14839 dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info);
14846 gtk_dial_class_init (GtkDialClass *class)
14848 GtkObjectClass *object_class;
14849 GtkWidgetClass *widget_class;
14851 object_class = (GtkObjectClass*) class;
14852 widget_class = (GtkWidgetClass*) class;
14854 parent_class = gtk_type_class (gtk_widget_get_type ());
14856 object_class->destroy = gtk_dial_destroy;
14858 widget_class->realize = gtk_dial_realize;
14859 widget_class->expose_event = gtk_dial_expose;
14860 widget_class->size_request = gtk_dial_size_request;
14861 widget_class->size_allocate = gtk_dial_size_allocate;
14862 widget_class->button_press_event = gtk_dial_button_press;
14863 widget_class->button_release_event = gtk_dial_button_release;
14864 widget_class->motion_notify_event = gtk_dial_motion_notify;
14868 gtk_dial_init (GtkDial *dial)
14871 dial->policy = GTK_UPDATE_CONTINUOUS;
14874 dial->pointer_width = 0;
14876 dial->old_value = 0.0;
14877 dial->old_lower = 0.0;
14878 dial->old_upper = 0.0;
14879 dial->adjustment = NULL;
14883 gtk_dial_new (GtkAdjustment *adjustment)
14887 dial = gtk_type_new (gtk_dial_get_type ());
14890 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
14892 gtk_dial_set_adjustment (dial, adjustment);
14894 return GTK_WIDGET (dial);
14898 gtk_dial_destroy (GtkObject *object)
14902 g_return_if_fail (object != NULL);
14903 g_return_if_fail (GTK_IS_DIAL (object));
14905 dial = GTK_DIAL (object);
14907 if (dial->adjustment)
14908 gtk_object_unref (GTK_OBJECT (dial->adjustment));
14910 if (GTK_OBJECT_CLASS (parent_class)->destroy)
14911 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
14915 gtk_dial_get_adjustment (GtkDial *dial)
14917 g_return_val_if_fail (dial != NULL, NULL);
14918 g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
14920 return dial->adjustment;
14924 gtk_dial_set_update_policy (GtkDial *dial,
14925 GtkUpdateType policy)
14927 g_return_if_fail (dial != NULL);
14928 g_return_if_fail (GTK_IS_DIAL (dial));
14930 dial->policy = policy;
14934 gtk_dial_set_adjustment (GtkDial *dial,
14935 GtkAdjustment *adjustment)
14937 g_return_if_fail (dial != NULL);
14938 g_return_if_fail (GTK_IS_DIAL (dial));
14940 if (dial->adjustment)
14942 gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
14943 gtk_object_unref (GTK_OBJECT (dial->adjustment));
14946 dial->adjustment = adjustment;
14947 gtk_object_ref (GTK_OBJECT (dial->adjustment));
14949 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
14950 (GtkSignalFunc) gtk_dial_adjustment_changed,
14952 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
14953 (GtkSignalFunc) gtk_dial_adjustment_value_changed,
14956 dial->old_value = adjustment->value;
14957 dial->old_lower = adjustment->lower;
14958 dial->old_upper = adjustment->upper;
14960 gtk_dial_update (dial);
14964 gtk_dial_realize (GtkWidget *widget)
14967 GdkWindowAttr attributes;
14968 gint attributes_mask;
14970 g_return_if_fail (widget != NULL);
14971 g_return_if_fail (GTK_IS_DIAL (widget));
14973 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
14974 dial = GTK_DIAL (widget);
14976 attributes.x = widget->allocation.x;
14977 attributes.y = widget->allocation.y;
14978 attributes.width = widget->allocation.width;
14979 attributes.height = widget->allocation.height;
14980 attributes.wclass = GDK_INPUT_OUTPUT;
14981 attributes.window_type = GDK_WINDOW_CHILD;
14982 attributes.event_mask = gtk_widget_get_events (widget) |
14983 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
14984 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
14985 GDK_POINTER_MOTION_HINT_MASK;
14986 attributes.visual = gtk_widget_get_visual (widget);
14987 attributes.colormap = gtk_widget_get_colormap (widget);
14989 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
14990 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
14992 widget->style = gtk_style_attach (widget->style, widget->window);
14994 gdk_window_set_user_data (widget->window, widget);
14996 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
15000 gtk_dial_size_request (GtkWidget *widget,
15001 GtkRequisition *requisition)
15003 requisition->width = DIAL_DEFAULT_SIZE;
15004 requisition->height = DIAL_DEFAULT_SIZE;
15008 gtk_dial_size_allocate (GtkWidget *widget,
15009 GtkAllocation *allocation)
15013 g_return_if_fail (widget != NULL);
15014 g_return_if_fail (GTK_IS_DIAL (widget));
15015 g_return_if_fail (allocation != NULL);
15017 widget->allocation = *allocation;
15018 dial = GTK_DIAL (widget);
15020 if (GTK_WIDGET_REALIZED (widget))
15023 gdk_window_move_resize (widget->window,
15024 allocation->x, allocation->y,
15025 allocation->width, allocation->height);
15028 dial->radius = MIN(allocation->width,allocation->height) * 0.45;
15029 dial->pointer_width = dial->radius / 5;
15033 gtk_dial_expose (GtkWidget *widget,
15034 GdkEventExpose *event)
15037 GdkPoint points[3];
15044 g_return_val_if_fail (widget != NULL, FALSE);
15045 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
15046 g_return_val_if_fail (event != NULL, FALSE);
15048 if (event->count > 0)
15051 dial = GTK_DIAL (widget);
15053 gdk_window_clear_area (widget->window,
15055 widget->allocation.width,
15056 widget->allocation.height);
15058 xc = widget->allocation.width/2;
15059 yc = widget->allocation.height/2;
15063 for (i=0; i<25; i++)
15065 theta = (i*M_PI/18. - M_PI/6.);
15069 tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
15071 gdk_draw_line (widget->window,
15072 widget->style->fg_gc[widget->state],
15073 xc + c*(dial->radius - tick_length),
15074 yc - s*(dial->radius - tick_length),
15075 xc + c*dial->radius,
15076 yc - s*dial->radius);
15081 s = sin(dial->angle);
15082 c = cos(dial->angle);
15085 points[0].x = xc + s*dial->pointer_width/2;
15086 points[0].y = yc + c*dial->pointer_width/2;
15087 points[1].x = xc + c*dial->radius;
15088 points[1].y = yc - s*dial->radius;
15089 points[2].x = xc - s*dial->pointer_width/2;
15090 points[2].y = yc - c*dial->pointer_width/2;
15092 gtk_draw_polygon (widget->style,
15103 gtk_dial_button_press (GtkWidget *widget,
15104 GdkEventButton *event)
15110 double d_perpendicular;
15112 g_return_val_if_fail (widget != NULL, FALSE);
15113 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
15114 g_return_val_if_fail (event != NULL, FALSE);
15116 dial = GTK_DIAL (widget);
15118 /* Determine if button press was within pointer region - we
15119 do this by computing the parallel and perpendicular distance of
15120 the point where the mouse was pressed from the line passing through
15123 dx = event->x - widget->allocation.width / 2;
15124 dy = widget->allocation.height / 2 - event->y;
15126 s = sin(dial->angle);
15127 c = cos(dial->angle);
15129 d_parallel = s*dy + c*dx;
15130 d_perpendicular = fabs(s*dx - c*dy);
15132 if (!dial->button &&
15133 (d_perpendicular < dial->pointer_width/2) &&
15134 (d_parallel > - dial->pointer_width))
15136 gtk_grab_add (widget);
15138 dial->button = event->button;
15140 gtk_dial_update_mouse (dial, event->x, event->y);
15147 gtk_dial_button_release (GtkWidget *widget,
15148 GdkEventButton *event)
15152 g_return_val_if_fail (widget != NULL, FALSE);
15153 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
15154 g_return_val_if_fail (event != NULL, FALSE);
15156 dial = GTK_DIAL (widget);
15158 if (dial->button == event->button)
15160 gtk_grab_remove (widget);
15164 if (dial->policy == GTK_UPDATE_DELAYED)
15165 gtk_timeout_remove (dial->timer);
15167 if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
15168 (dial->old_value != dial->adjustment->value))
15169 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
15176 gtk_dial_motion_notify (GtkWidget *widget,
15177 GdkEventMotion *event)
15180 GdkModifierType mods;
15183 g_return_val_if_fail (widget != NULL, FALSE);
15184 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
15185 g_return_val_if_fail (event != NULL, FALSE);
15187 dial = GTK_DIAL (widget);
15189 if (dial->button != 0)
15194 if (event->is_hint || (event->window != widget->window))
15195 gdk_window_get_pointer (widget->window, &x, &y, &mods);
15197 switch (dial->button)
15200 mask = GDK_BUTTON1_MASK;
15203 mask = GDK_BUTTON2_MASK;
15206 mask = GDK_BUTTON3_MASK;
15213 if (mods & mask)
15214 gtk_dial_update_mouse (dial, x,y);
15221 gtk_dial_timer (GtkDial *dial)
15223 g_return_val_if_fail (dial != NULL, FALSE);
15224 g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
15226 if (dial->policy == GTK_UPDATE_DELAYED)
15227 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
15233 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
15238 g_return_if_fail (dial != NULL);
15239 g_return_if_fail (GTK_IS_DIAL (dial));
15241 xc = GTK_WIDGET(dial)->allocation.width / 2;
15242 yc = GTK_WIDGET(dial)->allocation.height / 2;
15244 old_value = dial->adjustment->value;
15245 dial->angle = atan2(yc-y, x-xc);
15247 if (dial->angle < -M_PI/2.)
15248 dial->angle += 2*M_PI;
15250 if (dial->angle < -M_PI/6)
15251 dial->angle = -M_PI/6;
15253 if (dial->angle > 7.*M_PI/6.)
15254 dial->angle = 7.*M_PI/6.;
15256 dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
15257 (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
15259 if (dial->adjustment->value != old_value)
15261 if (dial->policy == GTK_UPDATE_CONTINUOUS)
15263 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
15267 gtk_widget_draw (GTK_WIDGET(dial), NULL);
15269 if (dial->policy == GTK_UPDATE_DELAYED)
15272 gtk_timeout_remove (dial->timer);
15274 dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
15275 (GtkFunction) gtk_dial_timer,
15283 gtk_dial_update (GtkDial *dial)
15287 g_return_if_fail (dial != NULL);
15288 g_return_if_fail (GTK_IS_DIAL (dial));
15290 new_value = dial->adjustment->value;
15292 if (new_value < dial->adjustment->lower)
15293 new_value = dial->adjustment->lower;
15295 if (new_value > dial->adjustment->upper)
15296 new_value = dial->adjustment->upper;
15298 if (new_value != dial->adjustment->value)
15300 dial->adjustment->value = new_value;
15301 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
15304 dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
15305 (dial->adjustment->upper - dial->adjustment->lower);
15307 gtk_widget_draw (GTK_WIDGET(dial), NULL);
15311 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
15316 g_return_if_fail (adjustment != NULL);
15317 g_return_if_fail (data != NULL);
15319 dial = GTK_DIAL (data);
15321 if ((dial->old_value != adjustment->value) ||
15322 (dial->old_lower != adjustment->lower) ||
15323 (dial->old_upper != adjustment->upper))
15325 gtk_dial_update (dial);
15327 dial->old_value = adjustment->value;
15328 dial->old_lower = adjustment->lower;
15329 dial->old_upper = adjustment->upper;
15334 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
15339 g_return_if_fail (adjustment != NULL);
15340 g_return_if_fail (data != NULL);
15342 dial = GTK_DIAL (data);
15344 if (dial->old_value != adjustment->value)
15346 gtk_dial_update (dial);
15348 dial->old_value = adjustment->value;
15354 <!-- ----------------------------------------------------------------- -->
15358 /* example-start scribble-simple scribble-simple.c */
15360 /* GTK - The GIMP Toolkit
15361 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15363 * This library is free software; you can redistribute it and/or
15364 * modify it under the terms of the GNU Library General Public
15365 * License as published by the Free Software Foundation; either
15366 * version 2 of the License, or (at your option) any later version.
15368 * This library is distributed in the hope that it will be useful,
15369 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15370 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15371 * Library General Public License for more details.
15373 * You should have received a copy of the GNU Library General Public
15374 * License along with this library; if not, write to the
15375 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15376 * Boston, MA 02111-1307, USA.
15379 #include <gtk/gtk.h>
15381 /* Backing pixmap for drawing area */
15382 static GdkPixmap *pixmap = NULL;
15384 /* Create a new backing pixmap of the appropriate size */
15386 configure_event (GtkWidget *widget, GdkEventConfigure *event)
15389 gdk_pixmap_unref(pixmap);
15391 pixmap = gdk_pixmap_new(widget->window,
15392 widget->allocation.width,
15393 widget->allocation.height,
15395 gdk_draw_rectangle (pixmap,
15396 widget->style->white_gc,
15399 widget->allocation.width,
15400 widget->allocation.height);
15405 /* Redraw the screen from the backing pixmap */
15407 expose_event (GtkWidget *widget, GdkEventExpose *event)
15409 gdk_draw_pixmap(widget->window,
15410 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
15412 event->area.x, event->area.y,
15413 event->area.x, event->area.y,
15414 event->area.width, event->area.height);
15419 /* Draw a rectangle on the screen */
15421 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
15423 GdkRectangle update_rect;
15425 update_rect.x = x - 5;
15426 update_rect.y = y - 5;
15427 update_rect.width = 10;
15428 update_rect.height = 10;
15429 gdk_draw_rectangle (pixmap,
15430 widget->style->black_gc,
15432 update_rect.x, update_rect.y,
15433 update_rect.width, update_rect.height);
15434 gtk_widget_draw (widget, &update_rect);
15438 button_press_event (GtkWidget *widget, GdkEventButton *event)
15440 if (event->button == 1 && pixmap != NULL)
15441 draw_brush (widget, event->x, event->y);
15447 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
15450 GdkModifierType state;
15452 if (event->is_hint)
15453 gdk_window_get_pointer (event->window, &x, &y, &state);
15458 state = event->state;
15461 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
15462 draw_brush (widget, x, y);
15474 main (int argc, char *argv[])
15477 GtkWidget *drawing_area;
15482 gtk_init (&argc, &argv);
15484 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
15485 gtk_widget_set_name (window, "Test Input");
15487 vbox = gtk_vbox_new (FALSE, 0);
15488 gtk_container_add (GTK_CONTAINER (window), vbox);
15489 gtk_widget_show (vbox);
15491 gtk_signal_connect (GTK_OBJECT (window), "destroy",
15492 GTK_SIGNAL_FUNC (quit), NULL);
15494 /* Create the drawing area */
15496 drawing_area = gtk_drawing_area_new ();
15497 gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200);
15498 gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
15500 gtk_widget_show (drawing_area);
15502 /* Signals used to handle backing pixmap */
15504 gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
15505 (GtkSignalFunc) expose_event, NULL);
15506 gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
15507 (GtkSignalFunc) configure_event, NULL);
15509 /* Event signals */
15511 gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
15512 (GtkSignalFunc) motion_notify_event, NULL);
15513 gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
15514 (GtkSignalFunc) button_press_event, NULL);
15516 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
15517 | GDK_LEAVE_NOTIFY_MASK
15518 | GDK_BUTTON_PRESS_MASK
15519 | GDK_POINTER_MOTION_MASK
15520 | GDK_POINTER_MOTION_HINT_MASK);
15522 /* .. And a quit button */
15523 button = gtk_button_new_with_label ("Quit");
15524 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
15526 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
15527 GTK_SIGNAL_FUNC (gtk_widget_destroy),
15528 GTK_OBJECT (window));
15529 gtk_widget_show (button);
15531 gtk_widget_show (window);